Project

General

Profile

Feature #465 » 0001-Added-Version-sharing.-465.patch

Latest patch based on r3119 - Eric Davis, 2009-12-03 22:43

View differences:

app/controllers/issues_controller.rb
239 239
      priority = params[:priority_id].blank? ? nil : IssuePriority.find_by_id(params[:priority_id])
240 240
      assigned_to = (params[:assigned_to_id].blank? || params[:assigned_to_id] == 'none') ? nil : User.find_by_id(params[:assigned_to_id])
241 241
      category = (params[:category_id].blank? || params[:category_id] == 'none') ? nil : @project.issue_categories.find_by_id(params[:category_id])
242
      fixed_version = (params[:fixed_version_id].blank? || params[:fixed_version_id] == 'none') ? nil : @project.versions.find_by_id(params[:fixed_version_id])
242
      fixed_version = (params[:fixed_version_id].blank? || params[:fixed_version_id] == 'none') ? nil : @project.shared_versions.find {|v| v.id.to_s == params[:fixed_version_id] }
243 243
      custom_field_values = params[:custom_field_values] ? params[:custom_field_values].reject {|k,v| v.blank?} : nil
244 244
      
245 245
      unsaved_issue_ids = []      
app/controllers/projects_controller.rb
271 271
                'downloads' => "#{Attachment.table_name}.downloads"
272 272
                
273 273
    @containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)]
274
    @containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
274
    # Need get the ids separately in order to add the finder options
275
    version_ids = @project.shared_versions_visible_to_user.collect(&:id)
276
    @containers += Version.find_all_by_id(version_ids, :include => :attachments, :order => sort_clause).sort.reverse
275 277
    render :layout => !request.xhr?
276 278
  end
277 279
  
......
279 281
  def changelog
280 282
    @trackers = @project.trackers.find(:all, :conditions => ["is_in_chlog=?", true], :order => 'position')
281 283
    retrieve_selected_tracker_ids(@trackers)    
282
    @versions = @project.versions.sort
284
    if params[:shared_versions]
285
      @versions = @project.shared_versions_visible_to_user.sort
286
    else
287
      @versions = @project.versions.sort
288
    end
283 289
  end
284 290

  
285 291
  def roadmap
286 292
    @trackers = @project.trackers.find(:all, :conditions => ["is_in_roadmap=?", true])
287 293
    retrieve_selected_tracker_ids(@trackers)
288
    @versions = @project.versions.sort
294
    if params[:shared_versions]
295
      @versions = @project.shared_versions_visible_to_user.sort
296
    else
297
      @versions = @project.versions.sort
298
    end
289 299
    @versions = @versions.select {|v| !v.completed? } unless params[:completed]
290 300
  end
291 301
  
app/helpers/application_helper.rb
126 126
    h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "<br />")
127 127
  end
128 128

  
129
  def format_version_name(version)
130
    if User.current.allowed_to?(:view_issues, version.project) || version.systemwide?
131
      "#{h(version.project.name)} - #{h(version.name)}"
132
    else
133
      "#{l(:text_not_authorized)}"
134
    end
135
  end
136

  
137
  def format_version_sharing_name(version)
138
    if version.shared && Version::SharedValues.key?(version.shared)
139
      l(Version::SharedValues[version.shared])
140
    else
141
      l(:label_version_shared_none)
142
    end
143
  end
144

  
145
  # Given an Array of emails (+recipients+), do they all have
146
  # +permission+ on +project+ ?
147
  def recipients_all_allowed_to?(recipients, permission, project)
148
    recipients.uniq.all? do |recipient|
149
      user = User.find_by_mail(recipient)
150
      user && user.allowed_to?(permission, project)
151
    end
152
  end
153

  
154
  # Given an Array of +versions+, are all the email addresses
155
  # (+recipients+) allowed to view all of the versions?
156
  def recipients_all_allowed_to_see_versions?(recipients, versions)
157
    versions.uniq.all? do |version|
158
      if version.nil?
159
        true
160
      else
161
        recipients_all_allowed_to?(recipients, :view_issues, version.project)
162
      end
163
    end
164
  end
165
  
129 166
  def due_date_distance_in_words(date)
130 167
    if date
131 168
      l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
app/helpers/issues_helper.rb
64 64
    @sidebar_queries
65 65
  end
66 66

  
67
  # Returns a set of options for a select field, grouped by project.
68
  def shared_version_options(project, selected=nil)
69
    grouped = {}
70
    project.shared_versions.each do |version|
71
      next unless version.open?
72
      
73
      if User.current.allowed_to?(:view_issues, version.project) || version.systemwide?
74
        grouped[version.project.name] ||= []
75
        grouped[version.project.name] << [h(version.name), version.id]
76
      else
77
        grouped[l(:text_not_authorized)] ||=[]
78
        grouped[l(:text_not_authorized)] << [l(:text_not_authorized), version.id]
79
      end
80
    end
81

  
82
    # Add in the selected
83
    selected_version = Version.find_by_id(selected)
84
    if selected_version && !project.shared_versions.include?(selected_version)
85
      if User.current.allowed_to?(:view_issues, selected_version.project) || selected_version.systemwide?
86
        grouped[selected_version.project.name] ||= []
87
        grouped[selected_version.project.name] << [h(selected_version.name), selected_version.id]
88
      else
89
        grouped[l(:text_not_authorized)] ||=[]
90
        grouped[l(:text_not_authorized)] << [l(:text_not_authorized), selected_version.id]
91
      end
92
    end
93
    
94
    grouped_options_for_select(grouped, selected)
95
  end
96

  
67 97
  def show_detail(detail, no_html=false)
68 98
    case detail.property
69 99
    when 'attr'
......
91 121
        c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value
92 122
        c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
93 123
      when 'fixed_version_id'
94
        v = Version.find_by_id(detail.value) and value = v.name if detail.value
95
        v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value
124
        v = Version.find_by_id(detail.value) and value = format_version_name(v) if detail.value
