From 0818a3057b0a91e422158d828026c941b4e10622 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Thu, 25 Jun 2026 17:51:45 +0200 Subject: Rails 5.2 test updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename test/functional → test/controllers, test/unit → test/models - Remove test/performance/browsing_test.rb (performance_test_help removed) - Fix use_transactional_fixtures → use_transactional_tests - Remove use_instantiated_fixtures (removed in Rails 5) - Fix ActiveRecord::Fixtures → FixtureSet - Fix controller test params syntax: add params: {} wrapper throughout - Fix assert_select targets for aggregator test - Fix test_update_a_draft_with_changing_the_template: draft → head - Add test_node.reload after children.create! (awesome_nested_set bug) - Add before/after count pattern for create tests (transactional isolation) - Known failures: 5 tests affected by Rails 5 transactional test isolation --- test/models/asset_test.rb | 23 ++ test/models/event_test.rb | 114 ++++++++++ test/models/helpers/admin_helper_test.rb | 4 + test/models/helpers/assets_helper_test.rb | 4 + test/models/helpers/content_helper_test.rb | 4 + test/models/helpers/events_helper_test.rb | 4 + test/models/helpers/menu_items_helper_test.rb | 4 + test/models/helpers/nodes_helper_test.rb | 4 + test/models/helpers/occurrences_helper_test.rb | 4 + test/models/helpers/pages_helper_test.rb | 4 + test/models/helpers/revisions_helper_test.rb | 4 + test/models/helpers/rss_helper_test.rb | 4 + test/models/helpers/search_helper_test.rb | 4 + test/models/helpers/tags_helper_test.rb | 4 + test/models/helpers/users_helper_test.rb | 4 + test/models/menu_item_test.rb | 8 + test/models/node_test.rb | 290 +++++++++++++++++++++++++ test/models/occurrence_test.rb | 8 + test/models/page_test.rb | 146 +++++++++++++ test/models/permission_test.rb | 8 + test/models/related_asset_test.rb | 8 + test/models/user_test.rb | 64 ++++++ 22 files changed, 721 insertions(+) create mode 100644 test/models/asset_test.rb create mode 100644 test/models/event_test.rb create mode 100644 test/models/helpers/admin_helper_test.rb create mode 100644 test/models/helpers/assets_helper_test.rb create mode 100644 test/models/helpers/content_helper_test.rb create mode 100644 test/models/helpers/events_helper_test.rb create mode 100644 test/models/helpers/menu_items_helper_test.rb create mode 100644 test/models/helpers/nodes_helper_test.rb create mode 100644 test/models/helpers/occurrences_helper_test.rb create mode 100644 test/models/helpers/pages_helper_test.rb create mode 100644 test/models/helpers/revisions_helper_test.rb create mode 100644 test/models/helpers/rss_helper_test.rb create mode 100644 test/models/helpers/search_helper_test.rb create mode 100644 test/models/helpers/tags_helper_test.rb create mode 100644 test/models/helpers/users_helper_test.rb create mode 100644 test/models/menu_item_test.rb create mode 100644 test/models/node_test.rb create mode 100644 test/models/occurrence_test.rb create mode 100644 test/models/page_test.rb create mode 100644 test/models/permission_test.rb create mode 100644 test/models/related_asset_test.rb create mode 100644 test/models/user_test.rb (limited to 'test/models') diff --git a/test/models/asset_test.rb b/test/models/asset_test.rb new file mode 100644 index 0000000..a1041e4 --- /dev/null +++ b/test/models/asset_test.rb @@ -0,0 +1,23 @@ +require 'test_helper' + +class AssetTest < ActiveSupport::TestCase + + test "related assets get destroyed when assets get destroyed" do + Asset.delete_all + RelatedAsset.delete_all + + assert asset = Asset.create + assert node = Node.root.children.create( :slug => "asset" ) + assert_equal [], node.draft.assets + + draft = node.draft + draft.assets << asset + assert_equal 1, draft.assets.length + + asset.destroy + draft.reload + assert_equal 0, draft.assets.length + assert_equal 0, RelatedAsset.count + end + +end diff --git a/test/models/event_test.rb b/test/models/event_test.rb new file mode 100644 index 0000000..f310af8 --- /dev/null +++ b/test/models/event_test.rb @@ -0,0 +1,114 @@ +require 'test_helper' + +class EventTest < ActiveSupport::TestCase + + def setup + Page.delete_all + @cal_node = Node.root.children.create! :slug => "calendar" + @draft = @cal_node.find_or_create_draft User.first + @draft.title = "99C3" + @draft.abstract = "The 99th Chaos Comunication Congress" + @draft.body = "Its totally freakin awesome" + @draft.save + @cal_node.publish_draft! + @cal_node.head.reload + end + + test 'verfy setup data' do + assert_not_nil @cal_node + assert_not_nil @cal_node.head + end + + test 'creating an event with malformed rrule raises exception' do + assert_raise(ArgumentError) do + Event.create!( + :start_time => "2009-01-01T15:23:42".to_time, + :end_time => "2009-01-01T20:05:23".to_time, + :url => "http://events.ccc.de/congress/2082", + :latitude => 52.525308, + :longitude => 13.378944, + :rrule => "FOOBAR", + :allday => false, + :custom_rrule => false, + :node_id => @cal_node.id + ) + end + end + + test 'create day event for node with one occurrence' do + assert_not_nil event = Event.create!( + :start_time => "2009-01-01T15:23:42".to_time, + :end_time => "2009-01-01T20:05:23".to_time, + :url => "http://events.ccc.de/congress/2082", + :latitude => 52.525308, + :longitude => 13.378944, + :rrule => nil, + :allday => false, + :custom_rrule => false, + :node_id => @cal_node.id + ) + + assert_equal 1, Occurrence.count + assert_equal event.start_time, Occurrence.first.start_time + assert_equal event.end_time, Occurrence.first.end_time + end + + test 'create day event with weekly reoccurrence and checking data' do + assert_not_nil event = Event.create!( + :start_time => "2009-01-01T15:23:42".to_time, + :end_time => "2009-01-01T20:05:23".to_time, + :url => "http://events.ccc.de/congress/2082", + :latitude => 52.525308, + :longitude => 13.378944, + :rrule => "FREQ=WEEKLY;INTERVAL=1", + :allday => false, + :custom_rrule => false, + :node_id => @cal_node.id + ) + + assert_not_nil scoped_occurrences = event.occurrences_in_range( + "2009-01-01".to_time, "2009-12-31".to_time + ) + + assert_equal 52, scoped_occurrences.length + + assert_equal "2009-12-24T15:23:42".to_time, scoped_occurrences[51].start_time + assert_equal "2009-12-24T20:05:23".to_time, scoped_occurrences[51].end_time + assert_equal @cal_node.event, scoped_occurrences[51].event + assert_equal @cal_node, scoped_occurrences[51].node + + assert_equal "2009-03-19T15:23:42".to_time, scoped_occurrences[11].start_time + assert_equal "2009-03-19T20:05:23".to_time, scoped_occurrences[11].end_time + assert_equal @cal_node.event, scoped_occurrences[11].event + assert_equal @cal_node, scoped_occurrences[11].node + + assert_equal "2009-01-01T15:23:42".to_time, scoped_occurrences[0].start_time + assert_equal "2009-01-01T20:05:23".to_time, scoped_occurrences[0].end_time + assert_equal @cal_node.event, scoped_occurrences[11].event + assert_equal @cal_node, scoped_occurrences[11].node + end + + test 'create chaosradio event with custom rrule and interval' do + assert_not_nil event = Event.create!( + :start_time => "2009-01-28T21:00:00".to_time, + :end_time => "2009-01-28T23:00:00".to_time, + :url => "http://chaosradio.ccc.de", + :latitude => 52.525308, + :longitude => 13.378944, + :rrule => "FREQ=MONTHLY;INTERVAL=1;BYDAY=-1WE", + :allday => false, + :custom_rrule => true, + :node_id => @cal_node.id + ) + + assert_not_nil scoped_occurrences = event.occurrences_in_range( + "2009-01-01".to_time, "2009-12-31".to_time + ) + + assert_equal 12, scoped_occurrences.length + + expected_days = [28, 25, 25, 29, 27, 24, 29, 26, 30, 28, 25, 30] + chaosradio_days = scoped_occurrences.map {|x| x.start_time.day} + assert_equal expected_days, chaosradio_days + end +end \ No newline at end of file diff --git a/test/models/helpers/admin_helper_test.rb b/test/models/helpers/admin_helper_test.rb new file mode 100644 index 0000000..23d9f40 --- /dev/null +++ b/test/models/helpers/admin_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class AdminHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/assets_helper_test.rb b/test/models/helpers/assets_helper_test.rb new file mode 100644 index 0000000..ae50bff --- /dev/null +++ b/test/models/helpers/assets_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class AssetsHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/content_helper_test.rb b/test/models/helpers/content_helper_test.rb new file mode 100644 index 0000000..2da82d7 --- /dev/null +++ b/test/models/helpers/content_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class ContentHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/events_helper_test.rb b/test/models/helpers/events_helper_test.rb new file mode 100644 index 0000000..2e7567e --- /dev/null +++ b/test/models/helpers/events_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class EventsHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/menu_items_helper_test.rb b/test/models/helpers/menu_items_helper_test.rb new file mode 100644 index 0000000..8919dfd --- /dev/null +++ b/test/models/helpers/menu_items_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class MenuItemsHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/nodes_helper_test.rb b/test/models/helpers/nodes_helper_test.rb new file mode 100644 index 0000000..13011de --- /dev/null +++ b/test/models/helpers/nodes_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class NodesHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/occurrences_helper_test.rb b/test/models/helpers/occurrences_helper_test.rb new file mode 100644 index 0000000..0692926 --- /dev/null +++ b/test/models/helpers/occurrences_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class OccurrencesHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/pages_helper_test.rb b/test/models/helpers/pages_helper_test.rb new file mode 100644 index 0000000..535dfe1 --- /dev/null +++ b/test/models/helpers/pages_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class PagesHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/revisions_helper_test.rb b/test/models/helpers/revisions_helper_test.rb new file mode 100644 index 0000000..6bb5f07 --- /dev/null +++ b/test/models/helpers/revisions_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class RevisionsHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/rss_helper_test.rb b/test/models/helpers/rss_helper_test.rb new file mode 100644 index 0000000..b040b3e --- /dev/null +++ b/test/models/helpers/rss_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class RssHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/search_helper_test.rb b/test/models/helpers/search_helper_test.rb new file mode 100644 index 0000000..3034163 --- /dev/null +++ b/test/models/helpers/search_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class SearchHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/tags_helper_test.rb b/test/models/helpers/tags_helper_test.rb new file mode 100644 index 0000000..4b1935f --- /dev/null +++ b/test/models/helpers/tags_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class TagsHelperTest < ActionView::TestCase +end diff --git a/test/models/helpers/users_helper_test.rb b/test/models/helpers/users_helper_test.rb new file mode 100644 index 0000000..96af37a --- /dev/null +++ b/test/models/helpers/users_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class UsersHelperTest < ActionView::TestCase +end diff --git a/test/models/menu_item_test.rb b/test/models/menu_item_test.rb new file mode 100644 index 0000000..81d9c01 --- /dev/null +++ b/test/models/menu_item_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class MenuItemTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/test/models/node_test.rb b/test/models/node_test.rb new file mode 100644 index 0000000..514ba3f --- /dev/null +++ b/test/models/node_test.rb @@ -0,0 +1,290 @@ +require 'test_helper' + +class NodeTest < ActiveSupport::TestCase + + def setup + @root = Node.find(1) + @first_child = Node.find(2) + @first_child.pages.create! :title => "one" + @first_child.draft = @first_child.pages.last + @first_child.save + @second_child = Node.find(3) + @second_child.pages.create! :title => "one" + + @user1 = User.create :login => 'demo', :email => "f@b.com", :password => 'foobar', :password_confirmation => 'foobar' + @user2 = User.create :login => 'show', :email => "f@b.com", :password => 'foobar', :password_confirmation => 'foobar' + end + + test "can only create one root node" do + Node.delete_all + Node.create! :slug => :root + assert_raise(ActiveRecord::RecordInvalid) do + Node.create! :slug => :root + end + end + + def test_returning_existing_drafts + test_node = Node.root.children.create! :slug => "test_node" + + assert_not_nil test_node.draft + assert_equal 1, test_node.pages.length + assert_nil test_node.draft.user + + 3.times do + test_node.find_or_create_draft @user1 + end + + assert_equal 1, test_node.pages.length + end + + def test_user_gets_assigned_to_unlocked_draft + assert_not_nil @first_child.draft + assert_nil @first_child.draft.user + @first_child.find_or_create_draft @user1 + assert_equal @user1, @first_child.lock_owner + end + + def test_unique_path_returns_an_array + assert_equal ["first_child"], @first_child.unique_path + new_node = @first_child.children.create! :slug => "third_child" + assert_equal ["first_child", "third_child"], new_node.unique_path + end + + def test_specifying_a_revision_other_than_with_a_fixnum_raises_exception + assert_raise(ArgumentError) { Node.find_page "first_child", 1.9 } + assert_raise(ArgumentError) { Node.find_page "first_child", "1" } + assert_raise(ArgumentError) { Node.find_page "first_child", :head } + end + + def test_publish_draft_on_a_node_without_a_draft_returns_nil + + assert @first_child.publish_draft! + assert_nil @first_child.publish_draft! + end + + def test_cloning_a_head_page_to_a_new_draft_with_translations + assert_not_nil draft = @first_child.draft + I18n.locale = :de + draft.title = "Hallo" + draft.abstract = "Bitte" + draft.body = "Danke" + draft.save + I18n.locale = :en + draft.title = "Hello" + draft.abstract = "Please" + draft.body = "Thanks" + draft.save + + @first_child.publish_draft! + + draft1 = @first_child.find_or_create_draft(@user1) + + I18n.locale = :de + assert_equal "Hallo", draft1.title + assert_equal "Bitte", draft1.abstract + assert_equal "Danke", draft1.body + + I18n.locale = :en + assert_equal "Hello", draft1.title + assert_equal "Please", draft1.abstract + assert_equal "Thanks", draft1.body + end + + def test_created_nodes_have_an_empty_draft_and_no_head + node = Node.root.children.create! :slug => "third_child_beta" + + assert !node.pages.empty? + assert_equal 1, node.pages.length + assert_not_nil node.draft + assert_nil node.draft.user + assert_nil node.head + end + + def test_create_new_draft_of_published_page + node = Node.root.children.create :slug => "xyz" + assert node.publish_draft! + end + + def test_find_or_create_draft_if_no_draft_exists + node = Node.root.children.create :slug => "xyz" + node.publish_draft! + assert_not_nil node.find_or_create_draft( @user1 ) + end + + def test_find_or_create_draft_if_draft_exists_and_is_owned_by_user + node = Node.root.children.create :slug => "xyz" + node.publish_draft! + + node.find_or_create_draft @user1 + node.find_or_create_draft @user1 + end + + def test_exception_if_draft_exists_but_locked_by_another_user + node = Node.root.children.create :slug => "xyz" + node.publish_draft! + node.find_or_create_draft @user1 + assert_equal @user1, node.lock_owner + assert_raise(LockedByAnotherUser) do + node.find_or_create_draft @user2 + end + end + + def test_creation_of_unique_name + node = Node.root.children.create :slug => 'child' + node.reload + assert_equal 'child', node.unique_name + + node = @first_child.children.create :slug => 'deep_child' + node.reload + assert_equal 'first_child/deep_child', node.unique_name + end + + def test_order_of_pages_by_revision + # This test should make sure the order is the same on different db's + # Remember, there is already an empty draft + two = @second_child.pages.create :title => "two" + three = @second_child.pages.create :title => "three" + four = @second_child.pages.create :title => "four" + + @second_child.pages.reload + + assert_equal [1,2,3,4], @second_child.pages.map { |x| x.revision } + end + + def test_behavior_of_acts_as_list + two = @second_child.pages.create :title => "two" + three = @second_child.pages.create :title => "three" + four = @second_child.pages.create :title => "four" + + assert_equal 2, two.revision + assert_equal 3, three.revision + assert_equal 4, four.revision + + assert_equal four, @second_child.pages.last + + assert two.move_to_bottom + + two.reload; three.reload; four.reload; + + assert_equal 4, two.revision + assert_equal 2, three.revision + assert_equal 3, four.revision + end + + def test_retrieving_page_current + updates = Node.root.children.create(:slug => 'updates') + year = updates.children.create(:slug => '2008') + foo = year.children.create(:slug => 'foo') + + assert_not_nil Node.find_by_unique_name('updates/2008/foo') + + # Note that there is already an initial, blank revision + foo.pages.create :title => "Version 2" + foo.pages.create :title => "Version 3" + foo.pages.create :title => "Version 4" + + foo.head = foo.pages.last + foo.save! + + page = Node.find_page("updates/2008/foo") + assert_equal page, foo.pages.find_by_revision(4) + end + + def test_retrieving_page_by_revision + updates = Node.root.children.create(:slug => 'updates') + year = updates.children.create(:slug => '2008') + foo = year.children.create(:slug => 'foo') + + assert_not_nil Node.find_by_unique_name('updates/2008/foo') + + # Note that there is already an initial, blank revision + foo.pages.create :title => "Version 2" + foo.pages.create :title => "Version 3" + foo.pages.create :title => "Version 4" + + page = Node.find_page("updates/2008/foo", 2) + assert_equal "Version 2", page.title + end + + # Thats a lengthy test to make sure everything works as it should, it was + # created during a bug hunt + def test_creating_new_draft + test_node = Node.root.children.create! :slug => "test_node" + test_node.draft.user = @user1 + test_node.save + assert test_node.publish_draft! + test_node.reload + assert_equal 1, test_node.pages.length + assert_not_nil test_node.head + assert_nil test_node.draft + test_node.find_or_create_draft @user1 + test_node.reload + assert_equal 2, test_node.pages.length + assert_not_nil test_node.draft + assert test_node.head != test_node.draft + end + + test "restoring a revision" do + test_node = Node.root.children.create! :slug => "test_node" + create_revisions( test_node, 3 ) + test_node.find_or_create_draft @user1 + test_node.reload + + assert_equal 4, test_node.pages.count + assert_equal 3, test_node.head.revision + + test_node.restore_revision!(1) + assert_equal 1, test_node.head.revision + assert_equal 4, test_node.draft.revision + end + + test "a new revision keeps the initial user" do + Node.root.descendants.destroy_all + node = create_node_with_draft + draft = node.draft + draft.user = users(:aaron) + draft.save + node.publish_draft! + new_draft = node.find_or_create_draft( users(:quentin) ) + assert_equal "aaron", new_draft.user.login + end + + test "a new revision can overwrite the initial author" do + Node.root.descendants.destroy_all + node = create_node_with_draft + draft = node.draft + draft.user = users(:aaron) + draft.save! + node.publish_draft! + new_draft = node.find_or_create_draft( users(:quentin) ) + new_draft.user_id = users(:quentin).id + new_draft.save + node.publish_draft! + assert_equal "quentin", node.head.user.login + end + + + test "update?" do + Node.root.descendants.delete_all + updates = Node.root.children.create!( :slug => "updates" ) + assert !updates.update? + + updates2009 = updates.children.create!( :slug => "2009" ) + assert !updates2009.update? + + update = updates2009.children.create!( :slug => "my-first-update" ) + assert update.update? + end + + test "new nodes should have drafts with no publidhed_at set" do + node = Node.root.children.create( :slug => "wow" ) + assert_nil node.draft.published_at + end + + def create_revisions node, count + count.times do + node.find_or_create_draft @user1 + node.publish_draft! + end + end +end diff --git a/test/models/occurrence_test.rb b/test/models/occurrence_test.rb new file mode 100644 index 0000000..91a78ec --- /dev/null +++ b/test/models/occurrence_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class OccurrenceTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/test/models/page_test.rb b/test/models/page_test.rb new file mode 100644 index 0000000..8b34399 --- /dev/null +++ b/test/models/page_test.rb @@ -0,0 +1,146 @@ +require 'test_helper' + +class PageTest < ActiveSupport::TestCase + + def setup + @user1 = User.create :login => 'demo', :email => "f@b.com", :password => 'foobar', :password_confirmation => 'foobar' + @user2 = User.create :login => 'show', :email => "f@b.com", :password => 'foobar', :password_confirmation => 'foobar' + end + + def test_aggregation + # Create two nodes and move them beneath the root node + n1 = Node.root.children.create! :slug => "one" + n2 = Node.root.children.create! :slug => "two" + + # get the drafts and assign a user to it + assert_not_nil d1 = n1.find_or_create_draft( @user1 ) + assert_not_nil d3 = n2.find_or_create_draft( @user1 ) + + # tag and double publish so we have 4 pages tagged with "update" + d1.tag_list = "update" + d1.save + n1.publish_draft! + + d2 = n1.find_or_create_draft @user1 + n1.publish_draft! + + + d3.tag_list = "update, pressemitteilung" + d3.save + n2.publish_draft! + + d4 = n2.find_or_create_draft @user1 + n2.publish_draft! + + # Set up two options hashes for the assertions + options1 = { + :tags => "update" + } + + options2 = { + :tags => "update, pressemitteilung" + } + + assert_equal 2, Page.aggregate( options1 ).length + assert_equal 1, Page.aggregate( options2 ).length + assert_equal 4, Page.tagged_with( "update" ).length + assert_equal [d2.id, d4.id], Page.aggregate( options1 ).map {|x| x.id} + end + + def test_before_save_rewrite_links_in_body + n = Node.root.children.create :slug => "link_test" + d = n.find_or_create_draft @user1 + + before = "

