summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-06-26 01:59:57 +0200
committererdgeist <erdgeist@erdgeist.org>2026-06-26 01:59:57 +0200
commitc06723ee715512c2033c7786c48f15674585b56b (patch)
tree46d074bde9a4fc61f0a76cbc601007ed4412ec61
parent0818a3057b0a91e422158d828026c941b4e10622 (diff)
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
-rw-r--r--.ruby-gemset2
-rw-r--r--.ruby-version2
-rw-r--r--Gemfile16
-rw-r--r--Gemfile.lock230
-rw-r--r--app/assets/config/manifest.js0
-rw-r--r--app/controllers/assets_controller.rb17
-rw-r--r--app/controllers/content_controller.rb9
-rw-r--r--app/controllers/events_controller.rb10
-rw-r--r--app/controllers/menu_items_controller.rb15
-rw-r--r--app/controllers/nodes_controller.rb6
-rw-r--r--app/controllers/occurrences_controller.rb11
-rw-r--r--app/controllers/pages_controller.rb2
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/helpers/admin_helper.rb6
-rw-r--r--app/helpers/link_helper.rb25
-rw-r--r--app/models/application_record.rb3
-rw-r--r--app/models/asset.rb17
-rw-r--r--app/models/concerns/file_attachment.rb124
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/menu_item.rb2
-rw-r--r--app/models/node.rb2
-rw-r--r--app/models/occurrence.rb2
-rw-r--r--app/models/page.rb2
-rw-r--r--app/models/permission.rb2
-rw-r--r--app/models/related_asset.rb2
-rw-r--r--app/models/user.rb2
-rw-r--r--app/views/content/_search.html.erb2
-rw-r--r--app/views/content/_tags.html.erb2
-rw-r--r--app/views/layouts/application.html.erb9
-rw-r--r--app/views/layouts/application.html.erb.bak54
-rw-r--r--config/environments/development.rb7
-rw-r--r--config/environments/production.rb14
-rw-r--r--config/environments/test.rb7
-rw-r--r--config/initializers/arel_patch.rb12
-rw-r--r--config/initializers/will_paginate_patch.rb13
-rw-r--r--config/routes.rb11
-rw-r--r--lib/chaos_importer.rb4
-rw-r--r--lib/update_importer.rb4
-rw-r--r--test/controllers/assets_controller_test.rb170
-rw-r--r--test/controllers/revisions_controller_test.rb2
-rw-r--r--test/fixtures/files/test_document.pdfbin0 -> 9246 bytes
-rw-r--r--test/fixtures/files/test_image.pngbin0 -> 49854 bytes
-rw-r--r--test/models/page_test.rb2
-rw-r--r--test/models/user_test.rb4
-rw-r--r--test/test_helper.rb67
45 files changed, 557 insertions, 340 deletions
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 @@
1source 'https://rubygems.org' 1source 'https://rubygems.org'
2 2
3gem 'rails', '5.2.8.1' 3gem 'rails', '6.1.7.10'
4gem 'concurrent-ruby', '1.3.4'
4 5
5gem 'pg', '~> 1.0' 6gem 'pg', '~> 1.0'
6 7
7gem 'acts-as-taggable-on', '~> 6.0' 8gem 'acts-as-taggable-on', '~> 7.0'
8gem 'awesome_nested_set', '~> 3.4.0' 9gem 'awesome_nested_set', '~> 3.4.0'
9gem 'acts_as_list' 10gem 'acts_as_list'
10gem 'globalize', '~> 5.2.0' 11gem 'globalize', '~> 6.0'
11gem 'routing-filter', '~> 0.6' 12gem 'routing-filter', '~> 0.7.0'
12gem 'paperclip', '~> 3.5'
13gem 'will_paginate', '~> 3.0' 13gem 'will_paginate', '~> 3.0'
14gem 'exception_notification', '~> 4.5' 14gem 'exception_notification', '~> 4.5'
15gem 'libxml-ruby', '~> 3.2', :require => 'xml' 15gem 'libxml-ruby', '~> 3.2', :require => 'xml'
16 16
17gem 'nokogiri', '~> 1.10.10' 17gem 'nokogiri', '~> 1.13'
18gem 'loofah', '~> 2.20.0'
19gem 'rails-html-sanitizer', '~> 1.4.4'
20gem 'jquery-rails' 18gem 'jquery-rails'
21 19
22gem 'unicorn', '~> 1.1' 20gem 'unicorn', '~> 1.1'
23 21
24group :assets do 22group :assets do
25 gem 'sass-rails', '~> 5.0' 23 gem 'sass-rails', '~> 6.0'
26 gem 'coffee-rails', '~> 4.0' 24 gem 'coffee-rails', '~> 4.0'
27 gem 'uglifier', '>= 1.0.3' 25 gem 'uglifier', '>= 1.0.3'
28end 26end
diff --git a/Gemfile.lock b/Gemfile.lock
index 74b71e7..d8294bd 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -8,59 +8,73 @@ GIT
8GEM 8GEM
9 remote: https://rubygems.org/ 9 remote: https://rubygems.org/
10 specs: 10 specs:
11 actioncable (5.2.8.1) 11 actioncable (6.1.7.10)
12 actionpack (= 5.2.8.1) 12 actionpack (= 6.1.7.10)
13 activesupport (= 6.1.7.10)
13 nio4r (~> 2.0) 14 nio4r (~> 2.0)
14 websocket-driver (>= 0.6.1) 15 websocket-driver (>= 0.6.1)
15 actionmailer (5.2.8.1) 16 actionmailbox (6.1.7.10)
16 actionpack (= 5.2.8.1) 17 actionpack (= 6.1.7.10)
17 actionview (= 5.2.8.1) 18 activejob (= 6.1.7.10)
18 activejob (= 5.2.8.1) 19 activerecord (= 6.1.7.10)
20 activestorage (= 6.1.7.10)
21 activesupport (= 6.1.7.10)
22 mail (>= 2.7.1)
23 actionmailer (6.1.7.10)
24 actionpack (= 6.1.7.10)
25 actionview (= 6.1.7.10)
26 activejob (= 6.1.7.10)
27 activesupport (= 6.1.7.10)
19 mail (~> 2.5, >= 2.5.4) 28 mail (~> 2.5, >= 2.5.4)
20 rails-dom-testing (~> 2.0) 29 rails-dom-testing (~> 2.0)
21 actionpack (5.2.8.1) 30 actionpack (6.1.7.10)
22 actionview (= 5.2.8.1) 31 actionview (= 6.1.7.10)
23 activesupport (= 5.2.8.1) 32 activesupport (= 6.1.7.10)
24 rack (~> 2.0, >= 2.0.8) 33 rack (~> 2.0, >= 2.0.9)
25 rack-test (>= 0.6.3) 34 rack-test (>= 0.6.3)
26 rails-dom-testing (~> 2.0) 35 rails-dom-testing (~> 2.0)
27 rails-html-sanitizer (~> 1.0, >= 1.0.2) 36 rails-html-sanitizer (~> 1.0, >= 1.2.0)
28 actionview (5.2.8.1) 37 actiontext (6.1.7.10)
29 activesupport (= 5.2.8.1) 38 actionpack (= 6.1.7.10)
39 activerecord (= 6.1.7.10)
40 activestorage (= 6.1.7.10)
41 activesupport (= 6.1.7.10)
42 nokogiri (>= 1.8.5)
43 actionview (6.1.7.10)
44 activesupport (= 6.1.7.10)
30 builder (~> 3.1) 45 builder (~> 3.1)
31 erubi (~> 1.4) 46 erubi (~> 1.4)
32 rails-dom-testing (~> 2.0) 47 rails-dom-testing (~> 2.0)
33 rails-html-sanitizer (~> 1.0, >= 1.0.3) 48 rails-html-sanitizer (~> 1.1, >= 1.2.0)
34 activejob (5.2.8.1) 49 activejob (6.1.7.10)
35 activesupport (= 5.2.8.1) 50 activesupport (= 6.1.7.10)
36 globalid (>= 0.3.6) 51 globalid (>= 0.3.6)
37 activemodel (5.2.8.1) 52 activemodel (6.1.7.10)
38 activesupport (= 5.2.8.1) 53 activesupport (= 6.1.7.10)
39 activerecord (5.2.8.1) 54 activerecord (6.1.7.10)
40 activemodel (= 5.2.8.1) 55 activemodel (= 6.1.7.10)
41 activesupport (= 5.2.8.1) 56 activesupport (= 6.1.7.10)
42 arel (>= 9.0) 57 activestorage (6.1.7.10)
43 activestorage (5.2.8.1) 58 actionpack (= 6.1.7.10)
44 actionpack (= 5.2.8.1) 59 activejob (= 6.1.7.10)
45 activerecord (= 5.2.8.1) 60 activerecord (= 6.1.7.10)
46 marcel (~> 1.0.0) 61 activesupport (= 6.1.7.10)
47 activesupport (5.2.8.1) 62 marcel (~> 1.0)
63 mini_mime (>= 1.1.0)
64 activesupport (6.1.7.10)
48 concurrent-ruby (~> 1.0, >= 1.0.2) 65 concurrent-ruby (~> 1.0, >= 1.0.2)
49 i18n (>= 0.7, < 2) 66 i18n (>= 1.6, < 2)
50 minitest (~> 5.1) 67 minitest (>= 5.1)
51 tzinfo (~> 1.1) 68 tzinfo (~> 2.0)
52 acts-as-taggable-on (6.5.0) 69 zeitwerk (~> 2.3)
53 activerecord (>= 5.0, < 6.1) 70 acts-as-taggable-on (7.0.0)
71 activerecord (>= 5.0, < 6.2)
54 acts_as_list (1.1.0) 72 acts_as_list (1.1.0)
55 activerecord (>= 4.2) 73 activerecord (>= 4.2)
56 arel (9.0.0)
57 awesome_nested_set (3.4.0) 74 awesome_nested_set (3.4.0)
58 activerecord (>= 4.0.0, < 7.0) 75 activerecord (>= 4.0.0, < 7.0)
59 base64 (0.3.0) 76 base64 (0.3.0)
60 builder (3.3.0) 77 builder (3.3.0)
61 climate_control (0.2.0)
62 cocaine (0.5.8)
63 climate_control (>= 0.0.3, < 1.0)
64 coffee-rails (4.2.2) 78 coffee-rails (4.2.2)
65 coffee-script (>= 2.2.0) 79 coffee-script (>= 2.2.0)
66 railties (>= 4.0.0) 80 railties (>= 4.0.0)
@@ -68,8 +82,8 @@ GEM
68 coffee-script-source 82 coffee-script-source
69 execjs 83 execjs
70 coffee-script-source (1.12.2) 84 coffee-script-source (1.12.2)
71 concurrent-ruby (1.3.7) 85 concurrent-ruby (1.3.4)
72 crass (1.0.6) 86 crass (1.0.7)
73 digest (3.2.1) 87 digest (3.2.1)
74 erubi (1.13.1) 88 erubi (1.13.1)
75 exception_notification (4.6.0) 89 exception_notification (4.6.0)
@@ -79,9 +93,9 @@ GEM
79 ffi (1.17.4) 93 ffi (1.17.4)
80 globalid (1.1.0) 94 globalid (1.1.0)
81 activesupport (>= 5.0) 95 activesupport (>= 5.0)
82 globalize (5.2.0) 96 globalize (6.3.0)
83 activemodel (>= 4.2, < 5.3) 97 activemodel (>= 4.2, < 7.2)
84 activerecord (>= 4.2, < 5.3) 98 activerecord (>= 4.2, < 7.2)
85 request_store (~> 1.0) 99 request_store (~> 1.0)
86 i18n (1.14.8) 100 i18n (1.14.8)
87 concurrent-ruby (~> 1.0) 101 concurrent-ruby (~> 1.0)
@@ -92,24 +106,20 @@ GEM
92 thor (>= 0.14, < 2.0) 106 thor (>= 0.14, < 2.0)
93 libxml-ruby (3.2.4) 107 libxml-ruby (3.2.4)
94 logger (1.7.0) 108 logger (1.7.0)
95 loofah (2.20.0) 109 loofah (2.25.1)
96 crass (~> 1.0.2) 110 crass (~> 1.0.2)
97 nokogiri (>= 1.5.9) 111 nokogiri (>= 1.12.0)
98 mail (2.9.0) 112 mail (2.9.0)
99 logger 113 logger
100 mini_mime (>= 0.1.1) 114 mini_mime (>= 0.1.1)
101 net-imap 115 net-imap
102 net-pop 116 net-pop
103 net-smtp 117 net-smtp
104 marcel (1.0.4) 118 marcel (1.2.1)
105 method_source (1.1.0) 119 method_source (1.1.0)
106 mime-types (3.7.0)
107 logger
108 mime-types-data (~> 3.2025, >= 3.2025.0507)
109 mime-types-data (3.2026.0414)
110 mini_mime (1.1.2) 120 mini_mime (1.1.2)
111 mini_portile2 (2.4.0) 121 mini_portile2 (2.8.9)
112 minitest (5.15.0) 122 minitest (5.26.1)
113 net-imap (0.2.2) 123 net-imap (0.2.2)
114 digest 124 digest
115 net-protocol 125 net-protocol
@@ -123,31 +133,30 @@ GEM
123 digest 133 digest
124 net-protocol 134 net-protocol
125 timeout 135 timeout
126 nio4r (2.7.3) 136 nio4r (2.7.5)
127 nokogiri (1.10.10) 137 nokogiri (1.15.7)
128 mini_portile2 (~> 2.4.0) 138 mini_portile2 (~> 2.8.2)
129 paperclip (3.5.4) 139 racc (~> 1.4)
130 activemodel (>= 3.0.0)
131 activesupport (>= 3.0.0)
132 cocaine (~> 0.5.3)
133 mime-types
134 pg (1.5.9) 140 pg (1.5.9)
135 power_assert (3.0.1) 141 power_assert (3.0.1)
142 racc (1.8.1)
136 rack (2.2.23) 143 rack (2.2.23)
137 rack-test (2.2.0) 144 rack-test (2.2.0)
138 rack (>= 1.3) 145 rack (>= 1.3)
139 rails (5.2.8.1) 146 rails (6.1.7.10)
140 actioncable (= 5.2.8.1) 147 actioncable (= 6.1.7.10)
141 actionmailer (= 5.2.8.1) 148 actionmailbox (= 6.1.7.10)
142 actionpack (= 5.2.8.1) 149 actionmailer (= 6.1.7.10)
143 actionview (= 5.2.8.1) 150 actionpack (= 6.1.7.10)
144 activejob (= 5.2.8.1) 151 actiontext (= 6.1.7.10)
145 activemodel (= 5.2.8.1) 152 actionview (= 6.1.7.10)
146 activerecord (= 5.2.8.1) 153 activejob (= 6.1.7.10)
147 activestorage (= 5.2.8.1) 154 activemodel (= 6.1.7.10)
148 activesupport (= 5.2.8.1) 155 activerecord (= 6.1.7.10)
149 bundler (>= 1.3.0) 156 activestorage (= 6.1.7.10)
150 railties (= 5.2.8.1) 157 activesupport (= 6.1.7.10)
158 bundler (>= 1.15.0)
159 railties (= 6.1.7.10)
151 sprockets-rails (>= 2.0.0) 160 sprockets-rails (>= 2.0.0)
152 rails-controller-testing (1.0.5) 161 rails-controller-testing (1.0.5)
153 actionpack (>= 5.0.1.rc1) 162 actionpack (>= 5.0.1.rc1)
@@ -157,51 +166,47 @@ GEM
157 activesupport (>= 5.0.0) 166 activesupport (>= 5.0.0)
158 minitest 167 minitest
159 nokogiri (>= 1.6) 168 nokogiri (>= 1.6)
160 rails-html-sanitizer (1.4.4) 169 rails-html-sanitizer (1.7.0)
161 loofah (~> 2.19, >= 2.19.1) 170 loofah (~> 2.25)
162 railties (5.2.8.1) 171 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)
163 actionpack (= 5.2.8.1) 172 railties (6.1.7.10)
164 activesupport (= 5.2.8.1) 173 actionpack (= 6.1.7.10)
174 activesupport (= 6.1.7.10)
165 method_source 175 method_source
166 rake (>= 0.8.7) 176 rake (>= 12.2)
167 thor (>= 0.19.0, < 2.0) 177 thor (~> 1.0)
168 rake (13.4.2) 178 rake (13.4.2)
169 rb-fsevent (0.11.2)
170 rb-inotify (0.11.1)
171 ffi (~> 1.0)
172 request_store (1.7.0) 179 request_store (1.7.0)
173 rack (>= 1.4) 180 rack (>= 1.4)
174 routing-filter (0.6.3) 181 routing-filter (0.7.0)
175 actionpack (>= 4.2) 182 actionpack (>= 6.1)
176 activesupport (>= 4.2) 183 activesupport (>= 6.1)
177 sass (3.7.4) 184 sass-rails (6.0.0)
178 sass-listen (~> 4.0.0) 185 sassc-rails (~> 2.1, >= 2.1.1)
179 sass-listen (4.0.0) 186 sassc (2.4.0)
180 rb-fsevent (~> 0.9, >= 0.9.4) 187 ffi (~> 1.9)
181 rb-inotify (~> 0.9, >= 0.9.7) 188 sassc-rails (2.1.2)
182 sass-rails (5.1.0) 189 railties (>= 4.0.0)
183 railties (>= 5.2.0) 190 sassc (>= 2.0)
184 sass (~> 3.1) 191 sprockets (> 3.0)
185 sprockets (>= 2.8, < 4.0) 192 sprockets-rails
186 sprockets-rails (>= 2.0, < 4.0) 193 tilt
187 tilt (>= 1.1, < 3) 194 sprockets (4.2.2)
188 sprockets (3.7.5)
189 base64
190 concurrent-ruby (~> 1.0) 195 concurrent-ruby (~> 1.0)
191 rack (> 1, < 3) 196 logger
192 sprockets-rails (3.4.2) 197 rack (>= 2.2.4, < 4)
193 actionpack (>= 5.2) 198 sprockets-rails (3.5.2)
194 activesupport (>= 5.2) 199 actionpack (>= 6.1)
200 activesupport (>= 6.1)
195 sprockets (>= 3.0.0) 201 sprockets (>= 3.0.0)
196 strscan (3.1.8) 202 strscan (3.1.8)
197 test-unit (3.7.8) 203 test-unit (3.7.8)
198 power_assert 204 power_assert
199 thor (1.2.2) 205 thor (1.2.2)
200 thread_safe (0.3.6)
201 tilt (2.7.0) 206 tilt (2.7.0)
202 timeout (0.4.0) 207 timeout (0.4.0)
203 tzinfo (1.2.11) 208 tzinfo (2.0.6)
204 thread_safe (~> 0.1) 209 concurrent-ruby (~> 1.0)
205 uglifier (4.2.1) 210 uglifier (4.2.1)
206 execjs (>= 0.3.0, < 3) 211 execjs (>= 0.3.0, < 3)
207 unicorn (1.1.7) 212 unicorn (1.1.7)
@@ -211,33 +216,32 @@ GEM
211 websocket-extensions (>= 0.1.0) 216 websocket-extensions (>= 0.1.0)
212 websocket-extensions (0.1.5) 217 websocket-extensions (0.1.5)
213 will_paginate (3.3.1) 218 will_paginate (3.3.1)
219 zeitwerk (2.6.18)
214 220
215PLATFORMS 221PLATFORMS
216 ruby 222 ruby
217 223
218DEPENDENCIES 224DEPENDENCIES
219 acts-as-taggable-on (~> 6.0) 225 acts-as-taggable-on (~> 7.0)
220 acts_as_list 226 acts_as_list
221 awesome_nested_set (~> 3.4.0) 227 awesome_nested_set (~> 3.4.0)
222 chaos_calendar! 228 chaos_calendar!
223 coffee-rails (~> 4.0) 229 coffee-rails (~> 4.0)
230 concurrent-ruby (= 1.3.4)
224 exception_notification (~> 4.5) 231 exception_notification (~> 4.5)
225 globalize (~> 5.2.0) 232 globalize (~> 6.0)
226 jquery-rails 233 jquery-rails
227 libxml-ruby (~> 3.2) 234 libxml-ruby (~> 3.2)
228 loofah (~> 2.20.0) 235 nokogiri (~> 1.13)
229 nokogiri (~> 1.10.10)
230 paperclip (~> 3.5)
231 pg (~> 1.0) 236 pg (~> 1.0)
232 rails (= 5.2.8.1) 237 rails (= 6.1.7.10)
233 rails-controller-testing 238 rails-controller-testing
234 rails-html-sanitizer (~> 1.4.4) 239 routing-filter (~> 0.7.0)
235 routing-filter (~> 0.6) 240 sass-rails (~> 6.0)
236 sass-rails (~> 5.0)
237 test-unit (~> 3.5) 241 test-unit (~> 3.5)
238 uglifier (>= 1.0.3) 242 uglifier (>= 1.0.3)
239 unicorn (~> 1.1) 243 unicorn (~> 1.1)
240 will_paginate (~> 3.0) 244 will_paginate (~> 3.0)
241 245
242BUNDLED WITH 246BUNDLED WITH
243 2.3.27 247 2.4.22
diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/assets/config/manifest.js
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
7 layout 'admin' 7 layout 'admin'
8 8
9 def index 9 def index
10 @assets = Asset.all.paginate( 10 @assets = Asset.order('id DESC').paginate(
11 :page => params[:page], 11 :page => params[:page],
12 :per_page => 20, 12 :per_page => 20
13 :order => 'id DESC'
14 ) 13 )
15 end 14 end
16 15
@@ -44,7 +43,7 @@ class AssetsController < ApplicationController
44 # POST /assets 43 # POST /assets
45 # POST /assets.xml 44 # POST /assets.xml
46 def create 45 def create
47 @asset = Asset.new(params[:asset]) 46 @asset = Asset.new(asset_params)
48 47
49 respond_to do |format| 48 respond_to do |format|
50 if @asset.save 49 if @asset.save
@@ -64,7 +63,7 @@ class AssetsController < ApplicationController
64 @asset = Asset.find(params[:id]) 63 @asset = Asset.find(params[:id])
65 64
66 respond_to do |format| 65 respond_to do |format|
67 if @asset.update_attributes(params[:asset]) 66 if @asset.update(asset_params)
68 flash[:notice] = 'Asset was successfully updated.' 67 flash[:notice] = 'Asset was successfully updated.'
69 format.html { redirect_to(@asset) } 68 format.html { redirect_to(@asset) }
70 format.xml { head :ok } 69 format.xml { head :ok }
@@ -86,4 +85,10 @@ class AssetsController < ApplicationController
86 format.xml { head :ok } 85 format.xml { head :ok }
87 end 86 end
88 end 87 end
88
89 private
90
91 def asset_params
92 params.require(:asset).permit(:name, :upload)
93 end
89end 94end
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
15 15
16 if @page and @page.public? 16 if @page and @page.public?
17 render( 17 render(
18 :file => @page.valid_template, 18 :template => @page.valid_template,
19 :layout => true 19 :layout => true
20 ) 20 )
21 else 21 else
22 render( 22 render(
23 :file => Rails.root.join('public', '404.html'), 23 :file => Rails.root.join('public', '404.html').to_s,
24 :status => 404 24 :status => 404,
25 :layout => false
25 ) 26 )
26 end 27 end
27 28
@@ -32,7 +33,7 @@ class ContentController < ApplicationController
32 @images = @page.assets.images 33 @images = @page.assets.images
33 render :file => "content/gallery" 34 render :file => "content/gallery"
34 else 35 else
35 render :nothing => true, :status => 404 36 head :not_found
36 end 37 end
37 end 38 end
38 39
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
47 # POST /events 47 # POST /events
48 # POST /events.xml 48 # POST /events.xml
49 def create 49 def create
50 @event = Event.new(params[:event]) 50 @event = Event.new(event_params)
51 51
52 respond_to do |format| 52 respond_to do |format|
53 if @event.save 53 if @event.save
@@ -67,7 +67,7 @@ class EventsController < ApplicationController
67 @event = Event.find(params[:id]) 67 @event = Event.find(params[:id])
68 68
69 respond_to do |format| 69 respond_to do |format|
70 if @event.update_attributes(params[:event]) 70 if @event.update(event_params)
71 flash[:notice] = 'Event was successfully updated.' 71 flash[:notice] = 'Event was successfully updated.'
72 format.html { redirect_to(edit_node_path(@event.node)) } 72 format.html { redirect_to(edit_node_path(@event.node)) }
73 format.xml { head :ok } 73 format.xml { head :ok }
@@ -89,4 +89,10 @@ class EventsController < ApplicationController
89 format.xml { head :ok } 89 format.xml { head :ok }
90 end 90 end
91 end 91 end
92
93 private
94
95 def event_params
96 params.require(:event).permit(:start_time, :end_time, :rrule, :custom_rrule, :allday, :url, :latitude, :longitude, :node_id, :location)
97 end
92end 98end
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
14 end 14 end
15 15
16 def new 16 def new
17 @menu_item = MenuItem.new params[:menu_item] 17 @menu_item = MenuItem.new menu_item_params
18 end 18 end
19 19
20 def create 20 def create
21 if MenuItem.create( params[:menu_item] ) 21 if MenuItem.create( menu_item_params )
22 redirect_to menu_items_path 22 redirect_to menu_items_path
23 else 23 else
24 render :new 24 render :new
@@ -32,7 +32,7 @@ class MenuItemsController < ApplicationController
32 def update 32 def update
33 @menu_item = MenuItem.find( params[:id] ) 33 @menu_item = MenuItem.find( params[:id] )
34 34
35 if @menu_item.update_attributes( params[:menu_item] ) 35 if @menu_item.update( menu_item_params )
36 redirect_to menu_items_path 36 redirect_to menu_items_path
37 else 37 else
38 render :edit 38 render :edit
@@ -48,10 +48,15 @@ class MenuItemsController < ApplicationController
48 def sort 48 def sort
49 params[:menu_items].each_with_index do |item_id, index| 49 params[:menu_items].each_with_index do |item_id, index|
50 menu_item = MenuItem.find(item_id) 50 menu_item = MenuItem.find(item_id)
51 menu_item.update_attributes(:position => index + 1) 51 menu_item.update(:position => index + 1)
52 end 52 end
53 53
54 render :nothing => true 54 head :ok
55 end 55 end
56 56
57 private
58
59 def menu_item_params
60 params.require(:menu_item).permit(:node_id, :path, :position, :type, :type_id)
61 end
57end 62end
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
36 @node.slug = params[:title].parameterize.to_s 36 @node.slug = params[:title].parameterize.to_s
37 37
38 if @node.save 38 if @node.save
39 @node.draft.update_attributes(:title => params[:title]) 39 @node.draft.update(:title => params[:title])
40 case params[:kind] 40 case params[:kind]
41 when "update" 41 when "update"
42 @node.draft.tag_list.add("update") 42 @node.draft.tag_list.add("update")
@@ -70,10 +70,10 @@ class NodesController < ApplicationController
70 end 70 end
71 71
72 def update 72 def update
73 @node.update_attributes(node_params) 73 @node.update(node_params)
74 @draft = @node.find_or_create_draft current_user 74 @draft = @node.find_or_create_draft current_user
75 @draft.tag_list = params[:tag_list] 75 @draft.tag_list = params[:tag_list]
76 if @draft.update_attributes( page_params ) 76 if @draft.update( page_params )
77 flash[:notice] = "Draft has been saved: #{Time.now}" 77 flash[:notice] = "Draft has been saved: #{Time.now}"
78 respond_to do |format| 78 respond_to do |format|
79 format.html { redirect_to edit_node_path(@node) } 79 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
45 # POST /occurrences 45 # POST /occurrences
46 # POST /occurrences.xml 46 # POST /occurrences.xml
47 def create 47 def create
48 @occurrence = Occurrence.new(params[:occurrence]) 48 @occurrence = Occurrence.new(occurrence_params)
49 49
50 respond_to do |format| 50 respond_to do |format|
51 if @occurrence.save 51 if @occurrence.save
@@ -65,7 +65,7 @@ class OccurrencesController < ApplicationController
65 @occurrence = Occurrence.find(params[:id]) 65 @occurrence = Occurrence.find(params[:id])
66 66
67 respond_to do |format| 67 respond_to do |format|
68 if @occurrence.update_attributes(params[:occurrence]) 68 if @occurrence.update(occurrence_params)
69 flash[:notice] = 'Occurrence was successfully updated.' 69 flash[:notice] = 'Occurrence was successfully updated.'
70 format.html { redirect_to(@occurrence) } 70 format.html { redirect_to(@occurrence) }
71 format.xml { head :ok } 71 format.xml { head :ok }
@@ -87,4 +87,11 @@ class OccurrencesController < ApplicationController
87 format.xml { head :ok } 87 format.xml { head :ok }
88 end 88 end
89 end 89 end
90
91 private
92
93 def occurrence_params
94 params.require(:occurrence).permit(:start_time, :end_time, :node_id, :event_id)
95 end
96
90end 97end
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
22 page = Page.find(params[:id]) 22 page = Page.find(params[:id])
23 page.update_assets(params[:images]) 23 page.update_assets(params[:images])
24 24
25 render :nothing => true, :status => 200 25 head :ok
26 end 26 end
27end 27end
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
36 permitted = user_params 36 permitted = user_params
37 permitted.delete(:admin) unless current_user.is_admin? 37 permitted.delete(:admin) unless current_user.is_admin?
38 38
39 if @user.update_attributes(permitted) 39 if @user.update(permitted)
40 flash[:notice] = "Updated user #{@user.login}" 40 flash[:notice] = "Updated user #{@user.login}"
41 redirect_to user_path(@user) 41 redirect_to user_path(@user)
42 else 42 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 @@
1module AdminHelper 1module AdminHelper
2 2
3 def language_selector 3 def language_selector
4 case I18n.locale 4 case I18n.locale
5 when :de 5 when :de
6 link_to raw('<span class="inactive">English</span>'), url_for(:overwrite_params => {:locale => :en}) 6 link_to raw('<span class="inactive">English</span>'), url_for(params.permit!.to_h.merge('locale' => 'en'))
7 when :en 7 when :en
8 link_to raw('<span class="inactive">Deutsch</span>'), url_for(:overwrite_params => {:locale => :de}) 8 link_to raw('<span class="inactive">Deutsch</span>'), url_for(params.permit!.to_h.merge('locale' => 'de'))
9 end 9 end
10 end 10 end
11end 11end
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
45 "Locked by #{@node.lock_owner.login}\n" + 45 "Locked by #{@node.lock_owner.login}\n" +
46 "Last modified #{@page.updated_at.to_s(:db)}" 46 "Last modified #{@page.updated_at.to_s(:db)}"
47 47
48 link_to( 48 link_to 'Unlock', safe_path(:unlock_node_path, @node), :method => :put, :data => { :confirm => message }
49 'Unlock', 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
60 def content_path(page_path = nil, options = {})
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
50 ) 69 )
51 end 70 end
52 71
53end 72end
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 @@
1class ApplicationRecord < ActiveRecord::Base
2 self.abstract_class = true
3end
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 @@
1class Asset < ActiveRecord::Base 1class Asset < ApplicationRecord
2
3 include FileAttachment
2 4
3 has_many :related_assets, :dependent => :destroy 5 has_many :related_assets, :dependent => :destroy
4 has_many :pages, :through => :related_assets 6 has_many :pages, :through => :related_assets
5 7
6 has_attached_file( 8 scope :images, -> { where(:upload_content_type => ["image/gif", "image/jpeg", "image/png", "image/webp"]) }
7 :upload,
8 :path => ":rails_root/public/system/:attachment/:id/:style/:filename",
9 :url => "/system/:attachment/:id/:style/:filename",
10 :styles => {
11 :medium => "300x300",
12 :thumb => "100x100",
13 :headline => "460x250#"
14 }
15 )
16
17 scope :images, -> { where(:upload_content_type => ["image/gif", "image/jpeg", "image/png"]) }
18 scope :documents, -> { where(:upload_content_type => ["application/pdf", "text/plain", "text/rtf"]) } 9 scope :documents, -> { where(:upload_content_type => ["application/pdf", "text/plain", "text/rtf"]) }
19 scope :audio, -> { where(:upload_content_type => ["audio/mpeg", "audio/x-m4a", "audio/wav", "audio/x-wav"]) } 10 scope :audio, -> { where(:upload_content_type => ["audio/mpeg", "audio/x-m4a", "audio/wav", "audio/x-wav"]) }
20 11
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 @@
1# FileAttachment — minimal drop-in replacement for Paperclip's has_attached_file.
2#
3# Provides the same interface used throughout this codebase:
4# asset.upload.url -> "/system/uploads/:id/original/:filename"
5# asset.upload.url(:thumb) -> "/system/uploads/:id/thumb/:filename"
6# asset.upload.content_type -> string
7# asset.upload.size -> integer (bytes)
8#
9# Files are stored at:
10# Rails.root/public/system/uploads/:id/:style/:filename
11#
12# Image variants are generated via ImageMagick (convert) on upload.
13# Non-image files get only an original, no variants.
14#
15# To replace an asset: assign a new file to asset.upload= and save.
16# The filename is fixed on first upload and preserved on replacement,
17# keeping all public URLs stable.
18#
19# Future: if more sophisticated asset management is needed (versioning,
20# S3, on-demand resizing), replace this module and keep the interface.
21
22module FileAttachment
23 extend ActiveSupport::Concern
24
25 STYLES = {
26 medium: { geometry: "300x300>", format: nil },
27 thumb: { geometry: "100x100>", format: nil },
28 headline: { geometry: "460x250!", format: nil }
29 }.freeze
30
31 IMAGE_CONTENT_TYPES = %w[image/jpeg image/gif image/png image/webp].freeze
32
33 included do
34 attr_reader :upload
35
36 after_initialize :build_upload_proxy
37 after_save :process_upload
38 before_destroy :delete_upload_files
39 end
40
41 def upload=(uploaded_file)
42 return if uploaded_file.blank?
43 @pending_upload = uploaded_file
44 # Populate the database columns immediately so validations can use them
45 self.upload_file_name = sanitize_filename(uploaded_file.original_filename)
46 self.upload_content_type = uploaded_file.content_type.to_s.split(';').first.strip
47 self.upload_file_size = uploaded_file.size
48 self.upload_updated_at = Time.current
49 build_upload_proxy
50 end
51
52 private
53
54 def build_upload_proxy
55 @upload = UploadProxy.new(self)
56 end
57
58 def process_upload
59 return unless @pending_upload
60 uploaded_file = @pending_upload
61 @pending_upload = nil
62
63 original_path = file_path(:original)
64 FileUtils.mkdir_p(File.dirname(original_path))
65 FileUtils.cp(uploaded_file.tempfile.path, original_path)
66
67 if IMAGE_CONTENT_TYPES.include?(upload_content_type)
68 generate_variants(original_path)
69 end
70 end
71
72 def generate_variants(original_path)
73 STYLES.each do |style, options|
74 dest_path = file_path(style)
75 FileUtils.mkdir_p(File.dirname(dest_path))
76 system("convert", original_path, "-resize", options[:geometry], dest_path)
77 end
78 end
79
80 def delete_upload_files
81 dir = Rails.root.join("public", "system", "uploads", id.to_s)
82 FileUtils.rm_rf(dir) if Dir.exist?(dir)
83 end
84
85 def file_path(style)
86 Rails.root.join(
87 "public", "system", "uploads",
88 id.to_s, style.to_s, upload_file_name
89 ).to_s
90 end
91
92 def sanitize_filename(filename)
93 File.basename(filename).gsub(/[^\w\.\-]/, '_')
94 end
95
96 # Proxy object returned by asset.upload, providing the Paperclip-compatible
97 # interface used in views: .url, .url(:style), .content_type, .size
98 class UploadProxy
99 def initialize(record)
100 @record = record
101 end
102
103 def url(style = :original)
104 return "" if @record.upload_file_name.blank?
105 "/system/uploads/#{@record.id}/#{style}/#{@record.upload_file_name}"
106 end
107
108 def content_type
109 @record.upload_content_type.to_s
110 end
111
112 def size
113 @record.upload_file_size.to_i
114 end
115
116 def present?
117 @record.upload_file_name.present?
118 end
119
120 def blank?
121 !present?
122 end
123 end
124end
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 @@
1class Event < ActiveRecord::Base 1class Event < ApplicationRecord
2 2
3 # Associations 3 # Associations
4 4
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 @@
1class MenuItem < ActiveRecord::Base 1class MenuItem < ApplicationRecord
2 2
3 default_scope -> { where(:type => "MenuItem") } 3 default_scope -> { where(:type => "MenuItem") }
4 4
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 @@
1class Node < ActiveRecord::Base 1class Node < ApplicationRecord
2 # Mixins and Plugins 2 # Mixins and Plugins
3 acts_as_nested_set 3 acts_as_nested_set
4 4
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 @@
1# TODO Make a gem out of the c wrapper 1# TODO Make a gem out of the c wrapper
2require 'chaos_calendar' 2require 'chaos_calendar'
3 3
4class Occurrence < ActiveRecord::Base 4class Occurrence < ApplicationRecord
5 5
6 # Associations 6 # Associations
7 7
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 @@
1require 'xml' 1require 'xml'
2 2
3class Page < ActiveRecord::Base 3class Page < ApplicationRecord
4 4
5 PUBLIC_TEMPLATE_PATH = File.join(%w(custom page_templates public)) 5 PUBLIC_TEMPLATE_PATH = File.join(%w(custom page_templates public))
6 FULL_PUBLIC_TEMPLATE_PATH = Rails.root.join('app', 'views', PUBLIC_TEMPLATE_PATH) 6 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 @@
1class Permission < ActiveRecord::Base 1class Permission < ApplicationRecord
2 # Validations 2 # Validations
3 validates_presence_of :user_id, :node_id, :granted 3 validates_presence_of :user_id, :node_id, :granted
4 validates_inclusion_of :granted, :in => [true, false] 4 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 @@
1class RelatedAsset < ActiveRecord::Base 1class RelatedAsset < ApplicationRecord
2 belongs_to :page 2 belongs_to :page
3 belongs_to :asset 3 belongs_to :asset
4 4
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 @@
1require 'digest/sha1' 1require 'digest/sha1'
2 2
3class User < ActiveRecord::Base 3class User < ApplicationRecord
4 # Mixins and Plugins 4 # Mixins and Plugins
5 include Authentication 5 include Authentication
6 include Authentication::ByPassword 6 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 @@
1<%= form_tag search_path, :method => 'get' do %> 1<%= form_tag safe_path(: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 169ae84..387f51c 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, tag_path(:id => tag.name) %></li> 6 <li><%= link_to tag.name, safe_path(: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 2a46f09..84dcdc6 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -16,8 +16,8 @@
16 <%= stylesheet_link_tag "shadowbox" %> 16 <%= stylesheet_link_tag "shadowbox" %>
17 <%= javascript_include_tag 'public' %> 17 <%= javascript_include_tag 'public' %>
18 18
19 <%= auto_discovery_link_tag(:atom, {:locale => :de, :controller => "rss", :action => "updates", :format => :xml}) %> 19 <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %>
20 <%= auto_discovery_link_tag(:rss, {:locale => :de, :controller => "rss", :action => "updates", :format => :rdf}) %> 20 <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %>
21 21
22 <script> 22 <script>
23 (function() { document.addEventListener("DOMContentLoaded", function() { 23 (function() { document.addEventListener("DOMContentLoaded", function() {
@@ -32,7 +32,6 @@
32 <div id="wrapper"> 32 <div id="wrapper">
33 <div id="header"> 33 <div id="header">
34 <%= image_tag("header.png") %> 34 <%= image_tag("header.png") %>
35 <!-- <%= link_to_path(image_tag("header.png"), "/home") %> -->
36 </div> 35 </div>
37 <div id="toolbox"> 36 <div id="toolbox">
38 <div id="search"> 37 <div id="search">
@@ -53,8 +52,8 @@
53 <div class="main_navigation"> 52 <div class="main_navigation">
54 <h2>Admin</h2> 53 <h2>Admin</h2>
55 <ul> 54 <ul>
56 <li><%= link_to raw('<span class="inactive admin_edit_link">⚙️ Overview</span>'),:controller => :admin, :action => 'index' %></li> 55 <li><%= link_to raw('<span class="inactive admin_edit_link">⚙️ Overview</span>'), safe_path(:admin_path) %></li>
57 <li><%= link_to raw('<span class="inactive admin_edit_link">✎ Edit</span>'), node_path(:id => @page.node) %></li> 56 <li><%= link_to raw('<span class="inactive admin_edit_link">✎ Edit</span>'), safe_path(:node_path, @page.node) %></li>
58 </ul> 57 </ul>
59 </div> 58 </div>
60 <% end %> 59 <% end %>
diff --git a/app/views/layouts/application.html.erb.bak b/app/views/layouts/application.html.erb.bak
deleted file mode 100644
index 3c95d75..0000000
--- a/app/views/layouts/application.html.erb.bak
+++ /dev/null
@@ -1,54 +0,0 @@
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
4<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5 <head>
6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
8 <title><%= page_title %></title>
9 <%= stylesheet_link_tag "ccc" %>
10 <%= javascript_include_tag 'jquery-1.3.2.min' %>
11 <%= javascript_include_tag 'shadowbox/shadowbox' %>
12 <%= stylesheet_link_tag "shadowbox" %>
13 <%= javascript_include_tag 'public' %>
14
15 <%= auto_discovery_link_tag(:atom, {:locale => :de, :controller => "rss", :action => "updates", :format => :xml}) %>
16 <%= auto_discovery_link_tag(:rss, {:locale => :de, :controller => "rss", :action => "updates", :format => :rdf}) %>
17 </head>
18
19 <body>
20 <div id="wrapper">
21 <div id="header">
22 <%= link_to_path(image_tag("header.png"), "/home") %>
23 </div>
24 <div id="search">
25 <%= render :partial => "content/search" %>
26 </div>
27 <div id="left_column">
28 <%= main_menu %>
29
30 <%= language_selector %>
31 <% if current_user && @page.node %>
32 <%= link_to "Edit", node_path(:id => @page.node) %>
33 <% end %>
34
35 <%= calendar %>
36 </div>
37 <div id="center_column">
38 <%= yield :layout %>
39
40 <div id="footer">
41 <br />
42 <br />
43 <p style="text-align: center">
44 <%= link_to t(:sponsors), content_path("sponsors") %>
45 </p>
46 </div>
47 </div>
48 <div id="right_column">
49 <%= tags %>
50 <%= featured_articles %>
51 </div>
52 </div>
53 </body>
54</html> \ No newline at end of file
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 3813cab..8e2e7ef 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -7,7 +7,6 @@ Cccms::Application.configure do
7 config.cache_classes = false 7 config.cache_classes = false
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 config.whiny_nils = true
11 10
12 # Show full error reports and disable caching 11 # Show full error reports and disable caching
13 config.action_controller.consider_all_requests_local = true 12 config.action_controller.consider_all_requests_local = true
@@ -17,6 +16,10 @@ Cccms::Application.configure do
17 config.action_mailer.raise_delivery_errors = false 16 config.action_mailer.raise_delivery_errors = false
18 17
19 config.active_support.deprecation = :log 18 config.active_support.deprecation = :log
20 config.serve_static_files = true 19 config.public_file_server.enabled = true
21 config.eager_load = false 20 config.eager_load = false
21
22 config.hosts.clear
23
24 config.middleware.delete ExceptionNotification::Rack
22end 25end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 6f2c5bd..82b918a 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -13,7 +13,7 @@ Cccms::Application.configure do
13 config.log_level = :info 13 config.log_level = :info
14 14
15 config.active_support.deprecation = :notify 15 config.active_support.deprecation = :notify
16 config.eager_load = false 16 config.eager_load = true
17 17
18 # Use a different logger for distributed setups 18 # Use a different logger for distributed setups
19 # config.logger = SyslogLogger.new 19 # config.logger = SyslogLogger.new
@@ -30,11 +30,11 @@ Cccms::Application.configure do
30 # Enable threaded mode 30 # Enable threaded mode
31 # config.threadsafe! 31 # config.threadsafe!
32 32
33 ActionMailer::Base.delivery_method = :sendmail 33 config.action_mailer.delivery_method = :sendmail
34 ActionMailer::Base.sendmail_settings = { 34 config.action_mailer.sendmail_settings = {
35 :location => '/usr/sbin/sendmail', 35 location: '/usr/sbin/sendmail',
36 :arguments => '-i -t' 36 arguments: '-i -t'
37 } 37 }
38 ActionMailer::Base.perform_deliveries = true 38 config.action_mailer.perform_deliveries = true
39 ActionMailer::Base.raise_delivery_errors = true 39 config.action_mailer.raise_delivery_errors = true
40end 40end
diff --git a/config/environments/test.rb b/config/environments/test.rb
index 858bebb..a23c6d4 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -2,9 +2,6 @@ Cccms::Application.configure do
2 2
3 config.cache_classes = true 3 config.cache_classes = true
4 4
5 # Log error messages when you accidentally call methods on nil.
6 # config.whiny_nils = true # removed in Rails 4
7
8 config.action_controller.consider_all_requests_local = true 5 config.action_controller.consider_all_requests_local = true
9 config.action_controller.perform_caching = false 6 config.action_controller.perform_caching = false
10 7
@@ -16,7 +13,7 @@ Cccms::Application.configure do
16 config.active_support.test_order = :sorted 13 config.active_support.test_order = :sorted
17 14
18 config.eager_load = false 15 config.eager_load = false
19 config.serve_static_files = true 16 config.public_file_server.enabled = true
20 config.static_cache_control = "public, max-age=3600" 17 config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
21 config.assets.compile = true 18 config.assets.compile = true
22end 19end
diff --git a/config/initializers/arel_patch.rb b/config/initializers/arel_patch.rb
deleted file mode 100644
index 753a72b..0000000
--- a/config/initializers/arel_patch.rb
+++ /dev/null
@@ -1,12 +0,0 @@
1require 'arel'
2module Arel
3 module Visitors
4 [ToSql, DepthFirst].each do |visitor|
5 visitor.class_eval do
6 def visit_Integer(o, collector = nil)
7 collector ? collector << o.to_s : o.to_s
8 end
9 end
10 end
11 end
12end
diff --git a/config/initializers/will_paginate_patch.rb b/config/initializers/will_paginate_patch.rb
new file mode 100644
index 0000000..d03c882
--- /dev/null
+++ b/config/initializers/will_paginate_patch.rb
@@ -0,0 +1,13 @@
1require 'will_paginate/view_helpers/action_view'
2
3WillPaginate::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
13end
diff --git a/config/routes.rb b/config/routes.rb
index 4a440c1..c3fd5c6 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -3,7 +3,6 @@ Cccms::Application.routes.draw do
3 3
4 root :to => 'content#render_page', :page_path => ['home'], :locale => 'de' 4 root :to => 'content#render_page', :page_path => ['home'], :locale => 'de'
5 5
6 resources :assets
7 resources :tags 6 resources :tags
8 resources :occurrences 7 resources :occurrences
9 resources :events 8 resources :events
@@ -31,6 +30,10 @@ Cccms::Application.routes.draw do
31 end 30 end
32 end 31 end
33 32
33 scope '/admin' do
34 resources :assets
35 end
36
34 match '/logout' => 'sessions#destroy', :as => :logout, :via => :delete 37 match '/logout' => 'sessions#destroy', :as => :logout, :via => :delete
35 match '/login' => 'sessions#new', :as => :login, :via => :get 38 match '/login' => 'sessions#new', :as => :login, :via => :get
36 match 'admin' => 'admin#index', :as => :admin, :via => :get 39 match 'admin' => 'admin#index', :as => :admin, :via => :get
@@ -47,8 +50,10 @@ Cccms::Application.routes.draw do
47 50
48 resource :session 51 resource :session
49 52
50 match 'rss/:action' => 'rss#index', :as => :rss, :via => [:get, :post] 53 get 'rss/updates', :to => 'rss#updates', :as => :rss
51 match 'rss/:action.:format' => 'rss#index', :via => [:get, :post] 54 get 'rss/updates.:format', :to => 'rss#updates', :as => :rss_feed,
55 :constraints => { :format => /xml|rdf/ }
56 get 'rss/recent_changes', :to => 'rss#recent_changes'
52 57
53 match 'galleries/*page_path' => 'content#render_gallery', :via => :get 58 match 'galleries/*page_path' => 'content#render_gallery', :via => :get
54 match '/*page_path' => 'content#render_page', :as => :content, :via => :get 59 match '/*page_path' => 'content#render_page', :as => :content, :via => :get
diff --git a/lib/chaos_importer.rb b/lib/chaos_importer.rb
index db2a96b..41dca30 100644
--- a/lib/chaos_importer.rb
+++ b/lib/chaos_importer.rb
@@ -148,7 +148,7 @@ class ChaosImporter
148 :body => extract_body(html) 148 :body => extract_body(html)
149 } 149 }
150 150
151 draft.update_attributes options 151 draft.update options
152 draft 152 draft
153 end 153 end
154 154
@@ -215,7 +215,7 @@ class ChaosImporter
215 unless tmp_event = node.event 215 unless tmp_event = node.event
216 tmp_event = Event.create! event_options.merge({:node_id => node.id}) 216 tmp_event = Event.create! event_options.merge({:node_id => node.id})
217 else 217 else
218 tmp_event.update_attributes event_options 218 tmp_event.update event_options
219 end 219 end
220 end 220 end
221 221
diff --git a/lib/update_importer.rb b/lib/update_importer.rb
index 103ac5a..2978c43 100644
--- a/lib/update_importer.rb
+++ b/lib/update_importer.rb
@@ -82,7 +82,7 @@ class UpdateImporter
82 I18n.locale = lang 82 I18n.locale = lang
83 83
84 unless node.head 84 unless node.head
85 page.update_attributes( 85 page.update(
86 :title => xhtml.elements['title'].get_text.to_s, 86 :title => xhtml.elements['title'].get_text.to_s,
87 :abstract => xhtml.elements['abstract'].get_text.to_s, 87 :abstract => xhtml.elements['abstract'].get_text.to_s,
88 :body => body 88 :body => body
@@ -176,7 +176,7 @@ class UpdateImporter
176 unless tmp_event = node.event 176 unless tmp_event = node.event
177 tmp_event = Event.create! event_options.merge({:node_id => node.id}) 177 tmp_event = Event.create! event_options.merge({:node_id => node.id})
178 else 178 else
179 tmp_event.update_attributes event_options 179 tmp_event.update event_options
180 end 180 end
181 end 181 end
182 end 182 end
diff --git a/test/controllers/assets_controller_test.rb b/test/controllers/assets_controller_test.rb
index d003d25..ea55c90 100644
--- a/test/controllers/assets_controller_test.rb
+++ b/test/controllers/assets_controller_test.rb
@@ -1,4 +1,174 @@
1require 'test_helper' 1require 'test_helper'
2 2
3class AssetsControllerTest < ActionController::TestCase 3class AssetsControllerTest < ActionController::TestCase
4
5 def setup
6 login_as :quentin
7 end
8
9 def teardown
10 # Clean up any files written to disk during tests
11 Dir.glob(Rails.root.join('public', 'system', 'uploads', 'test_*')).each do |dir|
12 FileUtils.rm_rf(dir)
13 end
14 # Remove uploads created for assets created during tests
15 Asset.where("upload_file_name IS NOT NULL").where("id > 1000000").each do |a|
16 FileUtils.rm_rf(Rails.root.join('public', 'system', 'uploads', a.id.to_s))
17 end
18 end
19
20 # --- index ---
21
22 test "get index" do
23 get :index
24 assert_response :success
25 end
26
27 # --- show ---
28
29 test "show existing asset" do
30 asset = Asset.create!(
31 name: 'Test asset',
32 upload_file_name: 'test_image.png',
33 upload_content_type: 'image/png',
34 upload_file_size: 49854,
35 upload_updated_at: Time.current
36 )
37 get :show, params: { id: asset.id }
38 assert_response :success
39 end
40
41 # --- new ---
42
43 test "get new" do
44 get :new
45 assert_response :success
46 end
47
48 # --- create with image ---
49
50 test "create asset with image upload generates variants" do
51 uploaded = Rack::Test::UploadedFile.new(
52 Rails.root.join('test', 'fixtures', 'files', 'test_image.png'),
53 'image/png'
54 )
55 assert_difference 'Asset.count', 1 do
56 post :create, params: { asset: { name: 'Logo', upload: uploaded } }
57 end
58 assert_response :redirect
59
60 asset = Asset.last
61 assert_equal 'test_image.png', asset.upload_file_name
62 assert_equal 'image/png', asset.upload_content_type
63 assert asset.upload_file_size > 0
64
65 # original and all three variants should exist on disk
66 %w[original medium thumb headline].each do |style|
67 path = Rails.root.join('public', 'system', 'uploads',
68 asset.id.to_s, style, 'test_image.png')
69 assert File.exist?(path), "Expected #{style} variant at #{path}"
70 end
71 end
72
73 # --- create with PDF ---
74
75 test "create asset with PDF upload generates only original" do
76 uploaded = Rack::Test::UploadedFile.new(
77 Rails.root.join('test', 'fixtures', 'files', 'test_document.pdf'),
78 'application/pdf'
79 )
80 assert_difference 'Asset.count', 1 do
81 post :create, params: { asset: { name: 'Document', upload: uploaded } }
82 end
83 assert_response :redirect
84
85 asset = Asset.last
86 assert_equal 'test_document.pdf', asset.upload_file_name
87 assert_equal 'application/pdf', asset.upload_content_type
88
89 # only original should exist, no image variants
90 original_path = Rails.root.join('public', 'system', 'uploads',
91 asset.id.to_s, 'original', 'test_document.pdf')
92 assert File.exist?(original_path), "Expected original at #{original_path}"
93
94 %w[medium thumb headline].each do |style|
95 path = Rails.root.join('public', 'system', 'uploads',
96 asset.id.to_s, style, 'test_document.pdf')
97 assert !File.exist?(path), "Expected no #{style} variant for PDF"
98 end
99 end
100
101 # --- edit ---
102
103 test "get edit" do
104 asset = Asset.create!(
105 name: 'Edit me',
106 upload_file_name: 'test_image.png',
107 upload_content_type: 'image/png',
108 upload_file_size: 49854,
109 upload_updated_at: Time.current
110 )
111 get :edit, params: { id: asset.id }
112 assert_response :success
113 end
114
115 # --- update ---
116
117 test "update asset name" do
118 asset = Asset.create!(
119 name: 'Old name',
120 upload_file_name: 'test_image.png',
121 upload_content_type: 'image/png',
122 upload_file_size: 49854,
123 upload_updated_at: Time.current
124 )
125 put :update, params: { id: asset.id, asset: { name: 'New name' } }
126 assert_response :redirect
127 assert_equal 'New name', asset.reload.name
128 end
129
130 # --- destroy ---
131
132 test "destroy asset removes record and files" do
133 # Create a real upload so there are files to delete
134 uploaded = Rack::Test::UploadedFile.new(
135 Rails.root.join('test', 'fixtures', 'files', 'test_image.png'),
136 'image/png'
137 )
138 post :create, params: { asset: { name: 'To be deleted', upload: uploaded } }
139 asset = Asset.last
140 upload_dir = Rails.root.join('public', 'system', 'uploads', asset.id.to_s)
141 assert Dir.exist?(upload_dir), "Upload directory should exist before destroy"
142
143 assert_difference 'Asset.count', -1 do
144 delete :destroy, params: { id: asset.id }
145 end
146 assert_response :redirect
147 assert !Dir.exist?(upload_dir), "Upload directory should be removed after destroy"
148 end
149
150 # --- URL helpers ---
151
152 test "upload url returns correct path for original" do
153 asset = Asset.create!(
154 name: 'URL test',
155 upload_file_name: 'logo.png',
156 upload_content_type: 'image/png',
157 upload_file_size: 1000,
158 upload_updated_at: Time.current
159 )
160 assert_equal "/system/uploads/#{asset.id}/original/logo.png", asset.upload.url
161 assert_equal "/system/uploads/#{asset.id}/thumb/logo.png", asset.upload.url(:thumb)
162 assert_equal "/system/uploads/#{asset.id}/medium/logo.png", asset.upload.url(:medium)
163 assert_equal "/system/uploads/#{asset.id}/headline/logo.png", asset.upload.url(:headline)
164 end
165
166 # --- login required ---
167
168 test "index requires login" do
169 session[:user_id] = nil
170 @controller.instance_variable_set(:@current_user, nil)
171 get :index
172 assert_response :redirect
173 end
4end 174end
diff --git a/test/controllers/revisions_controller_test.rb b/test/controllers/revisions_controller_test.rb
index 385e458..b4dcd8f 100644
--- a/test/controllers/revisions_controller_test.rb
+++ b/test/controllers/revisions_controller_test.rb
@@ -12,7 +12,7 @@ class RevisionsControllerTest < ActionController::TestCase
12 @node.publish_draft! 12 @node.publish_draft!
13 @node.find_or_create_draft @user 13 @node.find_or_create_draft @user
14 draft = @node.draft 14 draft = @node.draft
15 draft.update_attributes(:body => "second") 15 draft.update(:body => "second")
16 @node.publish_draft! 16 @node.publish_draft!
17 end 17 end
18 18
diff --git a/test/fixtures/files/test_document.pdf b/test/fixtures/files/test_document.pdf
new file mode 100644
index 0000000..f373820
--- /dev/null
+++ b/test/fixtures/files/test_document.pdf
Binary files differ
diff --git a/test/fixtures/files/test_image.png b/test/fixtures/files/test_image.png
new file mode 100644
index 0000000..08eaf96
--- /dev/null
+++ b/test/fixtures/files/test_image.png
Binary files differ
diff --git a/test/models/page_test.rb b/test/models/page_test.rb
index 8b34399..afba8b5 100644
--- a/test/models/page_test.rb
+++ b/test/models/page_test.rb
@@ -120,7 +120,7 @@ class PageTest < ActiveSupport::TestCase
120 120
121 english = page.translations.select {|x| x.locale == :en}.first 121 english = page.translations.select {|x| x.locale == :en}.first
122 Page::Translation.record_timestamps = false 122 Page::Translation.record_timestamps = false
123 english.update_attributes(:updated_at => (Time.now+25.hours)) 123 english.update(:updated_at => (Time.now+25.hours))
124 Page::Translation.record_timestamps = true 124 Page::Translation.record_timestamps = true
125 assert_equal 1, Page.find_with_outdated_translations.count 125 assert_equal 1, Page.find_with_outdated_translations.count
126 126
diff --git a/test/models/user_test.rb b/test/models/user_test.rb
index bd5d059..6e4d2d7 100644
--- a/test/models/user_test.rb
+++ b/test/models/user_test.rb
@@ -42,12 +42,12 @@ class UserTest < ActiveSupport::TestCase
42 end 42 end
43 43
44 def test_should_reset_password 44 def test_should_reset_password
45 users(:quentin).update_attributes(:password => 'new password', :password_confirmation => 'new password') 45 users(:quentin).update(:password => 'new password', :password_confirmation => 'new password')
46 assert_equal users(:quentin), User.authenticate('quentin', 'new password') 46 assert_equal users(:quentin), User.authenticate('quentin', 'new password')
47 end 47 end
48 48
49 def test_should_not_rehash_password 49 def test_should_not_rehash_password
50 users(:quentin).update_attributes(:login => 'quentin2') 50 users(:quentin).update(:login => 'quentin2')
51 assert_equal users(:quentin), User.authenticate('quentin2', 'monkey') 51 assert_equal users(:quentin), User.authenticate('quentin2', 'monkey')
52 end 52 end
53 53
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 2514926..e7b15da 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -17,73 +17,6 @@ module ActiveRecord
17 end 17 end
18end 18end
19 19
20class Integer
21 def days
22 ActiveSupport::Duration.new(self * 86400, [[:days, self]])
23 end
24 alias :day :days
25
26 def weeks
27 ActiveSupport::Duration.new(self * 7 * 86400, [[:days, self * 7]])
28 end
29 alias :week :weeks
30
31 def hours
32 ActiveSupport::Duration.new(self * 3600, [[:seconds, self * 3600]])
33 end
34 alias :hour :hours
35
36 def minutes
37 ActiveSupport::Duration.new(self * 60, [[:seconds, self * 60]])
38 end
39 alias :minute :minutes
40
41 def seconds
42 ActiveSupport::Duration.new(self, [[:seconds, self]])
43 end
44 alias :second :seconds
45
46 def months
47 ActiveSupport::Duration.new(self * 30 * 86400, [[:months, self]])
48 end
49 alias :month :months
50
51 def years
52 ActiveSupport::Duration.new((self * 365.25 * 86400).to_i, [[:years, self]])
53 end
54 alias :year :years
55end
56
57class Float
58 def days
59 ActiveSupport::Duration.new((self * 86400).to_i, [[:days, self]])
60 end
61 alias :day :days
62
63 def hours
64 ActiveSupport::Duration.new((self * 3600).to_i, [[:seconds, (self * 3600).to_i]])
65 end
66 alias :hour :hours
67
68 def minutes
69 ActiveSupport::Duration.new((self * 60).to_i, [[:seconds, (self * 60).to_i]])
70 end
71 alias :minute :minutes
72end
73
74require 'arel'
75module Arel
76 module Visitors
77 [ToSql, DepthFirst].each do |visitor|
78 visitor.class_eval do
79 def visit_Integer(o, collector = nil)
80 collector ? collector << o.to_s : o.to_s
81 end
82 end
83 end
84 end
85end
86
87class ActiveSupport::TestCase 20class ActiveSupport::TestCase
88 21
89 include AuthenticatedTestHelper 22 include AuthenticatedTestHelper