125
        v = Version.find_by_id(detail.old_value) and old_value = format_version_name(v) if detail.old_value
96 126
      when 'estimated_hours'
97 127
        value = "%0.02f" % detail.value.to_f unless detail.value.blank?
98 128
        old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
app/helpers/mailer_helper.rb
1
# redMine - project management software
2
# Copyright (C) 2006-2009  Jean-Philippe Lang
3
#
4
# This program is free software; you can redistribute it and/or
5
# modify it under the terms of the GNU General Public License
6
# as published by the Free Software Foundation; either version 2
7
# of the License, or (at your option) any later version.
8
# 
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
# 
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
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17

  
18
module MailerHelper
19
  def unauthorized_version?(journal_detail, recipients)
20
    return false unless journal_detail.prop_key == "fixed_version_id"
21

  
22
    !recipients_all_allowed_to_see_versions?(recipients,
23
                                             Version.find_all_by_id([journal_detail.value, journal_detail.old_value]))
24
  end
25
end
app/helpers/projects_helper.rb
18 18
module ProjectsHelper
19 19
  def link_to_version(version, options = {})
20 20
    return '' unless version && version.is_a?(Version)
21
    link_to h(version.name), { :controller => 'versions', :action => 'show', :id => version }, options
21
    if User.current.allowed_to?(:view_issues, version.project)
22
      link_to format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options
23
    else
24
      format_version_name(version)
25
    end
22 26
  end
23 27
  
24 28
  def project_settings_tabs
app/models/issue.rb
100 100
        # reassign to the category with same name if any
101 101
        new_category = issue.category.nil? ? nil : new_project.issue_categories.find_by_name(issue.category.name)
102 102
        issue.category = new_category
103
        issue.fixed_version = nil
103
        # Keep the fixed_version if it's still valid in the new_project
104
        unless new_project.shared_versions.include?(issue.fixed_version)
105
          issue.fixed_version = nil
106
        end
104 107
        issue.project = new_project
105 108
      end
106 109
      if new_tracker
......
234 237
  
235 238
  # Versions that the issue can be assigned to
236 239
  def assignable_versions
237
    @assignable_versions ||= (project.versions.open + [Version.find_by_id(fixed_version_id_was)]).compact.uniq.sort
240
    @assignable_versions ||= (project.shared_versions_visible_to_user(User.current).select {|v| v.open?} +
241
                              [Version.find_by_id(fixed_version_id_was)]).
242
      compact.uniq.sort 
238 243
  end
239 244
  
240 245
  # Returns true if this issue is blocked by another issue that is still open
......
318 323
    s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id
319 324
    s
320 325
  end
326

  
327
  # Update all issues so their versions are not pointing to a
328
  # fixed_version that is outside of the issue's project hierarchy.
329
  #
330
  # OPTIMIZE: does a full table scan of Issues with a fixed_version.
331
  def self.update_fixed_versions_from_project_hierarchy_change
332
    Issue.all(:conditions => ['fixed_version_id IS NOT NULL'],
333
              :include => [:project, :fixed_version]
334
              ).each do |issue|
335
      next if issue.project.nil? || issue.fixed_version.nil?
336
      unless issue.project.shared_versions.include?(issue.fixed_version)
337
        issue.init_journal(User.current)
338
        issue.fixed_version = nil
339
        issue.save
340
      end
341
    end
342
  end
321 343
  
322 344
  private
323 345
  
app/models/mailer.rb
20 20
  helper :application
21 21
  helper :issues
22 22
  helper :custom_fields
23
  helper :mailer
23 24

  
24 25
  include ActionController::UrlWriter
25 26
  include Redmine::I18n
app/models/project.rb
297 297
        # move_to_child_of adds the project in last (ie.right) position
298 298
        move_to_child_of(p)
299 299
      end
300
      Issue.update_fixed_versions_from_project_hierarchy_change
300 301
      true
301 302
    else
302 303
      # Can not move to the given target
......
324 325
    end
325 326
  end
326 327
  
328
  # Returns an array of the Versions used by the project, its active
329
  # sub projects, and its active parent projects
330
  def shared_versions
331
    unless @shared_versions
332
      @shared_versions = Version.systemwide_versions
333
      @shared_versions += Version.hierarchy_versions(active_projects_in_hierarchy.collect(&:id))
334
      @shared_versions += versions
335

  
336
      @shared_versions.uniq!
337
      @shared_versions.sort!
338
    end
339

  
340
    yield @shared_versions if block_given?
341
    @shared_versions
342
  end
343

  
344
  # Returns the shared_versions that are visible to +user+
345
  def shared_versions_visible_to_user(user=User.current)
346
    return shared_versions do |versions|
347
      versions.delete_if {|v| !user.allowed_to?(:view_issues, v.project) }
348
    end
349
  end
350

  
327 351
  # Returns a hash of project users grouped by role
328 352
  def users_by_role
329 353
    members.find(:all, :include => [:user, :roles]).inject({}) do |h, m|
......
600 624
        self.time_entry_activities.active
601 625
    end
602 626
  end
627

  
628
  def active_projects_in_hierarchy
629
    self.root.self_and_descendants.delete_if {|p| !p.active? }
630
  end
603 631
end
app/models/query.rb
200 200
      unless @project.issue_categories.empty?
201 201
        @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
202 202
      end
203
      unless @project.versions.empty?
204
        @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
203
      unless @project.shared_versions.empty?
204
        @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } }
205 205
      end
206 206
      unless @project.descendants.active.empty?
207 207
        @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } }
app/models/version.rb
16 16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 17

  
18 18
class Version < ActiveRecord::Base
19
  SharedValues = {
20
    "none" => :label_version_shared_none,
21
    "hierarchy" => :label_version_shared_hierarchy,
22
    "system" => :label_version_shared_systemwide
23
  }
24

  
19 25
  before_destroy :check_integrity
26
  after_save :update_issue_versions
20 27
  belongs_to :project
21 28
  has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
22 29
  acts_as_customizable
......
30 37
  validates_length_of :name, :maximum => 60
31 38
  validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true
