##// END OF EJS Templates
Fixed: Custom field is rendered, even if its value is empty (for multiple) (#18654)....
Jean-Philippe Lang -
r13482:a18c719fcc9c
parent child
Show More
@@ -1,148 +1,159
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2014 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 module CustomFieldsHelper
21 21
22 22 CUSTOM_FIELDS_TABS = [
23 23 {:name => 'IssueCustomField', :partial => 'custom_fields/index',
24 24 :label => :label_issue_plural},
25 25 {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index',
26 26 :label => :label_spent_time},
27 27 {:name => 'ProjectCustomField', :partial => 'custom_fields/index',
28 28 :label => :label_project_plural},
29 29 {:name => 'VersionCustomField', :partial => 'custom_fields/index',
30 30 :label => :label_version_plural},
31 31 {:name => 'UserCustomField', :partial => 'custom_fields/index',
32 32 :label => :label_user_plural},
33 33 {:name => 'GroupCustomField', :partial => 'custom_fields/index',
34 34 :label => :label_group_plural},
35 35 {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index',
36 36 :label => TimeEntryActivity::OptionName},
37 37 {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index',
38 38 :label => IssuePriority::OptionName},
39 39 {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index',
40 40 :label => DocumentCategory::OptionName}
41 41 ]
42 42
43 43 def render_custom_fields_tabs(types)
44 44 tabs = CUSTOM_FIELDS_TABS.select {|h| types.include?(h[:name]) }
45 45 render_tabs tabs
46 46 end
47 47
48 48 def custom_field_type_options
49 49 CUSTOM_FIELDS_TABS.map {|h| [l(h[:label]), h[:name]]}
50 50 end
51 51
52 52 def render_custom_field_format_partial(form, custom_field)
53 53 partial = custom_field.format.form_partial
54 54 if partial
55 55 render :partial => custom_field.format.form_partial, :locals => {:f => form, :custom_field => custom_field}
56 56 end
57 57 end
58 58
59 59 def custom_field_tag_name(prefix, custom_field)
60 60 name = "#{prefix}[custom_field_values][#{custom_field.id}]"
61 61 name << "[]" if custom_field.multiple?
62 62 name
63 63 end
64 64
65 65 def custom_field_tag_id(prefix, custom_field)
66 66 "#{prefix}_custom_field_values_#{custom_field.id}"
67 67 end
68 68
69 69 # Return custom field html tag corresponding to its format
70 70 def custom_field_tag(prefix, custom_value)
71 71 custom_value.custom_field.format.edit_tag self,
72 72 custom_field_tag_id(prefix, custom_value.custom_field),
73 73 custom_field_tag_name(prefix, custom_value.custom_field),
74 74 custom_value,
75 75 :class => "#{custom_value.custom_field.field_format}_cf"
76 76 end
77 77
78 78 # Return custom field label tag
79 79 def custom_field_label_tag(name, custom_value, options={})
80 80 required = options[:required] || custom_value.custom_field.is_required?
81 81 title = custom_value.custom_field.description.presence
82 82 content = content_tag 'span', custom_value.custom_field.name, :title => title
83 83
84 84 content_tag "label", content +
85 85 (required ? " <span class=\"required\">*</span>".html_safe : ""),
86 86 :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}"
87 87 end
88 88
89 89 # Return custom field tag with its label tag
90 90 def custom_field_tag_with_label(name, custom_value, options={})
91 91 custom_field_label_tag(name, custom_value, options) + custom_field_tag(name, custom_value)
92 92 end
93 93
94 94 # Returns the custom field tag for when bulk editing objects
95 95 def custom_field_tag_for_bulk_edit(prefix, custom_field, objects=nil, value='')
96 96 custom_field.format.bulk_edit_tag self,
97 97 custom_field_tag_id(prefix, custom_field),
98 98 custom_field_tag_name(prefix, custom_field),
99 99 custom_field,
100 100 objects,
101 101 value,
102 102 :class => "#{custom_field.field_format}_cf"
103 103 end
104 104
105 105 # Return a string used to display a custom value
106 106 def show_value(custom_value, html=true)
107 107 format_object(custom_value, html)
108 108 end
109 109
110 110 # Return a string used to display a custom value
111 111 def format_value(value, custom_field)
112 112 format_object(custom_field.format.formatted_value(self, custom_field, value, false), false)
113 113 end
114 114
115 115 # Return an array of custom field formats which can be used in select_tag
116 116 def custom_field_formats_for_select(custom_field)
117 117 Redmine::FieldFormat.as_select(custom_field.class.customized_class.name)
118 118 end
119 119
120 # Yields the given block for each custom field value of object that should be
121 # displayed, with the custom field and the formatted value as arguments
122 def render_custom_field_values(object, &block)
123 object.visible_custom_field_values.each do |custom_value|
124 formatted = show_value(custom_value)
125 if formatted.present?
126 yield custom_value.custom_field, formatted
127 end
128 end
129 end
130
120 131 # Renders the custom_values in api views
121 132 def render_api_custom_values(custom_values, api)
122 133 api.array :custom_fields do
123 134 custom_values.each do |custom_value|
124 135 attrs = {:id => custom_value.custom_field_id, :name => custom_value.custom_field.name}
125 136 attrs.merge!(:multiple => true) if custom_value.custom_field.multiple?
126 137 api.custom_field attrs do
127 138 if custom_value.value.is_a?(Array)
128 139 api.array :value do
129 140 custom_value.value.each do |value|
130 141 api.value value unless value.blank?
131 142 end
132 143 end
133 144 else
134 145 api.value custom_value.value
135 146 end
136 147 end
137 148 end
138 149 end unless custom_values.empty?
139 150 end
140 151
141 152 def edit_tag_style_tag(form, options={})
142 153 select_options = [[l(:label_drop_down_list), ''], [l(:label_checkboxes), 'check_box']]
143 154 if options[:include_radio]
144 155 select_options << [l(:label_radio_buttons), 'radio']
145 156 end
146 157 form.select :edit_tag_style, select_options, :label => :label_display
147 158 end
148 159 end
@@ -1,87 +1,85
1 1 <div class="contextual">
2 2 <% if User.current.allowed_to?(:add_subprojects, @project) %>
3 3 <%= link_to l(:label_subproject_new), new_project_path(:parent_id => @project), :class => 'icon icon-add' %>
4 4 <% end %>
5 5 <% if User.current.allowed_to?(:close_project, @project) %>
6 6 <% if @project.active? %>
7 7 <%= link_to l(:button_close), close_project_path(@project), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock' %>
8 8 <% else %>
9 9 <%= link_to l(:button_reopen), reopen_project_path(@project), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-unlock' %>
10 10 <% end %>
11 11 <% end %>
12 12 </div>
13 13
14 14 <h2><%=l(:label_overview)%></h2>
15 15
16 16 <% unless @project.active? %>
17 17 <p class="warning"><span class="icon icon-lock"><%= l(:text_project_closed) %></span></p>
18 18 <% end %>
19 19
20 20 <div class="splitcontentleft">
21 21 <% if @project.description.present? %>
22 22 <div class="wiki">
23 23 <%= textilizable @project.description %>
24 24 </div>
25 25 <% end %>
26 26 <ul>
27 27 <% unless @project.homepage.blank? %>
28 28 <li><span class="label"><%=l(:field_homepage)%>:</span> <%= link_to h(@project.homepage), @project.homepage %></li>
29 29 <% end %>
30 30 <% if @subprojects.any? %>
31 31 <li><span class="label"><%=l(:label_subproject_plural)%>:</span>
32 32 <%= @subprojects.collect{|p| link_to p, project_path(p)}.join(", ").html_safe %></li>
33 33 <% end %>
34 <% @project.visible_custom_field_values.each do |custom_value| %>
35 <% if !custom_value.value.blank? %>
36 <li><span class="label"><%=h custom_value.custom_field.name %>:</span> <%=h show_value(custom_value) %></li>
37 <% end %>
34 <% render_custom_field_values(@project) do |custom_field, formatted| %>
35 <li><span class="label"><%= custom_field.name %>:</span> <%= formatted %></li>
38 36 <% end %>
39 37 </ul>
40 38
41 39 <% if User.current.allowed_to?(:view_issues, @project) %>
42 40 <div class="issues box">
43 41 <h3><%=l(:label_issue_tracking)%></h3>
44 42 <ul>
45 43 <% for tracker in @trackers %>
46 44 <li><%= link_to h(tracker.name), project_issues_path(@project, :set_filter => 1, :tracker_id => tracker.id) %>:
47 45 <%= l(:label_x_open_issues_abbr_on_total, :count => @open_issues_by_tracker[tracker].to_i,
48 46 :total => @total_issues_by_tracker[tracker].to_i) %>
49 47 </li>
50 48 <% end %>
51 49 </ul>
52 50 <p>
53 51 <%= link_to l(:label_issue_view_all), project_issues_path(@project, :set_filter => 1) %>
54 52 <% if User.current.allowed_to?(:view_calendar, @project, :global => true) %>
55 53 | <%= link_to l(:label_calendar), project_calendar_path(@project) %>
56 54 <% end %>
57 55 <% if User.current.allowed_to?(:view_gantt, @project, :global => true) %>
58 56 | <%= link_to l(:label_gantt), project_gantt_path(@project) %>
59 57 <% end %>
60 58 </p>
61 59 </div>
62 60 <% end %>
63 61 <%= call_hook(:view_projects_show_left, :project => @project) %>
64 62 </div>
65 63
66 64 <div class="splitcontentright">
67 65 <%= render :partial => 'members_box' %>
68 66
69 67 <% if @news.any? && authorize_for('news', 'index') %>
70 68 <div class="news box">
71 69 <h3><%=l(:label_news_latest)%></h3>
72 70 <%= render :partial => 'news/news', :collection => @news %>
73 71 <p><%= link_to l(:label_news_view_all), project_news_index_path(@project) %></p>
74 72 </div>
75 73 <% end %>
76 74 <%= call_hook(:view_projects_show_right, :project => @project) %>
77 75 </div>
78 76
79 77 <% content_for :sidebar do %>
80 78 <%= render :partial => 'projects/sidebar' %>
81 79 <% end %>
82 80
83 81 <% content_for :header_tags do %>
84 82 <%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :key => User.current.rss_key}) %>
85 83 <% end %>
86 84
87 85 <% html_title(l(:label_overview)) -%>
@@ -1,35 +1,33
1 1 <% if version.completed? %>
2 2 <p><%= format_date(version.effective_date) %></p>
3 3 <% elsif version.effective_date %>
4 4 <p><strong><%= due_date_distance_in_words(version.effective_date) %></strong> (<%= format_date(version.effective_date) %>)</p>
5 5 <% end %>
6 6
7 7 <p><%=h version.description %></p>
8 8 <% if version.custom_field_values.any? %>
9 9 <ul>
10 <% version.custom_field_values.each do |custom_value| %>
11 <% if custom_value.value.present? %>
12 <li><%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %></li>
13 <% end %>
10 <% render_custom_field_values(version) do |custom_field, formatted| %>
11 <li><span class="label"><%= custom_field.name %>:</span> <%= formatted %></li>
14 12 <% end %>
15 13 </ul>
16 14 <% end %>
17 15
18 16 <% if version.issues_count > 0 %>
19 17 <%= progress_bar([version.closed_percent, version.completed_percent],
20 18 :width => '40em', :legend => ('%0.0f%' % version.completed_percent)) %>
21 19 <p class="progress-info">
22 20 <%= link_to(l(:label_x_issues, :count => version.issues_count),
23 21 version_filtered_issues_path(version, :status_id => '*')) %>
24 22 &nbsp;
25 23 (<%= link_to_if(version.closed_issues_count > 0,
26 24 l(:label_x_closed_issues_abbr, :count => version.closed_issues_count),
27 25 version_filtered_issues_path(version, :status_id => 'c')) %>
28 26 &#8212;
29 27 <%= link_to_if(version.open_issues_count > 0,
30 28 l(:label_x_open_issues_abbr, :count => version.open_issues_count),
31 29 version_filtered_issues_path(version, :status_id => 'o')) %>)
32 30 </p>
33 31 <% else %>
34 32 <p class="progress-info"><%= l(:label_roadmap_no_issues) %></p>
35 33 <% end %>
@@ -1,653 +1,665
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2014 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class ProjectsControllerTest < ActionController::TestCase
21 21 fixtures :projects, :versions, :users, :roles, :members,
22 22 :member_roles, :issues, :journals, :journal_details,
23 23 :trackers, :projects_trackers, :issue_statuses,
24 24 :enabled_modules, :enumerations, :boards, :messages,
25 25 :attachments, :custom_fields, :custom_values, :time_entries,
26 26 :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions
27 27
28 28 def setup
29 29 @request.session[:user_id] = nil
30 30 Setting.default_language = 'en'
31 31 end
32 32
33 33 def test_index_by_anonymous_should_not_show_private_projects
34 34 get :index
35 35 assert_response :success
36 36 assert_template 'index'
37 37 projects = assigns(:projects)
38 38 assert_not_nil projects
39 39 assert projects.all?(&:is_public?)
40 40
41 41 assert_select 'ul' do
42 42 assert_select 'li' do
43 43 assert_select 'a', :text => 'eCookbook'
44 44 assert_select 'ul' do
45 45 assert_select 'a', :text => 'Child of private child'
46 46 end
47 47 end
48 48 end
49 49 assert_select 'a', :text => /Private child of eCookbook/, :count => 0
50 50 end
51 51
52 52 def test_index_atom
53 53 get :index, :format => 'atom'
54 54 assert_response :success
55 55 assert_template 'common/feed'
56 56 assert_select 'feed>title', :text => 'Redmine: Latest projects'
57 57 assert_select 'feed>entry', :count => Project.visible(User.current).count
58 58 end
59 59
60 60 test "#index by non-admin user with view_time_entries permission should show overall spent time link" do
61 61 @request.session[:user_id] = 3
62 62 get :index
63 63 assert_template 'index'
64 64 assert_select 'a[href=?]', '/time_entries'
65 65 end
66 66
67 67 test "#index by non-admin user without view_time_entries permission should not show overall spent time link" do
68 68 Role.find(2).remove_permission! :view_time_entries
69 69 Role.non_member.remove_permission! :view_time_entries
70 70 Role.anonymous.remove_permission! :view_time_entries
71 71 @request.session[:user_id] = 3
72 72
73 73 get :index
74 74 assert_template 'index'
75 75 assert_select 'a[href=?]', '/time_entries', 0
76 76 end
77 77
78 78 test "#index by non-admin user with permission should show add project link" do
79 79 Role.find(1).add_permission! :add_project
80 80 @request.session[:user_id] = 2
81 81 get :index
82 82 assert_template 'index'
83 83 assert_select 'a[href=?]', '/projects/new'
84 84 end
85 85
86 86 test "#new by admin user should accept get" do
87 87 @request.session[:user_id] = 1
88 88
89 89 get :new
90 90 assert_response :success
91 91 assert_template 'new'
92 92 end
93 93
94 94 test "#new by non-admin user with add_project permission should accept get" do
95 95 Role.non_member.add_permission! :add_project
96 96 @request.session[:user_id] = 9
97 97
98 98 get :new
99 99 assert_response :success
100 100 assert_template 'new'
101 101 assert_select 'select[name=?]', 'project[parent_id]', 0
102 102 end
103 103
104 104 test "#new by non-admin user with add_subprojects permission should accept get" do
105 105 Role.find(1).remove_permission! :add_project
106 106 Role.find(1).add_permission! :add_subprojects
107 107 @request.session[:user_id] = 2
108 108
109 109 get :new, :parent_id => 'ecookbook'
110 110 assert_response :success
111 111 assert_template 'new'
112 112
113 113 assert_select 'select[name=?]', 'project[parent_id]' do
114 114 # parent project selected
115 115 assert_select 'option[value="1"][selected=selected]'
116 116 # no empty value
117 117 assert_select 'option[value=""]', 0
118 118 end
119 119 end
120 120
121 121 test "#create by admin user should create a new project" do
122 122 @request.session[:user_id] = 1
123 123
124 124 post :create,
125 125 :project => {
126 126 :name => "blog",
127 127 :description => "weblog",
128 128 :homepage => 'http://weblog',
129 129 :identifier => "blog",
130 130 :is_public => 1,
131 131 :custom_field_values => { '3' => 'Beta' },
132 132 :tracker_ids => ['1', '3'],
133 133 # an issue custom field that is not for all project
134 134 :issue_custom_field_ids => ['9'],
135 135 :enabled_module_names => ['issue_tracking', 'news', 'repository']
136 136 }
137 137 assert_redirected_to '/projects/blog/settings'
138 138
139 139 project = Project.find_by_name('blog')
140 140 assert_kind_of Project, project
141 141 assert project.active?
142 142 assert_equal 'weblog', project.description
143 143 assert_equal 'http://weblog', project.homepage
144 144 assert_equal true, project.is_public?
145 145 assert_nil project.parent
146 146 assert_equal 'Beta', project.custom_value_for(3).value
147 147 assert_equal [1, 3], project.trackers.map(&:id).sort
148 148 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
149 149 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
150 150 end
151 151
152 152 test "#create by admin user should create a new subproject" do
153 153 @request.session[:user_id] = 1
154 154
155 155 assert_difference 'Project.count' do
156 156 post :create, :project => { :name => "blog",
157 157 :description => "weblog",
158 158 :identifier => "blog",
159 159 :is_public => 1,
160 160 :custom_field_values => { '3' => 'Beta' },
161 161 :parent_id => 1
162 162 }
163 163 assert_redirected_to '/projects/blog/settings'
164 164 end
165 165
166 166 project = Project.find_by_name('blog')
167 167 assert_kind_of Project, project
168 168 assert_equal Project.find(1), project.parent
169 169 end
170 170
171 171 test "#create by admin user should continue" do
172 172 @request.session[:user_id] = 1
173 173
174 174 assert_difference 'Project.count' do
175 175 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
176 176 end
177 177 assert_redirected_to '/projects/new'
178 178 end
179 179
180 180 test "#create by non-admin user with add_project permission should create a new project" do
181 181 Role.non_member.add_permission! :add_project
182 182 @request.session[:user_id] = 9
183 183
184 184 post :create, :project => { :name => "blog",
185 185 :description => "weblog",
186 186 :identifier => "blog",
187 187 :is_public => 1,
188 188 :custom_field_values => { '3' => 'Beta' },
189 189 :tracker_ids => ['1', '3'],
190 190 :enabled_module_names => ['issue_tracking', 'news', 'repository']
191 191 }
192 192
193 193 assert_redirected_to '/projects/blog/settings'
194 194
195 195 project = Project.find_by_name('blog')
196 196 assert_kind_of Project, project
197 197 assert_equal 'weblog', project.description
198 198 assert_equal true, project.is_public?
199 199 assert_equal [1, 3], project.trackers.map(&:id).sort
200 200 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
201 201
202 202 # User should be added as a project member
203 203 assert User.find(9).member_of?(project)
204 204 assert_equal 1, project.members.size
205 205 end
206 206
207 207 test "#create by non-admin user with add_project permission should fail with parent_id" do
208 208 Role.non_member.add_permission! :add_project
209 209 @request.session[:user_id] = 9
210 210
211 211 assert_no_difference 'Project.count' do
212 212 post :create, :project => { :name => "blog",
213 213 :description => "weblog",
214 214 :identifier => "blog",
215 215 :is_public => 1,
216 216 :custom_field_values => { '3' => 'Beta' },
217 217 :parent_id => 1
218 218 }
219 219 end
220 220 assert_response :success
221 221 project = assigns(:project)
222 222 assert_kind_of Project, project
223 223 assert_not_equal [], project.errors[:parent_id]
224 224 end
225 225
226 226 test "#create by non-admin user with add_subprojects permission should create a project with a parent_id" do
227 227 Role.find(1).remove_permission! :add_project
228 228 Role.find(1).add_permission! :add_subprojects
229 229 @request.session[:user_id] = 2
230 230
231 231 post :create, :project => { :name => "blog",
232 232 :description => "weblog",
233 233 :identifier => "blog",
234 234 :is_public => 1,
235 235 :custom_field_values => { '3' => 'Beta' },
236 236 :parent_id => 1
237 237 }
238 238 assert_redirected_to '/projects/blog/settings'
239 239 project = Project.find_by_name('blog')
240 240 end
241 241
242 242 test "#create by non-admin user with add_subprojects permission should fail without parent_id" do
243 243 Role.find(1).remove_permission! :add_project
244 244 Role.find(1).add_permission! :add_subprojects
245 245 @request.session[:user_id] = 2
246 246
247 247 assert_no_difference 'Project.count' do
248 248 post :create, :project => { :name => "blog",
249 249 :description => "weblog",
250 250 :identifier => "blog",
251 251 :is_public => 1,
252 252 :custom_field_values => { '3' => 'Beta' }
253 253 }
254 254 end
255 255 assert_response :success
256 256 project = assigns(:project)
257 257 assert_kind_of Project, project
258 258 assert_not_equal [], project.errors[:parent_id]
259 259 end
260 260
261 261 test "#create by non-admin user with add_subprojects permission should fail with unauthorized parent_id" do
262 262 Role.find(1).remove_permission! :add_project
263 263 Role.find(1).add_permission! :add_subprojects
264 264 @request.session[:user_id] = 2
265 265
266 266 assert !User.find(2).member_of?(Project.find(6))
267 267 assert_no_difference 'Project.count' do
268 268 post :create, :project => { :name => "blog",
269 269 :description => "weblog",
270 270 :identifier => "blog",
271 271 :is_public => 1,
272 272 :custom_field_values => { '3' => 'Beta' },
273 273 :parent_id => 6
274 274 }
275 275 end
276 276 assert_response :success
277 277 project = assigns(:project)
278 278 assert_kind_of Project, project
279 279 assert_not_equal [], project.errors[:parent_id]
280 280 end
281 281
282 282 def test_create_subproject_with_inherit_members_should_inherit_members
283 283 Role.find_by_name('Manager').add_permission! :add_subprojects
284 284 parent = Project.find(1)
285 285 @request.session[:user_id] = 2
286 286
287 287 assert_difference 'Project.count' do
288 288 post :create, :project => {
289 289 :name => 'inherited', :identifier => 'inherited', :parent_id => parent.id, :inherit_members => '1'
290 290 }
291 291 assert_response 302
292 292 end
293 293
294 294 project = Project.order('id desc').first
295 295 assert_equal 'inherited', project.name
296 296 assert_equal parent, project.parent
297 297 assert project.memberships.count > 0
298 298 assert_equal parent.memberships.count, project.memberships.count
299 299 end
300 300
301 301 def test_create_should_preserve_modules_on_validation_failure
302 302 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
303 303 @request.session[:user_id] = 1
304 304 assert_no_difference 'Project.count' do
305 305 post :create, :project => {
306 306 :name => "blog",
307 307 :identifier => "",
308 308 :enabled_module_names => %w(issue_tracking news)
309 309 }
310 310 end
311 311 assert_response :success
312 312 project = assigns(:project)
313 313 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
314 314 end
315 315 end
316 316
317 317 def test_show_by_id
318 318 get :show, :id => 1
319 319 assert_response :success
320 320 assert_template 'show'
321 321 assert_not_nil assigns(:project)
322 322 end
323 323
324 324 def test_show_by_identifier
325 325 get :show, :id => 'ecookbook'
326 326 assert_response :success
327 327 assert_template 'show'
328 328 assert_not_nil assigns(:project)
329 329 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
330 330
331 331 assert_select 'li', :text => /Development status/
332 332 end
333 333
334 334 def test_show_should_not_display_empty_sidebar
335 335 p = Project.find(1)
336 336 p.enabled_module_names = []
337 337 p.save!
338 338
339 339 get :show, :id => 'ecookbook'
340 340 assert_response :success
341 341 assert_select '#main.nosidebar'
342 342 end
343 343
344 344 def test_show_should_not_display_hidden_custom_fields
345 345 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
346 346 get :show, :id => 'ecookbook'
347 347 assert_response :success
348 348 assert_template 'show'
349 349 assert_not_nil assigns(:project)
350 350
351 351 assert_select 'li', :text => /Development status/, :count => 0
352 352 end
353 353
354 def test_show_should_not_display_blank_custom_fields_with_multiple_values
355 f1 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Foo Bar), :multiple => true
356 f2 = ProjectCustomField.generate! :field_format => 'list', :possible_values => %w(Baz Qux), :multiple => true
357 project = Project.generate!(:custom_field_values => {f2.id.to_s => %w(Qux)})
358
359 get :show, :id => project.id
360 assert_response :success
361
362 assert_select 'li', :text => /#{f1.name}/, :count => 0
363 assert_select 'li', :text => /#{f2.name}/
364 end
365
354 366 def test_show_should_not_fail_when_custom_values_are_nil
355 367 project = Project.find_by_identifier('ecookbook')
356 368 project.custom_values.first.update_attribute(:value, nil)
357 369 get :show, :id => 'ecookbook'
358 370 assert_response :success
359 371 assert_template 'show'
360 372 assert_not_nil assigns(:project)
361 373 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
362 374 end
363 375
364 376 def show_archived_project_should_be_denied
365 377 project = Project.find_by_identifier('ecookbook')
366 378 project.archive!
367 379
368 380 get :show, :id => 'ecookbook'
369 381 assert_response 403
370 382 assert_nil assigns(:project)
371 383 assert_select 'p', :text => /archived/
372 384 end
373 385
374 386 def test_show_should_not_show_private_subprojects_that_are_not_visible
375 387 get :show, :id => 'ecookbook'
376 388 assert_response :success
377 389 assert_template 'show'
378 390 assert_select 'a', :text => /Private child/, :count => 0
379 391 end
380 392
381 393 def test_show_should_show_private_subprojects_that_are_visible
382 394 @request.session[:user_id] = 2 # manager who is a member of the private subproject
383 395 get :show, :id => 'ecookbook'
384 396 assert_response :success
385 397 assert_template 'show'
386 398 assert_select 'a', :text => /Private child/
387 399 end
388 400
389 401 def test_settings
390 402 @request.session[:user_id] = 2 # manager
391 403 get :settings, :id => 1
392 404 assert_response :success
393 405 assert_template 'settings'
394 406 end
395 407
396 408 def test_settings_of_subproject
397 409 @request.session[:user_id] = 2
398 410 get :settings, :id => 'private-child'
399 411 assert_response :success
400 412 assert_template 'settings'
401 413
402 414 assert_select 'input[type=checkbox][name=?]', 'project[inherit_members]'
403 415 end
404 416
405 417 def test_settings_should_be_denied_for_member_on_closed_project
406 418 Project.find(1).close
407 419 @request.session[:user_id] = 2 # manager
408 420
409 421 get :settings, :id => 1
410 422 assert_response 403
411 423 end
412 424
413 425 def test_settings_should_be_denied_for_anonymous_on_closed_project
414 426 Project.find(1).close
415 427
416 428 get :settings, :id => 1
417 429 assert_response 302
418 430 end
419 431
420 432 def test_setting_with_wiki_module_and_no_wiki
421 433 Project.find(1).wiki.destroy
422 434 Role.find(1).add_permission! :manage_wiki
423 435 @request.session[:user_id] = 2
424 436
425 437 get :settings, :id => 1
426 438 assert_response :success
427 439 assert_template 'settings'
428 440
429 441 assert_select 'form[action=?]', '/projects/ecookbook/wiki' do
430 442 assert_select 'input[name=?]', 'wiki[start_page]'
431 443 end
432 444 end
433 445
434 446 def test_update
435 447 @request.session[:user_id] = 2 # manager
436 448 post :update, :id => 1, :project => {:name => 'Test changed name',
437 449 :issue_custom_field_ids => ['']}
438 450 assert_redirected_to '/projects/ecookbook/settings'
439 451 project = Project.find(1)
440 452 assert_equal 'Test changed name', project.name
441 453 end
442 454
443 455 def test_update_with_failure
444 456 @request.session[:user_id] = 2 # manager
445 457 post :update, :id => 1, :project => {:name => ''}
446 458 assert_response :success
447 459 assert_template 'settings'
448 460 assert_select_error /name cannot be blank/i
449 461 end
450 462
451 463 def test_update_should_be_denied_for_member_on_closed_project
452 464 Project.find(1).close
453 465 @request.session[:user_id] = 2 # manager
454 466
455 467 post :update, :id => 1, :project => {:name => 'Closed'}
456 468 assert_response 403
457 469 assert_equal 'eCookbook', Project.find(1).name
458 470 end
459 471
460 472 def test_update_should_be_denied_for_anonymous_on_closed_project
461 473 Project.find(1).close
462 474
463 475 post :update, :id => 1, :project => {:name => 'Closed'}
464 476 assert_response 302
465 477 assert_equal 'eCookbook', Project.find(1).name
466 478 end
467 479
468 480 def test_modules
469 481 @request.session[:user_id] = 2
470 482 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
471 483
472 484 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
473 485 assert_redirected_to '/projects/ecookbook/settings/modules'
474 486 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
475 487 end
476 488
477 489 def test_destroy_leaf_project_without_confirmation_should_show_confirmation
478 490 @request.session[:user_id] = 1 # admin
479 491
480 492 assert_no_difference 'Project.count' do
481 493 delete :destroy, :id => 2
482 494 assert_response :success
483 495 assert_template 'destroy'
484 496 end
485 497 end
486 498
487 499 def test_destroy_without_confirmation_should_show_confirmation_with_subprojects
488 500 @request.session[:user_id] = 1 # admin
489 501
490 502 assert_no_difference 'Project.count' do
491 503 delete :destroy, :id => 1
492 504 assert_response :success
493 505 assert_template 'destroy'
494 506 end
495 507 assert_select 'strong',
496 508 :text => ['Private child of eCookbook',
497 509 'Child of private child, eCookbook Subproject 1',
498 510 'eCookbook Subproject 2'].join(', ')
499 511 end
500 512
501 513 def test_destroy_with_confirmation_should_destroy_the_project_and_subprojects
502 514 @request.session[:user_id] = 1 # admin
503 515
504 516 assert_difference 'Project.count', -5 do
505 517 delete :destroy, :id => 1, :confirm => 1
506 518 assert_redirected_to '/admin/projects'
507 519 end
508 520 assert_nil Project.find_by_id(1)
509 521 end
510 522
511 523 def test_archive
512 524 @request.session[:user_id] = 1 # admin
513 525 post :archive, :id => 1
514 526 assert_redirected_to '/admin/projects'
515 527 assert !Project.find(1).active?
516 528 end
517 529
518 530 def test_archive_with_failure
519 531 @request.session[:user_id] = 1
520 532 Project.any_instance.stubs(:archive).returns(false)
521 533 post :archive, :id => 1
522 534 assert_redirected_to '/admin/projects'
523 535 assert_match /project cannot be archived/i, flash[:error]
524 536 end
525 537
526 538 def test_unarchive
527 539 @request.session[:user_id] = 1 # admin
528 540 Project.find(1).archive
529 541 post :unarchive, :id => 1
530 542 assert_redirected_to '/admin/projects'
531 543 assert Project.find(1).active?
532 544 end
533 545
534 546 def test_close
535 547 @request.session[:user_id] = 2
536 548 post :close, :id => 1
537 549 assert_redirected_to '/projects/ecookbook'
538 550 assert_equal Project::STATUS_CLOSED, Project.find(1).status
539 551 end
540 552
541 553 def test_reopen
542 554 Project.find(1).close
543 555 @request.session[:user_id] = 2
544 556 post :reopen, :id => 1
545 557 assert_redirected_to '/projects/ecookbook'
546 558 assert Project.find(1).active?
547 559 end
548 560
549 561 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
550 562 CustomField.delete_all
551 563 parent = nil
552 564 6.times do |i|
553 565 p = Project.generate_with_parent!(parent)
554 566 get :show, :id => p
555 567 assert_select '#header h1' do
556 568 assert_select 'a', :count => [i, 3].min
557 569 end
558 570
559 571 parent = p
560 572 end
561 573 end
562 574
563 575 def test_get_copy
564 576 @request.session[:user_id] = 1 # admin
565 577 get :copy, :id => 1
566 578 assert_response :success
567 579 assert_template 'copy'
568 580 assert assigns(:project)
569 581 assert_equal Project.find(1).description, assigns(:project).description
570 582 assert_nil assigns(:project).id
571 583
572 584 assert_select 'input[name=?][value=?]', 'project[enabled_module_names][]', 'issue_tracking', 1
573 585 end
574 586
575 587 def test_get_copy_with_invalid_source_should_respond_with_404
576 588 @request.session[:user_id] = 1
577 589 get :copy, :id => 99
578 590 assert_response 404
579 591 end
580 592
581 593 def test_post_copy_should_copy_requested_items
582 594 @request.session[:user_id] = 1 # admin
583 595 CustomField.delete_all
584 596
585 597 assert_difference 'Project.count' do
586 598 post :copy, :id => 1,
587 599 :project => {
588 600 :name => 'Copy',
589 601 :identifier => 'unique-copy',
590 602 :tracker_ids => ['1', '2', '3', ''],
591 603 :enabled_module_names => %w(issue_tracking time_tracking)
592 604 },
593 605 :only => %w(issues versions)
594 606 end
595 607 project = Project.find('unique-copy')
596 608 source = Project.find(1)
597 609 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
598 610
599 611 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
600 612 assert_equal source.issues.count, project.issues.count, "All issues were not copied"
601 613 assert_equal 0, project.members.count
602 614 end
603 615
604 616 def test_post_copy_should_redirect_to_settings_when_successful
605 617 @request.session[:user_id] = 1 # admin
606 618 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
607 619 assert_response :redirect
608 620 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
609 621 end
610 622
611 623 def test_post_copy_with_failure
612 624 @request.session[:user_id] = 1
613 625 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => ''}
614 626 assert_response :success
615 627 assert_template 'copy'
616 628 end
617 629
618 630 def test_jump_should_redirect_to_active_tab
619 631 get :show, :id => 1, :jump => 'issues'
620 632 assert_redirected_to '/projects/ecookbook/issues'
621 633 end
622 634
623 635 def test_jump_should_not_redirect_to_inactive_tab
624 636 get :show, :id => 3, :jump => 'documents'
625 637 assert_response :success
626 638 assert_template 'show'
627 639 end
628 640
629 641 def test_jump_should_not_redirect_to_unknown_tab
630 642 get :show, :id => 3, :jump => 'foobar'
631 643 assert_response :success
632 644 assert_template 'show'
633 645 end
634 646
635 647 def test_body_should_have_project_css_class
636 648 get :show, :id => 1
637 649 assert_select 'body.project-ecookbook'
638 650 end
639 651
640 652 def test_project_menu_should_include_new_issue_link
641 653 @request.session[:user_id] = 2
642 654 get :show, :id => 1
643 655 assert_select '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]', :text => 'New issue'
644 656 end
645 657
646 658 def test_project_menu_should_not_include_new_issue_link_for_project_without_trackers
647 659 Project.find(1).trackers.clear
648 660
649 661 @request.session[:user_id] = 2
650 662 get :show, :id => 1
651 663 assert_select '#main-menu a.new-issue', 0
652 664 end
653 665 end
General Comments 0
You need to be logged in to leave comments. Login now