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