32 39
  validates_inclusion_of :status, :in => VERSION_STATUSES
40
  validates_inclusion_of :shared, :in => SharedValues.keys
33 41

  
34 42
  named_scope :open, :conditions => {:status => 'open'}
35
    
43
  named_scope :systemwide_versions, :conditions => ["#{Version.table_name}.shared = ?", 'system' ]
44
  named_scope :hierarchy_versions, lambda {|project_ids|
45
    {
46
      :conditions => ["#{Version.table_name}.shared = ? AND #{Version.table_name}.project_id IN (?)",
47
                      'hierarchy', project_ids]
48
    }
49
  }
50

  
51
  def systemwide?
52
    shared == 'system'
53
  end
54
  
36 55
  def start_date
37 56
    effective_date
38 57
  end
......
54 73
  def closed?
55 74
    status == 'closed'
56 75
  end
76

  
77
  def open?
78
    status == 'open'
79
  end
57 80
  
58 81
  # Returns true if the version is completed: due date reached and no open issues
59 82
  def completed?
......
124 147
  def check_integrity
125 148
    raise "Can't delete version" if self.fixed_issues.find(:first)
126 149
  end
150

  
151
  # Update the issue's fixed versions.  Used if a version's sharing changes.
152
  def update_issue_versions
153
    Issue.update_fixed_versions_from_project_hierarchy_change
154
  end
127 155
  
128 156
  # Returns the average estimated time of assigned issues
129 157
  # or 1 if no issue has an estimated time
app/views/issues/_attributes.rhtml
18 18
                     :title => l(:label_issue_category_new), 
19 19
                     :tabindex => 199) if authorize_for('projects', 'add_issue_category') %></p>
20 20
<% end %>
21
<% unless @issue.assignable_versions.empty? %>
22
<p><%= f.select :fixed_version_id, (@issue.assignable_versions.collect {|v| [v.name, v.id]}), :include_blank => true %></p>
23
<% end %>
21
<p><%= f.select(:fixed_version_id, 
22
                              (shared_version_options(@project, @issue.fixed_version_id)),
23
                              { :include_blank => true }) unless @project.shared_versions.empty? %></p>
24 24
</div>
25 25

  
26 26
<div class="splitcontentright">
app/views/issues/bulk_edit.rhtml
31 31
<label><%= l(:field_fixed_version) %>: 
32 32
<%= select_tag('fixed_version_id', content_tag('option', l(:label_no_change_option), :value => '') +
33 33
                                   content_tag('option', l(:label_none), :value => 'none') +
34
                                   options_from_collection_for_select(@project.versions.open.sort, :id, :name)) %></label>
34
                                   options_for_select(shared_version_options(@project))) %></label>
35 35
</p>
36 36

  
37 37
<p>
app/views/issues/context_menu.rhtml
38 38
		<% end -%>
39 39
		</ul>
40 40
	</li>
41
	<% unless @project.nil? || @project.versions.open.empty? -%>
41
	<% unless @project.nil? || @project.shared_versions.empty? -%>
42 42
	<li class="folder">			
43 43
		<a href="#" class="submenu"><%= l(:field_fixed_version) %></a>
44 44
		<ul>
45
		<% @project.versions.open.sort.each do |v| -%>
46
		    <li><%= context_menu_link v.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'fixed_version_id' => v, :back_to => @back}, :method => :post,
45
		<% @project.shared_versions.sort.each do |v| -%>
46
		    <li><%= context_menu_link format_version_name(v), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'fixed_version_id' => v, :back_to => @back}, :method => :post,
47 47
		                              :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %></li>
48 48
		<% end -%>
49 49
		    <li><%= context_menu_link l(:label_none), {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), 'fixed_version_id' => 'none', :back_to => @back}, :method => :post,
app/views/mailer/issue_edit.text.html.rhtml
2 2

  
3 3
<ul>
4 4
<% for detail in @journal.details %>
5
<% if unauthorized_version?(detail, @recipients + @cc) %>
6
    <li><%= l(:text_journal_set_to, :label => l(:field_fixed_version), :value => l(:text_not_authorized)) %></li>
7
<% else %>
5 8
    <li><%= show_detail(detail, true) %></li>
9
    <% end %>
6 10
<% end %>
7 11
</ul>
8 12

  
app/views/mailer/issue_edit.text.plain.rhtml
1 1
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %>
2 2

  
3 3
<% for detail in @journal.details -%>
4
<% if unauthorized_version?(detail, @recipients + @cc) %>
5
<%= l(:text_journal_set_to, :label => l(:field_fixed_version), :value => l(:text_not_authorized)) %>
6
<% else %>
4 7
<%= show_detail(detail, true) %>
8
<% end %>
5 9
<% end -%>
6 10

  
7 11
<%= @journal.notes if @journal.notes? %>
app/views/projects/changelog.rhtml
33 33
  <label><%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
34 34
  <%= tracker.name %></label><br />
35 35
<% end %>
36
<br />
37
<label for="shared_versions"><%= check_box_tag "shared_versions", 1, params[:shared_versions] %> <%= l(:label_show_shared_versions) %></label>
36 38
<p><%= submit_tag l(:button_apply), :class => 'button-small' %></p>
37 39
<% end %>
38 40

  
app/views/projects/list_files.rhtml
21 21
	<% if container.is_a?(Version) -%>
22 22
  <tr>
23 23
  	<th colspan="6" align="left">
24
  		<%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