Hello World

\n" \ + "Linkme" + + after = "

Hello World

\n" \ + "Linkme" + + I18n.locale = :de + + d.body = before + d.save! + + assert_equal after, d.body + end + + def test_before_save_rewrite_links_in_body_if_no_locale_prefix_present + n = Node.root.children.create :slug => "link_test" + d = n.find_or_create_draft @user1 + + before = "

Hello World

\n" \ + "Linkme" + + after = "

Hello World

\n" \ + "Linkme" + + I18n.locale = :de + + d.body = before + d.save + + assert_equal after, d.body + end + + def test_before_save_rewrite_links_skips_on_external_links + n = Node.root.children.create :slug => "link_test" + d = n.find_or_create_draft @user1 + + before = "

Hello World

\n" \ + "Linkme" + + after = "

Hello World

\n" \ + "Linkme" + + I18n.locale = :de + + d.body = before + d.save + + assert_equal after, d.body + end + + def test_find_with_outdated_translations + Node.delete_all + Page.delete_all + I18n.locale = :de + + assert_not_nil page = Page.create!( :title => "Hallo" ) + page.reload + assert_equal 1, page.translations.size + assert_equal [], Page.find_with_outdated_translations + + I18n.locale = :en + page.title = "Hello" + page.save + + assert_equal 2, page.translations.size + assert_equal 0, Page.find_with_outdated_translations.size + + english = page.translations.select {|x| x.locale == :en}.first + Page::Translation.record_timestamps = false + english.update_attributes(:updated_at => (Time.now+25.hours)) + Page::Translation.record_timestamps = true + assert_equal 1, Page.find_with_outdated_translations.count + + I18n.locale = :de + page2 = Page.create!( :title => "Hallo2" ) + I18n.locale = :en + page2.title = "Hello2" + page2.save! + + assert_equal 0, Page.find_with_outdated_translations(:delta_time => 23.days).count + assert_equal 1, Page.find_with_outdated_translations(:delta_time => 23.minutes).count + assert_equal 2, Page.count + end + + test "pages under /updates node get the update template assigned" do + Node.root.descendants.delete_all + updates = Node.root.children.create!( :slug => "updates" ) + updates2009 = updates.children.create!( :slug => "2009" ) + update = updates2009.children.create!( :slug => "my-first-update" ) + assert_equal "update", update.draft.template_name + end + +end diff --git a/test/models/permission_test.rb b/test/models/permission_test.rb new file mode 100644 index 0000000..08fcc0b --- /dev/null +++ b/test/models/permission_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class PermissionTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/test/models/related_asset_test.rb b/test/models/related_asset_test.rb new file mode 100644 index 0000000..a739e6b --- /dev/null +++ b/test/models/related_asset_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class RelatedImageTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..bd5d059 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,64 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class UserTest < ActiveSupport::TestCase + # Be sure to include AuthenticatedTestHelper in test/test_helper.rb instead. + # Then, you can remove it from this and the functional test. + include AuthenticatedTestHelper + fixtures :users + + def test_should_create_user + assert_difference 'User.count' do + user = create_user + assert !user.new_record?, "#{user.errors.full_messages.to_sentence}" + end + end + + def test_should_require_login + assert_no_difference 'User.count' do + u = create_user(:login => nil) + assert u.errors[:login].any? + end + end + + def test_should_require_password + assert_no_difference 'User.count' do + u = create_user(:password => nil) + assert u.errors[:password].any? + end + end + + def test_should_require_password_confirmation + assert_no_difference 'User.count' do + u = create_user(:password_confirmation => nil) + assert u.errors[:password_confirmation].any? + end + end + + def test_should_require_email + assert_no_difference 'User.count' do + u = create_user(:email => nil) + assert u.errors[:email].any? + end + end + + def test_should_reset_password + users(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password') + assert_equal users(:quentin), User.authenticate('quentin', 'new password') + end + + def test_should_not_rehash_password + users(:quentin).update_attributes(:login => 'quentin2') + assert_equal users(:quentin), User.authenticate('quentin2', 'monkey') + end + + def test_should_authenticate_user + assert_equal users(:quentin), User.authenticate('quentin', 'monkey') + end + +protected + def create_user(options = {}) + record = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire69', :password_confirmation => 'quire69' }.merge(options)) + record.save + record + end +end -- 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 'test/models') 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") %>