##// END OF EJS Templates
Fixed 500 error when displaying a news with comments in reverse order (#18332)....
Jean-Philippe Lang -
r13213:46756cbd5646
parent child
Show More
@@ -1,111 +1,111
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class NewsController < ApplicationController
18 class NewsController < ApplicationController
19 default_search_scope :news
19 default_search_scope :news
20 model_object News
20 model_object News
21 before_filter :find_model_object, :except => [:new, :create, :index]
21 before_filter :find_model_object, :except => [:new, :create, :index]
22 before_filter :find_project_from_association, :except => [:new, :create, :index]
22 before_filter :find_project_from_association, :except => [:new, :create, :index]
23 before_filter :find_project_by_project_id, :only => [:new, :create]
23 before_filter :find_project_by_project_id, :only => [:new, :create]
24 before_filter :authorize, :except => [:index]
24 before_filter :authorize, :except => [:index]
25 before_filter :find_optional_project, :only => :index
25 before_filter :find_optional_project, :only => :index
26 accept_rss_auth :index
26 accept_rss_auth :index
27 accept_api_auth :index
27 accept_api_auth :index
28
28
29 helper :watchers
29 helper :watchers
30 helper :attachments
30 helper :attachments
31
31
32 def index
32 def index
33 case params[:format]
33 case params[:format]
34 when 'xml', 'json'
34 when 'xml', 'json'
35 @offset, @limit = api_offset_and_limit
35 @offset, @limit = api_offset_and_limit
36 else
36 else
37 @limit = 10
37 @limit = 10
38 end
38 end
39
39
40 scope = @project ? @project.news.visible : News.visible
40 scope = @project ? @project.news.visible : News.visible
41
41
42 @news_count = scope.count
42 @news_count = scope.count
43 @news_pages = Paginator.new @news_count, @limit, params['page']
43 @news_pages = Paginator.new @news_count, @limit, params['page']
44 @offset ||= @news_pages.offset
44 @offset ||= @news_pages.offset
45 @newss = scope.includes([:author, :project]).
45 @newss = scope.includes([:author, :project]).
46 order("#{News.table_name}.created_on DESC").
46 order("#{News.table_name}.created_on DESC").
47 limit(@limit).
47 limit(@limit).
48 offset(@offset).
48 offset(@offset).
49 to_a
49 to_a
50 respond_to do |format|
50 respond_to do |format|
51 format.html {
51 format.html {
52 @news = News.new # for adding news inline
52 @news = News.new # for adding news inline
53 render :layout => false if request.xhr?
53 render :layout => false if request.xhr?
54 }
54 }
55 format.api
55 format.api
56 format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
56 format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
57 end
57 end
58 end
58 end
59
59
60 def show
60 def show
61 @comments = @news.comments
61 @comments = @news.comments.to_a
62 @comments.reverse! if User.current.wants_comments_in_reverse_order?
62 @comments.reverse! if User.current.wants_comments_in_reverse_order?
63 end
63 end
64
64
65 def new
65 def new
66 @news = News.new(:project => @project, :author => User.current)
66 @news = News.new(:project => @project, :author => User.current)
67 end
67 end
68
68
69 def create
69 def create
70 @news = News.new(:project => @project, :author => User.current)
70 @news = News.new(:project => @project, :author => User.current)
71 @news.safe_attributes = params[:news]
71 @news.safe_attributes = params[:news]
72 @news.save_attachments(params[:attachments])
72 @news.save_attachments(params[:attachments])
73 if @news.save
73 if @news.save
74 render_attachment_warning_if_needed(@news)
74 render_attachment_warning_if_needed(@news)
75 flash[:notice] = l(:notice_successful_create)
75 flash[:notice] = l(:notice_successful_create)
76 redirect_to project_news_index_path(@project)
76 redirect_to project_news_index_path(@project)
77 else
77 else
78 render :action => 'new'
78 render :action => 'new'
79 end
79 end
80 end
80 end
81
81
82 def edit
82 def edit
83 end
83 end
84
84
85 def update
85 def update
86 @news.safe_attributes = params[:news]
86 @news.safe_attributes = params[:news]
87 @news.save_attachments(params[:attachments])
87 @news.save_attachments(params[:attachments])
88 if @news.save
88 if @news.save
89 render_attachment_warning_if_needed(@news)
89 render_attachment_warning_if_needed(@news)
90 flash[:notice] = l(:notice_successful_update)
90 flash[:notice] = l(:notice_successful_update)
91 redirect_to news_path(@news)
91 redirect_to news_path(@news)
92 else
92 else
93 render :action => 'edit'
93 render :action => 'edit'
94 end
94 end
95 end
95 end
96
96
97 def destroy
97 def destroy
98 @news.destroy
98 @news.destroy
99 redirect_to project_news_index_path(@project)
99 redirect_to project_news_index_path(@project)
100 end
100 end
101
101
102 private
102 private
103
103
104 def find_optional_project
104 def find_optional_project
105 return true unless params[:project_id]
105 return true unless params[:project_id]
106 @project = Project.find(params[:project_id])
106 @project = Project.find(params[:project_id])
107 authorize
107 authorize
108 rescue ActiveRecord::RecordNotFound
108 rescue ActiveRecord::RecordNotFound
109 render_404
109 render_404
110 end
110 end
111 end
111 end
@@ -1,167 +1,178
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class NewsControllerTest < ActionController::TestCase
20 class NewsControllerTest < ActionController::TestCase
21 fixtures :projects, :users, :roles, :members, :member_roles,
21 fixtures :projects, :users, :roles, :members, :member_roles,
22 :enabled_modules, :news, :comments,
22 :enabled_modules, :news, :comments,
23 :attachments
23 :attachments
24
24
25 def setup
25 def setup
26 User.current = nil
26 User.current = nil
27 end
27 end
28
28
29 def test_index
29 def test_index
30 get :index
30 get :index
31 assert_response :success
31 assert_response :success
32 assert_template 'index'
32 assert_template 'index'
33 assert_not_nil assigns(:newss)
33 assert_not_nil assigns(:newss)
34 assert_nil assigns(:project)
34 assert_nil assigns(:project)
35 end
35 end
36
36
37 def test_index_with_project
37 def test_index_with_project
38 get :index, :project_id => 1
38 get :index, :project_id => 1
39 assert_response :success
39 assert_response :success
40 assert_template 'index'
40 assert_template 'index'
41 assert_not_nil assigns(:newss)
41 assert_not_nil assigns(:newss)
42 end
42 end
43
43
44 def test_index_with_invalid_project_should_respond_with_404
44 def test_index_with_invalid_project_should_respond_with_404
45 get :index, :project_id => 999
45 get :index, :project_id => 999
46 assert_response 404
46 assert_response 404
47 end
47 end
48
48
49 def test_show
49 def test_show
50 get :show, :id => 1
50 get :show, :id => 1
51 assert_response :success
51 assert_response :success
52 assert_template 'show'
52 assert_template 'show'
53 assert_tag :tag => 'h2', :content => /eCookbook first release/
53 assert_tag :tag => 'h2', :content => /eCookbook first release/
54 end
54 end
55
55
56 def test_show_should_show_attachments
56 def test_show_should_show_attachments
57 attachment = Attachment.first
57 attachment = Attachment.first
58 attachment.container = News.find(1)
58 attachment.container = News.find(1)
59 attachment.save!
59 attachment.save!
60
60
61 get :show, :id => 1
61 get :show, :id => 1
62 assert_response :success
62 assert_response :success
63 assert_tag 'a', :content => attachment.filename
63 assert_tag 'a', :content => attachment.filename
64 end
64 end
65
65
66 def test_show_with_comments_in_reverse_order
67 user = User.find(1)
68 user.pref[:comments_sorting] = 'desc'
69 user.pref.save!
70
71 @request.session[:user_id] = 1
72 get :show, :id => 1
73 assert_response :success
74 assert_equal News.find(1).comments.to_a.sort_by(&:created_on).reverse, assigns(:comments)
75 end
76
66 def test_show_not_found
77 def test_show_not_found
67 get :show, :id => 999
78 get :show, :id => 999
68 assert_response 404
79 assert_response 404
69 end
80 end
70
81
71 def test_get_new
82 def test_get_new
72 @request.session[:user_id] = 2
83 @request.session[:user_id] = 2
73 get :new, :project_id => 1
84 get :new, :project_id => 1
74 assert_response :success
85 assert_response :success
75 assert_template 'new'
86 assert_template 'new'
76 end
87 end
77
88
78 def test_post_create
89 def test_post_create
79 ActionMailer::Base.deliveries.clear
90 ActionMailer::Base.deliveries.clear
80 @request.session[:user_id] = 2
91 @request.session[:user_id] = 2
81
92
82 with_settings :notified_events => %w(news_added) do
93 with_settings :notified_events => %w(news_added) do
83 post :create, :project_id => 1, :news => { :title => 'NewsControllerTest',
94 post :create, :project_id => 1, :news => { :title => 'NewsControllerTest',
84 :description => 'This is the description',
95 :description => 'This is the description',
85 :summary => '' }
96 :summary => '' }
86 end
97 end
87 assert_redirected_to '/projects/ecookbook/news'
98 assert_redirected_to '/projects/ecookbook/news'
88
99
89 news = News.find_by_title('NewsControllerTest')
100 news = News.find_by_title('NewsControllerTest')
90 assert_not_nil news
101 assert_not_nil news
91 assert_equal 'This is the description', news.description
102 assert_equal 'This is the description', news.description
92 assert_equal User.find(2), news.author
103 assert_equal User.find(2), news.author
93 assert_equal Project.find(1), news.project
104 assert_equal Project.find(1), news.project
94 assert_equal 1, ActionMailer::Base.deliveries.size
105 assert_equal 1, ActionMailer::Base.deliveries.size
95 end
106 end
96
107
97 def test_post_create_with_attachment
108 def test_post_create_with_attachment
98 set_tmp_attachments_directory
109 set_tmp_attachments_directory
99 @request.session[:user_id] = 2
110 @request.session[:user_id] = 2
100 assert_difference 'News.count' do
111 assert_difference 'News.count' do
101 assert_difference 'Attachment.count' do
112 assert_difference 'Attachment.count' do
102 post :create, :project_id => 1,
113 post :create, :project_id => 1,
103 :news => { :title => 'Test', :description => 'This is the description' },
114 :news => { :title => 'Test', :description => 'This is the description' },
104 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
115 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
105 end
116 end
106 end
117 end
107 attachment = Attachment.order('id DESC').first
118 attachment = Attachment.order('id DESC').first
108 news = News.order('id DESC').first
119 news = News.order('id DESC').first
109 assert_equal news, attachment.container
120 assert_equal news, attachment.container
110 end
121 end
111
122
112 def test_post_create_with_validation_failure
123 def test_post_create_with_validation_failure
113 @request.session[:user_id] = 2
124 @request.session[:user_id] = 2
114 post :create, :project_id => 1, :news => { :title => '',
125 post :create, :project_id => 1, :news => { :title => '',
115 :description => 'This is the description',
126 :description => 'This is the description',
116 :summary => '' }
127 :summary => '' }
117 assert_response :success
128 assert_response :success
118 assert_template 'new'
129 assert_template 'new'
119 assert_not_nil assigns(:news)
130 assert_not_nil assigns(:news)
120 assert assigns(:news).new_record?
131 assert assigns(:news).new_record?
121 assert_error_tag :content => /title #{ESCAPED_CANT} be blank/i
132 assert_error_tag :content => /title #{ESCAPED_CANT} be blank/i
122 end
133 end
123
134
124 def test_get_edit
135 def test_get_edit
125 @request.session[:user_id] = 2
136 @request.session[:user_id] = 2
126 get :edit, :id => 1
137 get :edit, :id => 1
127 assert_response :success
138 assert_response :success
128 assert_template 'edit'
139 assert_template 'edit'
129 end
140 end
130
141
131 def test_put_update
142 def test_put_update
132 @request.session[:user_id] = 2
143 @request.session[:user_id] = 2
133 put :update, :id => 1, :news => { :description => 'Description changed by test_post_edit' }
144 put :update, :id => 1, :news => { :description => 'Description changed by test_post_edit' }
134 assert_redirected_to '/news/1'
145 assert_redirected_to '/news/1'
135 news = News.find(1)
146 news = News.find(1)
136 assert_equal 'Description changed by test_post_edit', news.description
147 assert_equal 'Description changed by test_post_edit', news.description
137 end
148 end
138
149
139 def test_put_update_with_attachment
150 def test_put_update_with_attachment
140 set_tmp_attachments_directory
151 set_tmp_attachments_directory
141 @request.session[:user_id] = 2
152 @request.session[:user_id] = 2
142 assert_no_difference 'News.count' do
153 assert_no_difference 'News.count' do
143 assert_difference 'Attachment.count' do
154 assert_difference 'Attachment.count' do
144 put :update, :id => 1,
155 put :update, :id => 1,
145 :news => { :description => 'This is the description' },
156 :news => { :description => 'This is the description' },
146 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
157 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
147 end
158 end
148 end
159 end
149 attachment = Attachment.order('id DESC').first
160 attachment = Attachment.order('id DESC').first
150 assert_equal News.find(1), attachment.container
161 assert_equal News.find(1), attachment.container
151 end
162 end
152
163
153 def test_update_with_failure
164 def test_update_with_failure
154 @request.session[:user_id] = 2
165 @request.session[:user_id] = 2
155 put :update, :id => 1, :news => { :description => '' }
166 put :update, :id => 1, :news => { :description => '' }
156 assert_response :success
167 assert_response :success
157 assert_template 'edit'
168 assert_template 'edit'
158 assert_error_tag :content => /description #{ESCAPED_CANT} be blank/i
169 assert_error_tag :content => /description #{ESCAPED_CANT} be blank/i
159 end
170 end
160
171
161 def test_destroy
172 def test_destroy
162 @request.session[:user_id] = 2
173 @request.session[:user_id] = 2
163 delete :destroy, :id => 1
174 delete :destroy, :id => 1
164 assert_redirected_to '/projects/ecookbook/news'
175 assert_redirected_to '/projects/ecookbook/news'
165 assert_nil News.find_by_id(1)
176 assert_nil News.find_by_id(1)
166 end
177 end
167 end
178 end
General Comments 0
You need to be logged in to leave comments. Login now