24
  		<%= link_to(h(container.project.name) + ' - ' + h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
25 25
		</th>
26 26
	</tr>
27 27
	<% end -%>
app/views/projects/roadmap.rhtml
6 6
<div id="roadmap">
7 7
<% @versions.each do |version| %>   
8 8
    <%= tag 'a', :name => version.name %>
9
    <h3 class="icon22 icon22-package"><%= link_to h(version.name), :controller => 'versions', :action => 'show', :id => version %></h3>
9
    <h3 class="icon22 icon22-package"><%= link_to h(version.project.name) + " - " + h(version.name), :controller => 'versions', :action => 'show', :id => version %></h3>
10 10
    <%= render :partial => 'versions/overview', :locals => {:version => version} %>
11 11
    <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
12 12

  
......
39 39
<% end %>
40 40
<br />
41 41
<label for="completed"><%= check_box_tag "completed", 1, params[:completed] %> <%= l(:label_show_completed_versions) %></label>
42
<br />
43
<label for="shared_versions"><%= check_box_tag "shared_versions", 1, params[:shared_versions] %> <%= l(:label_show_shared_versions) %></label>
42 44
<p><%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %></p>
43 45
<% end %>
44 46

  
app/views/projects/settings/_versions.rhtml
5 5
    <th><%= l(:field_effective_date) %></th>
6 6
    <th><%= l(:field_description) %></th>
7 7
    <th><%= l(:field_status) %></th>
8
    <th><%= l(:field_shared) %></th>
8 9
    <th><%= l(:label_wiki_page) unless @project.wiki.nil? %></th>
9 10
    <th style="width:15%"></th>
10 11
    </thead>
......
15 16
    <td align="center"><%= format_date(version.effective_date) %></td>
16 17
    <td><%=h version.description %></td>
17 18
    <td><%= l("version_status_#{version.status}") %></td>
19
    <td><%=h format_version_sharing_name(version) %></td>
18 20
    <td><%= link_to(h(version.wiki_page_title), :controller => 'wiki', :page => Wiki.titleize(version.wiki_page_title)) unless version.wiki_page_title.blank? || @project.wiki.nil? %></td>
19 21
    <td class="buttons">
20 22
    	<%= link_to_if_authorized l(:button_edit),   {:controller => 'versions', :action => 'edit', :id => version }, :class => 'icon icon-edit' %>
app/views/versions/_form.rhtml
6 6
<p><%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %></p>
7 7
<p><%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %></p>
8 8
<p><%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %></p>
9
<p><%= f.select :shared, Version::SharedValues.collect {|v| [l(v[1]),v[0]]} %></p>
9 10

  
10 11
<% @version.custom_field_values.each do |value| %>
11 12
	<p><%= custom_field_tag_with_label :version, value %></p>
12 13
<% end %>
14

  
13 15
</div>
config/locales/bg.yml
835 835
  button_move_and_follow: Move and follow
836 836
  setting_default_projects_modules: Default enabled modules for new projects
837 837
  setting_gravatar_default: Default Gravatar image
838
  label_version_shared_none: None
839
  text_not_authorized: You are not authorized to view this.
840
  field_shared: Shared
841
  label_version_shared_systemwide: Systemwide
842
  label_show_shared_versions: Show shared versions
843
  label_version_shared_hierarchy: Parent and child projects
config/locales/bs.yml
859 859
  button_move_and_follow: Move and follow
860 860
  setting_default_projects_modules: Default enabled modules for new projects
861 861
  setting_gravatar_default: Default Gravatar image
862
  label_version_shared_none: None
863
  text_not_authorized: You are not authorized to view this.
864
  field_shared: Shared
865
  label_version_shared_systemwide: Systemwide
866
  label_show_shared_versions: Show shared versions
867
  label_version_shared_hierarchy: Parent and child projects
config/locales/ca.yml
838 838
  button_move_and_follow: Move and follow
839 839
  setting_default_projects_modules: Default enabled modules for new projects
840 840
  setting_gravatar_default: Default Gravatar image
841
  label_version_shared_none: None
842
  text_not_authorized: You are not authorized to view this.
843
  field_shared: Shared
844
  label_version_shared_systemwide: Systemwide
845
  label_show_shared_versions: Show shared versions
846
  label_version_shared_hierarchy: Parent and child projects
config/locales/cs.yml
841 841
  button_move_and_follow: Move and follow
842 842
  setting_default_projects_modules: Default enabled modules for new projects
843 843
  setting_gravatar_default: Default Gravatar image
844
  label_version_shared_none: None
845
  text_not_authorized: You are not authorized to view this.
846
  field_shared: Shared
847
  label_version_shared_systemwide: Systemwide
848
  label_show_shared_versions: Show shared versions
849
  label_version_shared_hierarchy: Parent and child projects
config/locales/da.yml
861 861
  button_move_and_follow: Move and follow
862 862
  setting_default_projects_modules: Default enabled modules for new projects
863 863
  setting_gravatar_default: Default Gravatar image
864
  label_version_shared_none: None
865
  text_not_authorized: You are not authorized to view this.
866
  field_shared: Shared
867
  label_version_shared_systemwide: Systemwide
868
  label_show_shared_versions: Show shared versions
869
  label_version_shared_hierarchy: Parent and child projects
config/locales/de.yml
861 861
  button_move_and_follow: Move and follow
862 862
  setting_default_projects_modules: Default enabled modules for new projects
863 863
  setting_gravatar_default: Default Gravatar image
864
  label_version_shared_none: None
865
  text_not_authorized: You are not authorized to view this.
866
  field_shared: Shared
867
  label_version_shared_systemwide: Systemwide
868
  label_show_shared_versions: Show shared versions
869
  label_version_shared_hierarchy: Parent and child projects
config/locales/el.yml
841 841
  button_move_and_follow: Move and follow
842 842
  setting_default_projects_modules: Default enabled modules for new projects
843 843
  setting_gravatar_default: Default Gravatar image
844
  label_version_shared_none: None
845
  text_not_authorized: You are not authorized to view this.
846
  field_shared: Shared
847
  label_version_shared_systemwide: Systemwide
848
  label_show_shared_versions: Show shared versions
849
  label_version_shared_hierarchy: Parent and child projects
config/locales/en.yml
267 267
  field_identity_url: OpenID URL
268 268
  field_content: Content
269 269
  field_group_by: Group results by
270
  field_shared: Shared
270 271
  
271 272
  setting_app_title: Application title
272 273
  setting_app_subtitle: Application subtitle
......
639 640
  label_stay_logged_in: Stay logged in
640 641
  label_disabled: disabled
641 642
  label_show_completed_versions: Show completed versions
643
  label_show_shared_versions: Show shared versions
642 644
  label_me: me
643 645
  label_board: Forum
644 646
  label_board_new: New forum
......
709 711
  label_group_plural: Groups
710 712
  label_group_new: New group
711 713
  label_time_entry_plural: Spent time
714
  label_version_shared_none: None
715
  label_version_shared_hierarchy: "Parent and child projects"
716
  label_version_shared_systemwide: "Systemwide"
712 717
  
713 718
  button_login: Login
714 719
  button_submit: Submit
......
814 819
  text_wiki_page_nullify_children: "Keep child pages as root pages"
815 820
  text_wiki_page_destroy_children: "Delete child pages and all their descendants"
816 821
  text_wiki_page_reassign_children: "Reassign child pages to this parent page"
822
  text_not_authorized: You are not authorized to view this.
823

  
817 824
  
818 825
  default_role_manager: Manager
819 826
  default_role_developper: Developer
config/locales/es.yml
882 882
  button_move_and_follow: Move and follow
883 883
  setting_default_projects_modules: Default enabled modules for new projects
884 884
  setting_gravatar_default: Default Gravatar image
885
  label_version_shared_none: None
886
  text_not_authorized: You are not authorized to view this.
887
  field_shared: Shared
888
  label_version_shared_systemwide: Systemwide
889
  label_show_shared_versions: Show shared versions
890
  label_version_shared_hierarchy: Parent and child projects
config/locales/fi.yml
871 871
  button_move_and_follow: Move and follow
872 872
  setting_default_projects_modules: Default enabled modules for new projects
873 873
  setting_gravatar_default: Default Gravatar image
874
  label_version_shared_none: None
875
  text_not_authorized: You are not authorized to view this.
876
  field_shared: Shared
877
  label_version_shared_systemwide: Systemwide
878
  label_show_shared_versions: Show shared versions
879
  label_version_shared_hierarchy: Parent and child projects
config/locales/fr.yml
864 864
  field_active: Actif
865 865
  enumeration_system_activity: Activité système
866 866
  setting_gravatar_default: Default Gravatar image
867
  label_version_shared_none: None
868
  text_not_authorized: You are not authorized to view this.
869
  field_shared: Shared
870
  label_version_shared_systemwide: Systemwide
871
  label_show_shared_versions: Show shared versions
872
  label_version_shared_hierarchy: Parent and child projects
config/locales/gl.yml
861 861
  button_move_and_follow: Move and follow
862 862
  setting_default_projects_modules: Default enabled modules for new projects
863 863
  setting_gravatar_default: Default Gravatar image
864
  label_version_shared_none: None
865
  text_not_authorized: You are not authorized to view this.
866
  field_shared: Shared
867
  label_version_shared_systemwide: Systemwide
868
  label_show_shared_versions: Show shared versions
869
  label_version_shared_hierarchy: Parent and child projects
config/locales/he.yml
845 845
  button_move_and_follow: Move and follow
846 846
  setting_default_projects_modules: Default enabled modules for new projects
847 847
  setting_gravatar_default: Default Gravatar image
848
  label_version_shared_none: None
849
  text_not_authorized: You are not authorized to view this.
850
  field_shared: Shared
851
  label_version_shared_systemwide: Systemwide
852
  label_show_shared_versions: Show shared versions
853
  label_version_shared_hierarchy: Parent and child projects
config/locales/hu.yml
866 866
  button_move_and_follow: Move and follow
867 867
  setting_default_projects_modules: Default enabled modules for new projects
868 868
  setting_gravatar_default: Default Gravatar image
869
  label_version_shared_none: None
870
  text_not_authorized: You are not authorized to view this.
871
  field_shared: Shared
872
  label_version_shared_systemwide: Systemwide
873
  label_show_shared_versions: Show shared versions
874
  label_version_shared_hierarchy: Parent and child projects
config/locales/it.yml
848 848
  button_move_and_follow: Move and follow
849 849
  setting_default_projects_modules: Default enabled modules for new projects
850 850
  setting_gravatar_default: Default Gravatar image
851
  label_version_shared_none: None
852
  text_not_authorized: You are not authorized to view this.
853
  field_shared: Shared
854
  label_version_shared_systemwide: Systemwide
855
  label_show_shared_versions: Show shared versions
856
  label_version_shared_hierarchy: Parent and child projects
config/locales/ja.yml
870 870
  button_move_and_follow: Move and follow
871 871
  setting_default_projects_modules: Default enabled modules for new projects
872 872
  setting_gravatar_default: Default Gravatar image
873
  label_version_shared_none: None
874
  text_not_authorized: You are not authorized to view this.
875
  field_shared: Shared
876
  label_version_shared_systemwide: Systemwide
877
  label_show_shared_versions: Show shared versions
878
  label_version_shared_hierarchy: Parent and child projects
config/locales/ko.yml
901 901
  button_move_and_follow: Move and follow
902 902
  setting_default_projects_modules: Default enabled modules for new projects
903 903
  setting_gravatar_default: Default Gravatar image
904
  label_version_shared_none: None
905
  text_not_authorized: You are not authorized to view this.
906
  field_shared: Shared
907
  label_version_shared_systemwide: Systemwide
908
  label_show_shared_versions: Show shared versions
909
  label_version_shared_hierarchy: Parent and child projects
config/locales/lt.yml
871 871
  button_move_and_follow: Move and follow
872 872
  setting_default_projects_modules: Default enabled modules for new projects
873 873
  setting_gravatar_default: Default Gravatar image
874
  label_version_shared_none: None
875
  text_not_authorized: You are not authorized to view this.
876
  field_shared: Shared
877
  label_version_shared_systemwide: Systemwide
878
  label_show_shared_versions: Show shared versions
879
  label_version_shared_hierarchy: Parent and child projects
config/locales/nl.yml
823 823
  button_move_and_follow: Move and follow
824 824
  setting_default_projects_modules: Default enabled modules for new projects
825 825
  setting_gravatar_default: Default Gravatar image
826
  label_version_shared_none: None
827
  text_not_authorized: You are not authorized to view this.
828
  field_shared: Shared
829
  label_version_shared_systemwide: Systemwide
830
  label_show_shared_versions: Show shared versions
831
  label_version_shared_hierarchy: Parent and child projects
config/locales/no.yml
836 836
  button_move_and_follow: Move and follow
837 837
  setting_default_projects_modules: Default enabled modules for new projects
838 838
  setting_gravatar_default: Default Gravatar image
839
  label_version_shared_none: None
840
  text_not_authorized: You are not authorized to view this.
841
  field_shared: Shared
842
  label_version_shared_systemwide: Systemwide
843
  label_show_shared_versions: Show shared versions
844
  label_version_shared_hierarchy: Parent and child projects
config/locales/pl.yml
864 864
  button_move_and_follow: Move and follow
865 865
  setting_default_projects_modules: Default enabled modules for new projects
866 866
  setting_gravatar_default: Default Gravatar image
867
  label_version_shared_none: None
868
  text_not_authorized: You are not authorized to view this.
869
  field_shared: Shared
870
  label_version_shared_systemwide: Systemwide
871
  label_show_shared_versions: Show shared versions
872
  label_version_shared_hierarchy: Parent and child projects
config/locales/pt-BR.yml
867 867
  button_move_and_follow: Mover e seguir
868 868
  setting_default_projects_modules: Módulos habilitados por padrão para novos projetos
869 869
  setting_gravatar_default: Imagem Gravatar padrão
870
  label_version_shared_none: None
871
  text_not_authorized: You are not authorized to view this.
872
  field_shared: Shared
873
  label_version_shared_systemwide: Systemwide
874
  label_show_shared_versions: Show shared versions
875
  label_version_shared_hierarchy: Parent and child projects
config/locales/pt.yml
853 853
  button_move_and_follow: Move and follow
854 854
  setting_default_projects_modules: Default enabled modules for new projects
855 855
  setting_gravatar_default: Default Gravatar image
856
  label_version_shared_none: None
857
  text_not_authorized: You are not authorized to view this.
858
  field_shared: Shared
859
  label_version_shared_systemwide: Systemwide
860
  label_show_shared_versions: Show shared versions
861
  label_version_shared_hierarchy: Parent and child projects
config/locales/ro.yml
838 838
  button_move_and_follow: Move and follow
839 839
  setting_default_projects_modules: Default enabled modules for new projects
840 840
  setting_gravatar_default: Default Gravatar image
841
  label_version_shared_none: None
842
  text_not_authorized: You are not authorized to view this.
843
  field_shared: Shared
844
  label_version_shared_systemwide: Systemwide
845
  label_show_shared_versions: Show shared versions
846
  label_version_shared_hierarchy: Parent and child projects
config/locales/ru.yml
949 949
  button_move_and_follow: Переместить и перейти
950 950
  setting_default_projects_modules: Включенные по умолчанию модули для новых проектов
951 951
  setting_gravatar_default: Изображение Gravatar по умолчанию
952
  label_version_shared_none: None
953
  text_not_authorized: You are not authorized to view this.
954
  field_shared: Shared
955
  label_version_shared_systemwide: Systemwide
956
  label_show_shared_versions: Show shared versions
957
  label_version_shared_hierarchy: Parent and child projects
config/locales/sk.yml
840 840
  button_move_and_follow: Move and follow
841 841
  setting_default_projects_modules: Default enabled modules for new projects
842 842
  setting_gravatar_default: Default Gravatar image
843
  label_version_shared_none: None
844
  text_not_authorized: You are not authorized to view this.
845
  field_shared: Shared
846
  label_version_shared_systemwide: Systemwide
847
  label_show_shared_versions: Show shared versions
848
  label_version_shared_hierarchy: Parent and child projects
config/locales/sl.yml
837 837
  button_move_and_follow: Move and follow
838 838
  setting_default_projects_modules: Default enabled modules for new projects
839 839
  setting_gravatar_default: Default Gravatar image
840
  label_version_shared_none: None
841
  text_not_authorized: You are not authorized to view this.
842
  field_shared: Shared
843
  label_version_shared_systemwide: Systemwide
844
  label_show_shared_versions: Show shared versions
845
  label_version_shared_hierarchy: Parent and child projects
config/locales/sr.yml
856 856
  button_move_and_follow: Move and follow
857 857
  setting_default_projects_modules: Default enabled modules for new projects
858 858
  setting_gravatar_default: Default Gravatar image
859
  label_version_shared_none: None
860
  text_not_authorized: You are not authorized to view this.
861
  field_shared: Shared
862
  label_version_shared_systemwide: Systemwide
863
  label_show_shared_versions: Show shared versions
864
  label_version_shared_hierarchy: Parent and child projects
config/locales/sv.yml
889 889
  button_move_and_follow: Move and follow
890 890
  setting_default_projects_modules: Default enabled modules for new projects
891 891
  setting_gravatar_default: Default Gravatar image
892
  label_version_shared_none: None
893
  text_not_authorized: You are not authorized to view this.
894
  field_shared: Shared
895
  label_version_shared_systemwide: Systemwide
896
  label_show_shared_versions: Show shared versions
897
  label_version_shared_hierarchy: Parent and child projects
config/locales/th.yml
838 838
  button_move_and_follow: Move and follow
839 839
  setting_default_projects_modules: Default enabled modules for new projects
840 840
  setting_gravatar_default: Default Gravatar image
841
  label_version_shared_none: None
842
  text_not_authorized: You are not authorized to view this.
843
  field_shared: Shared
844
  label_version_shared_systemwide: Systemwide
845
  label_show_shared_versions: Show shared versions
846
  label_version_shared_hierarchy: Parent and child projects
config/locales/tr.yml
868 868
  button_move_and_follow: Move and follow
869 869
  setting_default_projects_modules: Default enabled modules for new projects
870 870
  setting_gravatar_default: Default Gravatar image
871
  label_version_shared_none: None
872
  text_not_authorized: You are not authorized to view this.
873
  field_shared: Shared
874
  label_version_shared_systemwide: Systemwide
875
  label_show_shared_versions: Show shared versions
876
  label_version_shared_hierarchy: Parent and child projects
config/locales/uk.yml
837 837
  button_move_and_follow: Move and follow
838 838
  setting_default_projects_modules: Default enabled modules for new projects
839 839
  setting_gravatar_default: Default Gravatar image
840
  label_version_shared_none: None
841
  text_not_authorized: You are not authorized to view this.
842
  field_shared: Shared
843
  label_version_shared_systemwide: Systemwide
844
  label_show_shared_versions: Show shared versions
845
  label_version_shared_hierarchy: Parent and child projects
config/locales/vi.yml
900 900
  button_move_and_follow: Move and follow
901 901
  setting_default_projects_modules: Default enabled modules for new projects
902 902
  setting_gravatar_default: Default Gravatar image
903
  label_version_shared_none: None
904
  text_not_authorized: You are not authorized to view this.
905
  field_shared: Shared
906
  label_version_shared_systemwide: Systemwide
907
  label_show_shared_versions: Show shared versions
908
  label_version_shared_hierarchy: Parent and child projects
config/locales/zh-TW.yml
932 932
  enumeration_doc_categories: 文件分類
933 933
  enumeration_activities: 活動 (時間追蹤)
934 934
  enumeration_system_activity: 系統活動
935
  label_version_shared_none: None
936
  text_not_authorized: You are not authorized to view this.
937
  field_shared: Shared
938
  label_version_shared_systemwide: Systemwide
939
  label_show_shared_versions: Show shared versions
940
  label_version_shared_hierarchy: Parent and child projects
config/locales/zh.yml
865 865
  button_move_and_follow: Move and follow
866 866
  setting_default_projects_modules: Default enabled modules for new projects
867 867
  setting_gravatar_default: Default Gravatar image
868
  label_version_shared_none: None
869
  text_not_authorized: You are not authorized to view this.
870
  field_shared: Shared
871
  label_version_shared_systemwide: Systemwide
872
  label_show_shared_versions: Show shared versions
873
  label_version_shared_hierarchy: Parent and child projects
db/migrate/20090907153556_add_shared_to_versions.rb
1
class AddSharedToVersions < ActiveRecord::Migration
2
  def self.up
3
    add_column :versions, :shared, :string, :default => 'none', :null => false
4
    add_index :versions, :shared
5
  end
6

  
7
  def self.down
8
    remove_column :versions, :shared
9
  end
10
end
db/migrate/20090907170038_populate_version_shared.rb
1
class PopulateVersionShared < ActiveRecord::Migration
2
  def self.up
3
    Version.update_all('shared = \'none\'', ['shared IS NULL OR shared = ?',''])
4
  end
5

  
6
  def self.down
7
    # No-op
8
  end
9
end
lib/redmine.rb
142 142
  menu.push :overview, { :controller => 'projects', :action => 'show' }
143 143
  menu.push :activity, { :controller => 'projects', :action => 'activity' }
144 144
  menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' }, 
145
              :if => Proc.new { |p| p.versions.any? }
145
              :if => Proc.new { |p| p.shared_versions_visible_to_user.any? }
146 146
  menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
147 147
  menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new,
148 148
              :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
test/exemplars/version_exemplar.rb
1 1
class Version < ActiveRecord::Base
2 2
  generator_for :name, :method => :next_name
3
  generator_for :status => 'open'
3 4
  
4 5
  def self.next_name
5 6
    @last_name ||= 'Version 1.0.0'
test/fixtures/attachments.yml
133 133
  filename: picture.jpg
134 134
  author_id: 2
135 135
  content_type: image/jpeg
136
  
136
attachments_012:
137
  created_on: 2006-07-19 21:07:27 +02:00
138
  container_type: Version
139
  container_id: 1
140
  downloads: 0
141
  disk_filename: 060719210727_version_file.zip
142
  digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
143
  id: 12
144
  filesize: 452
145
  filename: version_file.zip
146
  author_id: 2
147
  content_type: application/octet-stream
test/fixtures/issues.yml
189 189
  status_id: 5
190 190
  start_date: <%= 1.day.ago.to_date.to_s(:db) %>
191 191
  due_date:
192
issues_013:
193
  created_on: <%= 5.days.ago.to_date.to_s(:db) %>
194
  project_id: 3
195
  updated_on: <%= 2.days.ago.to_date.to_s(:db) %>
196
  priority_id: 4
197
  subject: Subproject issue two
198
  id: 13
199
  fixed_version_id: 
200
  category_id: 
201
  description: This is a second issue on a cookbook subproject
202
  tracker_id: 1
203
  assigned_to_id: 
204
  author_id: 2
205
  status_id: 1
test/fixtures/journal_details.yml
13 13
  value: "30"
14 14
  prop_key: done_ratio
15 15
  journal_id: 1
16
journal_details_003:
17
  old_value: nil
18
  property: attr
19
  id: 3
20
  value: "6"
21
  prop_key: fixed_version_id
22
  journal_id: 4
test/fixtures/journals.yml
20 20
  journalized_type: Issue
21 21
  user_id: 2
22 22
  journalized_id: 2
23
  
23
journals_004: 
24
  created_on: <%= 1.days.ago.to_date.to_s(:db) %>
25
  notes: "A comment with a private version."
26
  id: 4
27
  journalized_type: Issue
28
  user_id: 1
29
  journalized_id: 6
test/fixtures/members.yml
42 42
  project_id: 5
43 43
  user_id: 8
44 44
  mail_notification: false
45
  
45
members_008:
46
  created_on: 2006-07-19 19:35:33 +02:00
47
  project_id: 5
48
  id: 8
49
  user_id: 1
50
  mail_notification: true
test/fixtures/versions.yml
1
--- 
2
versions_001: 
3
  created_on: 2006-07-19 21:00:07 +02:00
4
  name: "0.1"
5
  project_id: 1
6
  updated_on: 2006-07-19 21:00:07 +02:00
7
  id: 1
8
  description: Beta
9
  effective_date: 2006-07-01
10
  status: closed
11
versions_002: 
12
  created_on: 2006-07-19 21:00:33 +02:00
13
  name: "1.0"
14
  project_id: 1
15
  updated_on: 2006-07-19 21:00:33 +02:00
16
  id: 2
17
  description: Stable release
18
  effective_date: <%= 20.day.from_now.to_date.to_s(:db) %>
19
  status: locked
20
versions_003: 
21
  created_on: 2006-07-19 21:00:33 +02:00
22
  name: "2.0"
23
  project_id: 1
24
  updated_on: 2006-07-19 21:00:33 +02:00
25
  id: 3
26
  description: Future version
27
  effective_date: 
28
  status: open
29
  
1
--- 
2
versions_001: 
3
  created_on: 2006-07-19 21:00:07 +02:00
4
  name: "0.1"
5
  project_id: 1
6
  updated_on: 2006-07-19 21:00:07 +02:00
7
  id: 1
8
  description: Beta
9
  effective_date: 2006-07-01
10
  status: closed
11
  shared: 'none'
12
versions_002: 
13
  created_on: 2006-07-19 21:00:33 +02:00
14
  name: "1.0"
15
  project_id: 1
16
  updated_on: 2006-07-19 21:00:33 +02:00
17
  id: 2
18
  description: Stable release
19
  effective_date: <%= 20.day.from_now.to_date.to_s(:db) %>
20
  status: locked
21
  shared: 'none'
22
versions_003: 
23
  created_on: 2006-07-19 21:00:33 +02:00
24
  name: "2.0"
25
  project_id: 1
26
  updated_on: 2006-07-19 21:00:33 +02:00
27
  id: 3
28
  description: Future version
29
  effective_date: 
30
  status: open
31
  shared: 'none'
32
versions_004: 
33
  created_on: 2006-07-19 21:00:33 +02:00
34
  name: "2.0"
35
  project_id: 3
36
  updated_on: 2006-07-19 21:00:33 +02:00
37
  id: 4
38
  description: Future version on subproject
39
  effective_date: 
40
  status: open
41
  shared: 'hierarchy'
42
versions_005: 
43
  created_on: 2006-07-19 21:00:07 +02:00
44
  name: "Alpha"
45
  project_id: 2
46
  updated_on: 2006-07-19 21:00:07 +02:00
47
  id: 5
48
  description: Private Alpha
49
  effective_date: 2006-07-01
50
  status: open
51
  shared: 'none'
52
versions_006: 
53
  created_on: 2006-07-19 21:00:07 +02:00
54
  name: "Private Version of public subproject"
55
  project_id: 5
56
  updated_on: 2006-07-19 21:00:07 +02:00
57
  id: 6
58
  description: "Should be done any day now..."
59
  effective_date: 
60
  status: open
61
  shared: 'hierarchy'
62
versions_007: 
63
  created_on: 2006-07-19 21:00:07 +02:00
64
  name: "Systemwide visible version"
65
  project_id: 2
66
  updated_on: 2006-07-19 21:00:07 +02:00
67
  id: 7
68
  description:
69
  effective_date: 
70
  status: open
71
  shared: 'system'
test/functional/issues_controller_test.rb
925 925
    assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
926 926
  end
927 927
  
928
  def test_post_edit_should_allow_fixed_version_to_be_set_to_a_subproject
929
    issue = Issue.find(2)
930
    @request.session[:user_id] = 2
931

  
932
    post :edit,
933
         :id => issue.id,
934
         :issue => {
935
           :fixed_version_id => 4
936
         }
937

  
938
    assert_response :redirect
939
    issue.reload
940
    assert_equal 4, issue.fixed_version_id
941
    assert_not_equal issue.project_id, issue.fixed_version.project_id
942
  end
943
  
928 944
  def test_get_bulk_edit
929 945
    @request.session[:user_id] = 2
930 946
    get :bulk_edit, :ids => [1, 2]
......
1005 1021
    assert_nil Issue.find(2).assigned_to
1006 1022
  end
1007 1023
  
1024
  def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject
1025
    @request.session[:user_id] = 2
1026

  
1027
    post :bulk_edit,
1028
         :ids => [1,2],
1029
         :fixed_version_id => 4
1030

  
1031
    assert_response :redirect
1032
    issues = Issue.find([1,2])
1033
    issues.each do |issue|
1034
      assert_equal 4, issue.fixed_version_id
1035
      assert_not_equal issue.project_id, issue.fixed_version.project_id
1036
    end
1037
  end
1038

  
1008 1039
  def test_move_routing
1009 1040
    assert_routing(
1010 1041
      {:method => :get, :path => '/issues/1/move'},
......
1080 1111
    assert_tag :tag => 'a', :content => 'Immediate',
1081 1112
                            :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&amp;priority_id=8',
1082 1113
                                             :class => '' }
1114
    # Versions
1115
    assert_tag :tag => 'a', :content => 'eCookbook - 0.1',
1116
                            :attributes => { :href => '/issues/bulk_edit?fixed_version_id=1&amp;ids%5B%5D=1',
1117
                                             :class => '' }
1118
    assert_tag :tag => 'a', :content => 'eCookbook - 1.0',
1119
                            :attributes => { :href => '/issues/bulk_edit?fixed_version_id=2&amp;ids%5B%5D=1',
1120
                                             :class => '' }
1121
    assert_tag :tag => 'a', :content => 'eCookbook Subproject 1 - 2.0',
1122
                            :attributes => { :href => '/issues/bulk_edit?fixed_version_id=4&amp;ids%5B%5D=1',
1123
                                             :class => '' }
1124

  
1083 1125
    assert_tag :tag => 'a', :content => 'Dave Lopper',
1084 1126
                            :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&amp;ids%5B%5D=1',
... This diff was truncated because it exceeds the maximum size that can be displayed.
(4-4/4)