diff options
| -rw-r--r-- | Gemfile | 1 | ||||
| -rw-r--r-- | Gemfile.lock | 7 | ||||
| -rw-r--r-- | app/helpers/link_helper.rb | 35 | ||||
| -rw-r--r-- | app/helpers/nodes_helper.rb | 2 | ||||
| -rw-r--r-- | app/models/locked_by_another_user.rb | 1 | ||||
| -rw-r--r-- | app/models/node.rb | 13 | ||||
| -rw-r--r-- | app/views/admin/_recent_changes.html.erb | 2 | ||||
| -rw-r--r-- | app/views/content/_search.html.erb | 2 | ||||
| -rw-r--r-- | app/views/content/_tags.html.erb | 2 | ||||
| -rw-r--r-- | app/views/layouts/application.html.erb | 4 | ||||
| -rw-r--r-- | config/application.rb | 1 | ||||
| -rw-r--r-- | config/environments/development.rb | 2 | ||||
| -rw-r--r-- | config/environments/test.rb | 4 | ||||
| -rw-r--r-- | config/initializers/i18n.rb | 3 | ||||
| -rw-r--r-- | config/initializers/will_paginate_patch.rb | 13 | ||||
| -rw-r--r-- | doc/20260626025705_add_search_vector_to_page_translations.rb.pending | 47 |
16 files changed, 75 insertions, 64 deletions
| @@ -26,6 +26,7 @@ group :assets do | |||
| 26 | gem 'sass-rails', '~> 6.0' | 26 | gem 'sass-rails', '~> 6.0' |
| 27 | gem 'coffee-rails', '~> 4.0' | 27 | gem 'coffee-rails', '~> 4.0' |
| 28 | gem 'uglifier', '>= 1.0.3' | 28 | gem 'uglifier', '>= 1.0.3' |
| 29 | gem 'minitest', '~> 5.25' | ||
| 29 | end | 30 | end |
| 30 | 31 | ||
| 31 | group :test do | 32 | group :test do |
diff --git a/Gemfile.lock b/Gemfile.lock index 357998d..9d5ec90 100644 --- a/Gemfile.lock +++ b/Gemfile.lock | |||
| @@ -157,9 +157,7 @@ GEM | |||
| 157 | marcel (1.2.1) | 157 | marcel (1.2.1) |
| 158 | mini_mime (1.1.5) | 158 | mini_mime (1.1.5) |
| 159 | mini_portile2 (2.8.9) | 159 | mini_portile2 (2.8.9) |
| 160 | minitest (6.0.6) | 160 | minitest (5.27.0) |
| 161 | drb (~> 2.0) | ||
| 162 | prism (~> 1.5) | ||
| 163 | net-imap (0.6.4.1) | 161 | net-imap (0.6.4.1) |
| 164 | date | 162 | date |
| 165 | net-protocol | 163 | net-protocol |
| @@ -323,6 +321,7 @@ DEPENDENCIES | |||
| 323 | globalize (~> 7.0) | 321 | globalize (~> 7.0) |
| 324 | jquery-rails | 322 | jquery-rails |
| 325 | libxml-ruby (~> 5.0) | 323 | libxml-ruby (~> 5.0) |
| 324 | minitest (~> 5.25) | ||
| 326 | nokogiri (~> 1.18) | 325 | nokogiri (~> 1.18) |
| 327 | pg (~> 1.4.6) | 326 | pg (~> 1.4.6) |
| 328 | puma | 327 | puma |
| @@ -394,7 +393,7 @@ CHECKSUMS | |||
| 394 | marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f | 393 | marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f |
| 395 | mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef | 394 | mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef |
| 396 | mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289 | 395 | mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289 |
| 397 | minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1 | 396 | minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5 |
| 398 | net-imap (0.6.4.1) sha256=29f0360d75a7efd3539f16ac1957dea5c0a51ddeceb348db4553c3120914ea0d | 397 | net-imap (0.6.4.1) sha256=29f0360d75a7efd3539f16ac1957dea5c0a51ddeceb348db4553c3120914ea0d |
| 399 | net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 | 398 | net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3 |
| 400 | net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 | 399 | net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8 |
diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb index 39ec495..cb13c8d 100644 --- a/app/helpers/link_helper.rb +++ b/app/helpers/link_helper.rb | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | module LinkHelper | 1 | module LinkHelper |
| 2 | 2 | ||
| 3 | def content_path_helper path_array | 3 | def content_path_helper path_array |
| 4 | url_for( | 4 | url_for( |
| 5 | :controller => :content, | 5 | :controller => :content, |
| @@ -8,11 +8,11 @@ module LinkHelper | |||
| 8 | :page_path => path_array | 8 | :page_path => path_array |
| 9 | ) | 9 | ) |
| 10 | end | 10 | end |
| 11 | 11 | ||
| 12 | def content_url_helper path_array | 12 | def content_url_helper path_array |
| 13 | request.protocol + request.host_with_port + content_path_helper(path_array) | 13 | request.protocol + request.host_with_port + content_path_helper(path_array) |
| 14 | end | 14 | end |
| 15 | 15 | ||
| 16 | def link_to_path title, path, html_options = {} | 16 | def link_to_path title, path, html_options = {} |
| 17 | return "" if path.nil? | 17 | return "" if path.nil? |
| 18 | 18 | ||
| @@ -22,9 +22,7 @@ module LinkHelper | |||
| 22 | end | 22 | end |
| 23 | 23 | ||
| 24 | active_class = active ? {:class => 'active'} : {:class => 'inactive'} | 24 | active_class = active ? {:class => 'active'} : {:class => 'inactive'} |
| 25 | |||
| 26 | html_options = html_options.merge(active_class) | 25 | html_options = html_options.merge(active_class) |
| 27 | |||
| 28 | locale = params[:locale] || I18n.locale | 26 | locale = params[:locale] || I18n.locale |
| 29 | 27 | ||
| 30 | link_to( | 28 | link_to( |
| @@ -39,34 +37,13 @@ module LinkHelper | |||
| 39 | return :class => "selected" | 37 | return :class => "selected" |
| 40 | end | 38 | end |
| 41 | end | 39 | end |
| 42 | 40 | ||
| 43 | def unlock_link | 41 | def unlock_link |
| 44 | message = "Are you sure you want to unlock?\n" + | 42 | message = "Are you sure you want to unlock?\n" + |
| 45 | "Locked by #{@node.lock_owner.login}\n" + | 43 | "Locked by #{@node.lock_owner.login}\n" + |
| 46 | "Last modified #{@page.updated_at.to_s(:db)}" | 44 | "Last modified #{@page.updated_at.to_fs(:db)}" |
| 47 | |||
| 48 | link_to 'Unlock', safe_path(:unlock_node_path, @node), :method => :put, :data => { :confirm => message } | ||
| 49 | end | ||
| 50 | |||
| 51 | # Rails 6.1 workaround: content_path named helper returns RouteWithParams | ||
| 52 | # when called from within a catch-all glob route request context. | ||
| 53 | # Rails 6.1 workaround: named route helpers return RouteWithParams when called | ||
| 54 | # from within a catch-all glob route request context. | ||
| 55 | # Remove this method when upgrading to Rails 7.0+, where this is fixed. | ||
| 56 | def safe_path(name, *args) | ||
| 57 | Rails.application.routes.url_helpers.send(name, *args) | ||
| 58 | end | ||
| 59 | 45 | ||
| 60 | def content_path(page_path = nil, options = {}) | 46 | link_to 'Unlock', unlock_node_path(@node), :method => :put, :data => { :confirm => message } |
| 61 | if page_path.is_a?(Hash) | ||
| 62 | options = page_path | ||
| 63 | page_path = options.delete(:page_path) | ||
| 64 | end | ||
| 65 | options[:locale] ||= params[:locale] || I18n.locale | ||
| 66 | Rails.application.routes.url_helpers.content_path( | ||
| 67 | Array(page_path).join("/").sub(/^\//, ""), | ||
| 68 | options | ||
| 69 | ) | ||
| 70 | end | 47 | end |
| 71 | 48 | ||
| 72 | end | 49 | end |
diff --git a/app/helpers/nodes_helper.rb b/app/helpers/nodes_helper.rb index 204ad8a..c739ccd 100644 --- a/app/helpers/nodes_helper.rb +++ b/app/helpers/nodes_helper.rb | |||
| @@ -31,7 +31,7 @@ module NodesHelper | |||
| 31 | 31 | ||
| 32 | def event_information | 32 | def event_information |
| 33 | if @node.event | 33 | if @node.event |
| 34 | "#{@node.event.start_time.to_s(:db)} - #{@node.event.end_time.to_s(:db)} > " \ | 34 | "#{@node.event.start_time.to_fs(:db)} - #{@node.event.end_time.to_fs(:db)} > " \ |
| 35 | "#{link_to 'show', event_path(@node.event)} " \ | 35 | "#{link_to 'show', event_path(@node.event)} " \ |
| 36 | "#{link_to 'edit', edit_event_path(@node.event)}" | 36 | "#{link_to 'edit', edit_event_path(@node.event)}" |
| 37 | else | 37 | else |
diff --git a/app/models/locked_by_another_user.rb b/app/models/locked_by_another_user.rb new file mode 100644 index 0000000..6f9e272 --- /dev/null +++ b/app/models/locked_by_another_user.rb | |||
| @@ -0,0 +1 @@ | |||
| class LockedByAnotherUser < StandardError; end | |||
diff --git a/app/models/node.rb b/app/models/node.rb index f7a70d0..41c3867 100644 --- a/app/models/node.rb +++ b/app/models/node.rb | |||
| @@ -73,7 +73,7 @@ class Node < ApplicationRecord | |||
| 73 | raise( | 73 | raise( |
| 74 | LockedByAnotherUser, | 74 | LockedByAnotherUser, |
| 75 | "Page is locked by another user who is working on it! " \ | 75 | "Page is locked by another user who is working on it! " \ |
| 76 | "Last modification: #{draft.updated_at.to_s(:db)}" | 76 | "Last modification: #{draft.updated_at.to_fs(:db)}" |
| 77 | ) | 77 | ) |
| 78 | else | 78 | else |
| 79 | lock_for! current_user | 79 | lock_for! current_user |
| @@ -211,6 +211,13 @@ class Node < ApplicationRecord | |||
| 211 | self.created_at < new_id_format_date ? unique_path : id | 211 | self.created_at < new_id_format_date ? unique_path : id |
| 212 | end | 212 | end |
| 213 | 213 | ||
| 214 | # TODO: restore full-text search once PostgreSQL is upgraded. | ||
| 215 | # The tsvector/plpgsql approach requires PostgreSQL 10+ with plpgsql available. | ||
| 216 | # For now, search is disabled to unblock the Rails 7.2 upgrade. | ||
| 217 | def self.search(term, _ = {}) | ||
| 218 | none | ||
| 219 | end | ||
| 220 | |||
| 214 | protected | 221 | protected |
| 215 | def lock_for! current_user | 222 | def lock_for! current_user |
| 216 | self.lock_owner = current_user | 223 | self.lock_owner = current_user |
| @@ -255,7 +262,3 @@ class Node < ApplicationRecord | |||
| 255 | end | 262 | end |
| 256 | end | 263 | end |
| 257 | end | 264 | end |
| 258 | |||
| 259 | class LockedByAnotherUser < StandardError; end | ||
| 260 | |||
| 261 | |||
diff --git a/app/views/admin/_recent_changes.html.erb b/app/views/admin/_recent_changes.html.erb index 300d088..88b5e93 100644 --- a/app/views/admin/_recent_changes.html.erb +++ b/app/views/admin/_recent_changes.html.erb | |||
| @@ -13,7 +13,7 @@ | |||
| 13 | <td><%= truncated_title_for_node node %></td> | 13 | <td><%= truncated_title_for_node node %></td> |
| 14 | <td><%= node.unique_name %></td> | 14 | <td><%= node.unique_name %></td> |
| 15 | <td><%= node.draft.user.login rescue "" %></td> | 15 | <td><%= node.draft.user.login rescue "" %></td> |
| 16 | <td><%= node.updated_at.to_s(:db) %></td> | 16 | <td><%= node.updated_at.to_fs(:db) %></td> |
| 17 | <td class="actions"> | 17 | <td class="actions"> |
| 18 | <%= link_to 'Show', node_path(node) %> | 18 | <%= link_to 'Show', node_path(node) %> |
| 19 | <%= link_to "Revisions", revision_path(:id => node.id) %> | 19 | <%= link_to "Revisions", revision_path(:id => node.id) %> |
diff --git a/app/views/content/_search.html.erb b/app/views/content/_search.html.erb index f732fca..aa91424 100644 --- a/app/views/content/_search.html.erb +++ b/app/views/content/_search.html.erb | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | <%= form_tag safe_path(:search_path), :method => 'get' do %> | 1 | <%= form_tag search_path, :method => 'get' do %> |
| 2 | <div><%= text_field_tag :search_term, params[:search_term], :placeholder => 'suchen', :type => 'search' %></div> | 2 | <div><%= text_field_tag :search_term, params[:search_term], :placeholder => 'suchen', :type => 'search' %></div> |
| 3 | <% end %> | 3 | <% end %> |
diff --git a/app/views/content/_tags.html.erb b/app/views/content/_tags.html.erb index 387f51c..f0e7210 100644 --- a/app/views/content/_tags.html.erb +++ b/app/views/content/_tags.html.erb | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | <h2>Tags</h2> | 3 | <h2>Tags</h2> |
| 4 | <ul class="teasertext"> | 4 | <ul class="teasertext"> |
| 5 | <% @page.tags.each do |tag| %> | 5 | <% @page.tags.each do |tag| %> |
| 6 | <li><%= link_to tag.name, safe_path(:tag_path, tag.name) %></li> | 6 | <li><%= link_to tag.name, tag_path(tag.name) %></li> |
| 7 | <% end %> | 7 | <% end %> |
| 8 | </ul> | 8 | </ul> |
| 9 | </div> | 9 | </div> |
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 84dcdc6..c5cbf14 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb | |||
| @@ -52,8 +52,8 @@ | |||
| 52 | <div class="main_navigation"> | 52 | <div class="main_navigation"> |
| 53 | <h2>Admin</h2> | 53 | <h2>Admin</h2> |
| 54 | <ul> | 54 | <ul> |
| 55 | <li><%= link_to raw('<span class="inactive admin_edit_link">⚙️ Overview</span>'), safe_path(:admin_path) %></li> | 55 | <li><%= link_to raw('<span class="inactive admin_edit_link">⚙️ Overview</span>'), admin_path %></li> |
| 56 | <li><%= link_to raw('<span class="inactive admin_edit_link">✎ Edit</span>'), safe_path(:node_path, @page.node) %></li> | 56 | <li><%= link_to raw('<span class="inactive admin_edit_link">✎ Edit</span>'), node_path(@page.node) %></li> |
| 57 | </ul> | 57 | </ul> |
| 58 | </div> | 58 | </div> |
| 59 | <% end %> | 59 | <% end %> |
diff --git a/config/application.rb b/config/application.rb index 1a7f32b..d92802f 100644 --- a/config/application.rb +++ b/config/application.rb | |||
| @@ -54,6 +54,7 @@ module Cccms | |||
| 54 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. | 54 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. |
| 55 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] | 55 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')] |
| 56 | config.i18n.default_locale = :de | 56 | config.i18n.default_locale = :de |
| 57 | config.i18n.fallbacks = { en: [:en, :de] } | ||
| 57 | 58 | ||
| 58 | config.filter_parameters += [:password, :password_confirmation] | 59 | config.filter_parameters += [:password, :password_confirmation] |
| 59 | config.serve_static_files = true | 60 | config.serve_static_files = true |
diff --git a/config/environments/development.rb b/config/environments/development.rb index 8e2e7ef..43a6846 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb | |||
| @@ -4,7 +4,7 @@ Cccms::Application.configure do | |||
| 4 | # In the development environment your application's code is reloaded on | 4 | # In the development environment your application's code is reloaded on |
| 5 | # every request. This slows down response time but is perfect for development | 5 | # every request. This slows down response time but is perfect for development |
| 6 | # since you don't have to restart the webserver when you make code changes. | 6 | # since you don't have to restart the webserver when you make code changes. |
| 7 | config.cache_classes = false | 7 | config.enable_reloading = true |
| 8 | 8 | ||
| 9 | # Log error messages when you accidentally call methods on nil. | 9 | # Log error messages when you accidentally call methods on nil. |
| 10 | 10 | ||
diff --git a/config/environments/test.rb b/config/environments/test.rb index a23c6d4..48aafe8 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | Cccms::Application.configure do | 1 | Cccms::Application.configure do |
| 2 | 2 | ||
| 3 | config.cache_classes = true | 3 | config.enable_reloading = false |
| 4 | 4 | ||
| 5 | config.action_controller.consider_all_requests_local = true | 5 | config.action_controller.consider_all_requests_local = true |
| 6 | config.action_controller.perform_caching = false | 6 | config.action_controller.perform_caching = false |
| @@ -10,10 +10,8 @@ Cccms::Application.configure do | |||
| 10 | config.action_mailer.delivery_method = :test | 10 | config.action_mailer.delivery_method = :test |
| 11 | 11 | ||
| 12 | config.active_support.deprecation = :log | 12 | config.active_support.deprecation = :log |
| 13 | config.active_support.test_order = :sorted | ||
| 14 | 13 | ||
| 15 | config.eager_load = false | 14 | config.eager_load = false |
| 16 | config.public_file_server.enabled = true | 15 | config.public_file_server.enabled = true |
| 17 | config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' } | 16 | config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' } |
| 18 | config.assets.compile = true | ||
| 19 | end | 17 | end |
diff --git a/config/initializers/i18n.rb b/config/initializers/i18n.rb deleted file mode 100644 index 0190f63..0000000 --- a/config/initializers/i18n.rb +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | require "i18n/backend/fallbacks" | ||
| 2 | I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) | ||
| 3 | I18n.fallbacks.map "en" => ["de"] | ||
diff --git a/config/initializers/will_paginate_patch.rb b/config/initializers/will_paginate_patch.rb deleted file mode 100644 index d03c882..0000000 --- a/config/initializers/will_paginate_patch.rb +++ /dev/null | |||
| @@ -1,13 +0,0 @@ | |||
| 1 | require 'will_paginate/view_helpers/action_view' | ||
| 2 | |||
| 3 | WillPaginate::ActionView::LinkRenderer.class_eval do | ||
| 4 | def url(page) | ||
| 5 | path = @template.request.path | ||
| 6 | page_param = WillPaginate::PageNumber(page) | ||
| 7 | if page_param == 1 | ||
| 8 | path | ||
| 9 | else | ||
| 10 | "#{path}?#{@options[:param_name]}=#{page}" | ||
| 11 | end | ||
| 12 | end | ||
| 13 | end | ||
diff --git a/doc/20260626025705_add_search_vector_to_page_translations.rb.pending b/doc/20260626025705_add_search_vector_to_page_translations.rb.pending new file mode 100644 index 0000000..0747637 --- /dev/null +++ b/doc/20260626025705_add_search_vector_to_page_translations.rb.pending | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | class AddSearchVectorToPageTranslations < ActiveRecord::Migration[7.2] | ||
| 2 | def up | ||
| 3 | add_column :page_translations, :search_vector, :tsvector | ||
| 4 | |||
| 5 | execute <<~SQL | ||
| 6 | UPDATE page_translations | ||
| 7 | SET search_vector = to_tsvector( | ||
| 8 | 'simple', | ||
| 9 | coalesce(title, '') || ' ' || | ||
| 10 | coalesce(abstract, '') || ' ' || | ||
| 11 | coalesce(body, '') | ||
| 12 | ) | ||
| 13 | SQL | ||
| 14 | |||
| 15 | add_index :page_translations, :search_vector, | ||
| 16 | using: :gin, | ||
| 17 | name: 'index_page_translations_on_search_vector' | ||
| 18 | |||
| 19 | execute <<~SQL | ||
| 20 | CREATE OR REPLACE FUNCTION page_translations_search_vector_update() | ||
| 21 | RETURNS trigger AS $$ | ||
| 22 | BEGIN | ||
| 23 | NEW.search_vector := to_tsvector( | ||
| 24 | 'simple', | ||
| 25 | coalesce(NEW.title, '') || ' ' || | ||
| 26 | coalesce(NEW.abstract, '') || ' ' || | ||
| 27 | coalesce(NEW.body, '') | ||
| 28 | ); | ||
| 29 | RETURN NEW; | ||
| 30 | END; | ||
| 31 | $$ LANGUAGE plpgsql; | ||
| 32 | |||
| 33 | CREATE TRIGGER page_translations_search_vector_trigger | ||
| 34 | BEFORE INSERT OR UPDATE ON page_translations | ||
| 35 | FOR EACH ROW EXECUTE PROCEDURE page_translations_search_vector_update(); | ||
| 36 | SQL | ||
| 37 | end | ||
| 38 | |||
| 39 | def down | ||
| 40 | execute <<~SQL | ||
| 41 | DROP TRIGGER IF EXISTS page_translations_search_vector_trigger ON page_translations; | ||
| 42 | DROP FUNCTION IF EXISTS page_translations_search_vector_update(); | ||
| 43 | SQL | ||
| 44 | remove_index :page_translations, name: 'index_page_translations_on_search_vector' | ||
| 45 | remove_column :page_translations, :search_vector | ||
| 46 | end | ||
| 47 | end | ||
