From af91c3b25108065ce108a6f0c9b1d6ecd7e22e5a Mon Sep 17 00:00:00 2001
From: Eric Davis
")
end
+ def format_version_name(version)
+ if User.current.allowed_to?(:view_issues, version.project) || version.systemwide?
+ "#{h(version.project.name)} - #{h(version.name)}"
+ else
+ "#{l(:text_not_authorized)}"
+ end
+ end
+
+ def format_version_sharing_name(version)
+ if version.shared && Version::SharedValues.key?(version.shared)
+ l(Version::SharedValues[version.shared])
+ else
+ l(:label_version_shared_none)
+ end
+ end
+
+ # Given an Array of emails (+recipients+), do they all have
+ # +permission+ on +project+ ?
+ def recipients_all_allowed_to?(recipients, permission, project)
+ recipients.uniq.all? do |recipient|
+ user = User.find_by_mail(recipient)
+ user && user.allowed_to?(permission, project)
+ end
+ end
+
+ # Given an Array of +versions+, are all the email addresses
+ # (+recipients+) allowed to view all of the versions?
+ def recipients_all_allowed_to_see_versions?(recipients, versions)
+ versions.uniq.all? do |version|
+ if version.nil?
+ true
+ else
+ recipients_all_allowed_to?(recipients, :view_issues, version.project)
+ end
+ end
+ end
+
def due_date_distance_in_words(date)
if date
l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date))
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 0f28cc0..2e55f1f 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -64,6 +64,36 @@ module IssuesHelper
@sidebar_queries
end
+ # Returns a set of options for a select field, grouped by project.
+ def shared_version_options(project, selected=nil)
+ grouped = {}
+ project.shared_versions.each do |version|
+ next unless version.open?
+
+ if User.current.allowed_to?(:view_issues, version.project) || version.systemwide?
+ grouped[version.project.name] ||= []
+ grouped[version.project.name] << [h(version.name), version.id]
+ else
+ grouped[l(:text_not_authorized)] ||=[]
+ grouped[l(:text_not_authorized)] << [l(:text_not_authorized), version.id]
+ end
+ end
+
+ # Add in the selected
+ selected_version = Version.find_by_id(selected)
+ if selected_version && !project.shared_versions.include?(selected_version)
+ if User.current.allowed_to?(:view_issues, selected_version.project) || selected_version.systemwide?
+ grouped[selected_version.project.name] ||= []
+ grouped[selected_version.project.name] << [h(selected_version.name), selected_version.id]
+ else
+ grouped[l(:text_not_authorized)] ||=[]
+ grouped[l(:text_not_authorized)] << [l(:text_not_authorized), selected_version.id]
+ end
+ end
+
+ grouped_options_for_select(grouped, selected)
+ end
+
def show_detail(detail, no_html=false)
case detail.property
when 'attr'
@@ -91,8 +121,8 @@ module IssuesHelper
c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value
c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
when 'fixed_version_id'
- v = Version.find_by_id(detail.value) and value = v.name if detail.value
- v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value
+ v = Version.find_by_id(detail.value) and value = format_version_name(v) if detail.value
+ v = Version.find_by_id(detail.old_value) and old_value = format_version_name(v) if detail.old_value
when 'estimated_hours'
value = "%0.02f" % detail.value.to_f unless detail.value.blank?
old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
diff --git a/app/helpers/mailer_helper.rb b/app/helpers/mailer_helper.rb
new file mode 100644
index 0000000..a4ff772
--- /dev/null
+++ b/app/helpers/mailer_helper.rb
@@ -0,0 +1,25 @@
+# redMine - project management software
+# Copyright (C) 2006-2009 Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+module MailerHelper
+ def unauthorized_version?(journal_detail, recipients)
+ return false unless journal_detail.prop_key == "fixed_version_id"
+
+ !recipients_all_allowed_to_see_versions?(recipients,
+ Version.find_all_by_id([journal_detail.value, journal_detail.old_value]))
+ end
+end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 07ba23d..e76c42c 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -18,7 +18,11 @@
module ProjectsHelper
def link_to_version(version, options = {})
return '' unless version && version.is_a?(Version)
- link_to h(version.name), { :controller => 'versions', :action => 'show', :id => version }, options
+ if User.current.allowed_to?(:view_issues, version.project)
+ link_to format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options
+ else
+ format_version_name(version)
+ end
end
def project_settings_tabs
diff --git a/app/models/issue.rb b/app/models/issue.rb
index d279f3c..0184a6a 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -100,7 +100,10 @@ class Issue < ActiveRecord::Base
# reassign to the category with same name if any
new_category = issue.category.nil? ? nil : new_project.issue_categories.find_by_name(issue.category.name)
issue.category = new_category
- issue.fixed_version = nil
+ # Keep the fixed_version if it's still valid in the new_project
+ unless new_project.shared_versions.include?(issue.fixed_version)
+ issue.fixed_version = nil
+ end
issue.project = new_project
end
if new_tracker
@@ -234,7 +237,9 @@ class Issue < ActiveRecord::Base
# Versions that the issue can be assigned to
def assignable_versions
- @assignable_versions ||= (project.versions.open + [Version.find_by_id(fixed_version_id_was)]).compact.uniq.sort
+ @assignable_versions ||= (project.shared_versions_visible_to_user(User.current).select {|v| v.open?} +
+ [Version.find_by_id(fixed_version_id_was)]).
+ compact.uniq.sort
end
# Returns true if this issue is blocked by another issue that is still open
@@ -318,6 +323,23 @@ class Issue < ActiveRecord::Base
s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id
s
end
+
+ # Update all issues so their versions are not pointing to a
+ # fixed_version that is outside of the issue's project hierarchy.
+ #
+ # OPTIMIZE: does a full table scan of Issues with a fixed_version.
+ def self.update_fixed_versions_from_project_hierarchy_change
+ Issue.all(:conditions => ['fixed_version_id IS NOT NULL'],
+ :include => [:project, :fixed_version]
+ ).each do |issue|
+ next if issue.project.nil? || issue.fixed_version.nil?
+ unless issue.project.shared_versions.include?(issue.fixed_version)
+ issue.init_journal(User.current)
+ issue.fixed_version = nil
+ issue.save
+ end
+ end
+ end
private
diff --git a/app/models/mailer.rb b/app/models/mailer.rb
index 3d5231d..8fd1466 100644
--- a/app/models/mailer.rb
+++ b/app/models/mailer.rb
@@ -20,6 +20,7 @@ class Mailer < ActionMailer::Base
helper :application
helper :issues
helper :custom_fields
+ helper :mailer
include ActionController::UrlWriter
include Redmine::I18n
diff --git a/app/models/project.rb b/app/models/project.rb
index 8829f04..1d98588 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -297,6 +297,7 @@ class Project < ActiveRecord::Base
# move_to_child_of adds the project in last (ie.right) position
move_to_child_of(p)
end
+ Issue.update_fixed_versions_from_project_hierarchy_change
true
else
# Can not move to the given target
@@ -324,6 +325,29 @@ class Project < ActiveRecord::Base
end
end
+ # Returns an array of the Versions used by the project, its active
+ # sub projects, and its active parent projects
+ def shared_versions
+ unless @shared_versions
+ @shared_versions = Version.systemwide_versions
+ @shared_versions += Version.hierarchy_versions(active_projects_in_hierarchy.collect(&:id))
+ @shared_versions += versions
+
+ @shared_versions.uniq!
+ @shared_versions.sort!
+ end
+
+ yield @shared_versions if block_given?
+ @shared_versions
+ end
+
+ # Returns the shared_versions that are visible to +user+
+ def shared_versions_visible_to_user(user=User.current)
+ return shared_versions do |versions|
+ versions.delete_if {|v| !user.allowed_to?(:view_issues, v.project) }
+ end
+ end
+
# Returns a hash of project users grouped by role
def users_by_role
members.find(:all, :include => [:user, :roles]).inject({}) do |h, m|
@@ -600,4 +624,8 @@ class Project < ActiveRecord::Base
self.time_entry_activities.active
end
end
+
+ def active_projects_in_hierarchy
+ self.root.self_and_descendants.delete_if {|p| !p.active? }
+ end
end
diff --git a/app/models/query.rb b/app/models/query.rb
index f7aeb0e..2e1680a 100644
--- a/app/models/query.rb
+++ b/app/models/query.rb
@@ -200,8 +200,8 @@ class Query < ActiveRecord::Base
unless @project.issue_categories.empty?
@available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
end
- unless @project.versions.empty?
- @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
+ unless @project.shared_versions.empty?
+ @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] } }
end
unless @project.descendants.active.empty?
@available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } }
diff --git a/app/models/version.rb b/app/models/version.rb
index e63ed46..e5ef314 100644
--- a/app/models/version.rb
+++ b/app/models/version.rb
@@ -16,7 +16,14 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Version < ActiveRecord::Base
+ SharedValues = {
+ "none" => :label_version_shared_none,
+ "hierarchy" => :label_version_shared_hierarchy,
+ "system" => :label_version_shared_systemwide
+ }
+
before_destroy :check_integrity
+ after_save :update_issue_versions
belongs_to :project
has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
acts_as_customizable
@@ -30,9 +37,21 @@ class Version < ActiveRecord::Base
validates_length_of :name, :maximum => 60
validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true
validates_inclusion_of :status, :in => VERSION_STATUSES
+ validates_inclusion_of :shared, :in => SharedValues.keys
named_scope :open, :conditions => {:status => 'open'}
-
+ named_scope :systemwide_versions, :conditions => ["#{Version.table_name}.shared = ?", 'system' ]
+ named_scope :hierarchy_versions, lambda {|project_ids|
+ {
+ :conditions => ["#{Version.table_name}.shared = ? AND #{Version.table_name}.project_id IN (?)",
+ 'hierarchy', project_ids]
+ }
+ }
+
+ def systemwide?
+ shared == 'system'
+ end
+
def start_date
effective_date
end
@@ -54,6 +73,10 @@ class Version < ActiveRecord::Base
def closed?
status == 'closed'
end
+
+ def open?
+ status == 'open'
+ end
# Returns true if the version is completed: due date reached and no open issues
def completed?
@@ -124,6 +147,11 @@ private
def check_integrity
raise "Can't delete version" if self.fixed_issues.find(:first)
end
+
+ # Update the issue's fixed versions. Used if a version's sharing changes.
+ def update_issue_versions
+ Issue.update_fixed_versions_from_project_hierarchy_change
+ end
# Returns the average estimated time of assigned issues
# or 1 if no issue has an estimated time
diff --git a/app/views/issues/_attributes.rhtml b/app/views/issues/_attributes.rhtml
index b27c562..687f2cf 100644
--- a/app/views/issues/_attributes.rhtml
+++ b/app/views/issues/_attributes.rhtml
@@ -18,9 +18,9 @@
:title => l(:label_issue_category_new),
:tabindex => 199) if authorize_for('projects', 'add_issue_category') %>
<%= f.select :fixed_version_id, (@issue.assignable_versions.collect {|v| [v.name, v.id]}), :include_blank => true %>
-<% end %> +<%= f.select(:fixed_version_id, + (shared_version_options(@project, @issue.fixed_version_id)), + { :include_blank => true }) unless @project.shared_versions.empty? %>
diff --git a/app/views/issues/context_menu.rhtml b/app/views/issues/context_menu.rhtml index d2c673d..7b28bee 100644 --- a/app/views/issues/context_menu.rhtml +++ b/app/views/issues/context_menu.rhtml @@ -38,12 +38,12 @@ <% end -%> - <% unless @project.nil? || @project.versions.open.empty? -%> + <% unless @project.nil? || @project.shared_versions.empty? -%>
<%= submit_tag l(:button_apply), :class => 'button-small' %>
<% end %> diff --git a/app/views/projects/list_files.rhtml b/app/views/projects/list_files.rhtml index 2b2e5e8..70e36fe 100644 --- a/app/views/projects/list_files.rhtml +++ b/app/views/projects/list_files.rhtml @@ -21,7 +21,7 @@ <% if container.is_a?(Version) -%><%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %>
<% end %> diff --git a/app/views/projects/settings/_versions.rhtml b/app/views/projects/settings/_versions.rhtml index 9bca58c..628fbf7 100644 --- a/app/views/projects/settings/_versions.rhtml +++ b/app/views/projects/settings/_versions.rhtml @@ -5,6 +5,7 @@<%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %>
<%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %>
<%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %>
+<%= f.select :shared, Version::SharedValues.collect {|v| [l(v[1]),v[0]]} %>
<% @version.custom_field_values.each do |value| %><%= custom_field_tag_with_label :version, value %>
<% end %> + diff --git a/config/locales/bg.yml b/config/locales/bg.yml index e091f85..f8ed2a8 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -835,3 +835,9 @@ bg: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/bs.yml b/config/locales/bs.yml index d6b1590..d09489e 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -859,3 +859,9 @@ bs: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 6aacce6..c42539f 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -838,3 +838,9 @@ ca: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 943fb69..4832bfa 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -841,3 +841,9 @@ cs: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/da.yml b/config/locales/da.yml index 33acc45..ece9d12 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -861,3 +861,9 @@ da: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/de.yml b/config/locales/de.yml index 29273f3..897088f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -861,3 +861,9 @@ de: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/el.yml b/config/locales/el.yml index 6907603..0b6938e 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -841,3 +841,9 @@ el: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/en.yml b/config/locales/en.yml index 85234cb..3c1b70d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -267,6 +267,7 @@ en: field_identity_url: OpenID URL field_content: Content field_group_by: Group results by + field_shared: Shared setting_app_title: Application title setting_app_subtitle: Application subtitle @@ -639,6 +640,7 @@ en: label_stay_logged_in: Stay logged in label_disabled: disabled label_show_completed_versions: Show completed versions + label_show_shared_versions: Show shared versions label_me: me label_board: Forum label_board_new: New forum @@ -709,6 +711,9 @@ en: label_group_plural: Groups label_group_new: New group label_time_entry_plural: Spent time + label_version_shared_none: None + label_version_shared_hierarchy: "Parent and child projects" + label_version_shared_systemwide: "Systemwide" button_login: Login button_submit: Submit @@ -814,6 +819,8 @@ en: text_wiki_page_nullify_children: "Keep child pages as root pages" text_wiki_page_destroy_children: "Delete child pages and all their descendants" text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_not_authorized: You are not authorized to view this. + default_role_manager: Manager default_role_developper: Developer diff --git a/config/locales/es.yml b/config/locales/es.yml index 07bb880..07eeac3 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -882,3 +882,9 @@ es: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 4501e63..c525780 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -871,3 +871,9 @@ fi: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 2e2a69b..370df5a 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -864,3 +864,9 @@ fr: field_active: Actif enumeration_system_activity: Activité système setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/gl.yml b/config/locales/gl.yml index f2af3ed..2884a8d 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -861,3 +861,9 @@ gl: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/he.yml b/config/locales/he.yml index cae31b3..6cb4547 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -845,3 +845,9 @@ he: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/hu.yml b/config/locales/hu.yml index ef37ef2..3ded7a2 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -866,3 +866,9 @@ button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/it.yml b/config/locales/it.yml index 9460211..4548c40 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -848,3 +848,9 @@ it: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 450cff9..5f02e7d 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -870,3 +870,9 @@ ja: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 260d353..2e4239e 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -901,3 +901,9 @@ ko: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 5d4ff19..16bebe0 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -871,3 +871,9 @@ lt: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/nl.yml b/config/locales/nl.yml index f41e42b..f7a0399 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -823,3 +823,9 @@ nl: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/no.yml b/config/locales/no.yml index d9f81cf..2006607 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -836,3 +836,9 @@ button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 6227892..a94dfd6 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -864,3 +864,9 @@ pl: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 2019c49..8728b30 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -867,3 +867,9 @@ pt-BR: button_move_and_follow: Mover e seguir setting_default_projects_modules: Módulos habilitados por padrão para novos projetos setting_gravatar_default: Imagem Gravatar padrão + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 3b3f104..c33a8cd 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -853,3 +853,9 @@ pt: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 19e5a5c..2d331cf 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -838,3 +838,9 @@ ro: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 7555af4..0364ec7 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -949,3 +949,9 @@ ru: button_move_and_follow: Переместить и перейти setting_default_projects_modules: Включенные по умолчанию модули для новых проектов setting_gravatar_default: Изображение Gravatar по умолчанию + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/sk.yml b/config/locales/sk.yml index af8eab1..fc78cae 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -840,3 +840,9 @@ sk: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 56cd421..194b52c 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -837,3 +837,9 @@ sl: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 3227463..4401191 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -856,3 +856,9 @@ button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/sv.yml b/config/locales/sv.yml index a4698fc..29499cd 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -889,3 +889,9 @@ sv: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/th.yml b/config/locales/th.yml index 7b41412..d1c4815 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -838,3 +838,9 @@ th: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/tr.yml b/config/locales/tr.yml index a0a1c26..376aff7 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -868,3 +868,9 @@ tr: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 7d8d1a9..02460c5 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -837,3 +837,9 @@ uk: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/vi.yml b/config/locales/vi.yml index fef14e4..e8c9a75 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -900,3 +900,9 @@ vi: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 7eab6fa..b083123 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -932,3 +932,9 @@ enumeration_doc_categories: 文件分類 enumeration_activities: 活動 (時間追蹤) enumeration_system_activity: 系統活動 + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/config/locales/zh.yml b/config/locales/zh.yml index a40851b..36368f4 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -865,3 +865,9 @@ zh: button_move_and_follow: Move and follow setting_default_projects_modules: Default enabled modules for new projects setting_gravatar_default: Default Gravatar image + label_version_shared_none: None + text_not_authorized: You are not authorized to view this. + field_shared: Shared + label_version_shared_systemwide: Systemwide + label_show_shared_versions: Show shared versions + label_version_shared_hierarchy: Parent and child projects diff --git a/db/migrate/20090907153556_add_shared_to_versions.rb b/db/migrate/20090907153556_add_shared_to_versions.rb new file mode 100644 index 0000000..f8407ce --- /dev/null +++ b/db/migrate/20090907153556_add_shared_to_versions.rb @@ -0,0 +1,10 @@ +class AddSharedToVersions < ActiveRecord::Migration + def self.up + add_column :versions, :shared, :string, :default => 'none', :null => false + add_index :versions, :shared + end + + def self.down + remove_column :versions, :shared + end +end diff --git a/db/migrate/20090907170038_populate_version_shared.rb b/db/migrate/20090907170038_populate_version_shared.rb new file mode 100644 index 0000000..114eb14 --- /dev/null +++ b/db/migrate/20090907170038_populate_version_shared.rb @@ -0,0 +1,9 @@ +class PopulateVersionShared < ActiveRecord::Migration + def self.up + Version.update_all('shared = \'none\'', ['shared IS NULL OR shared = ?','']) + end + + def self.down + # No-op + end +end diff --git a/lib/redmine.rb b/lib/redmine.rb index 8dbe5d0..71a1f15 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -142,7 +142,7 @@ Redmine::MenuManager.map :project_menu do |menu| menu.push :overview, { :controller => 'projects', :action => 'show' } menu.push :activity, { :controller => 'projects', :action => 'activity' } menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' }, - :if => Proc.new { |p| p.versions.any? } + :if => Proc.new { |p| p.shared_versions_visible_to_user.any? } menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new, :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } diff --git a/test/exemplars/version_exemplar.rb b/test/exemplars/version_exemplar.rb index 8aef99f..33e7c3a 100644 --- a/test/exemplars/version_exemplar.rb +++ b/test/exemplars/version_exemplar.rb @@ -1,5 +1,6 @@ class Version < ActiveRecord::Base generator_for :name, :method => :next_name + generator_for :status => 'open' def self.next_name @last_name ||= 'Version 1.0.0' diff --git a/test/fixtures/attachments.yml b/test/fixtures/attachments.yml index c6493bd..002bb09 100644 --- a/test/fixtures/attachments.yml +++ b/test/fixtures/attachments.yml @@ -133,4 +133,15 @@ attachments_011: filename: picture.jpg author_id: 2 content_type: image/jpeg - \ No newline at end of file +attachments_012: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Version + container_id: 1 + downloads: 0 + disk_filename: 060719210727_version_file.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 12 + filesize: 452 + filename: version_file.zip + author_id: 2 + content_type: application/octet-stream diff --git a/test/fixtures/issues.yml b/test/fixtures/issues.yml index 0319745..1cc7837 100644 --- a/test/fixtures/issues.yml +++ b/test/fixtures/issues.yml @@ -189,3 +189,17 @@ issues_012: status_id: 5 start_date: <%= 1.day.ago.to_date.to_s(:db) %> due_date: +issues_013: + created_on: <%= 5.days.ago.to_date.to_s(:db) %> + project_id: 3 + updated_on: <%= 2.days.ago.to_date.to_s(:db) %> + priority_id: 4 + subject: Subproject issue two + id: 13 + fixed_version_id: + category_id: + description: This is a second issue on a cookbook subproject + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 diff --git a/test/fixtures/journal_details.yml b/test/fixtures/journal_details.yml index 38e6bf1..046202d 100644 --- a/test/fixtures/journal_details.yml +++ b/test/fixtures/journal_details.yml @@ -13,3 +13,10 @@ journal_details_002: value: "30" prop_key: done_ratio journal_id: 1 +journal_details_003: + old_value: nil + property: attr + id: 3 + value: "6" + prop_key: fixed_version_id + journal_id: 4 diff --git a/test/fixtures/journals.yml b/test/fixtures/journals.yml index 5c0b702..2323c1a 100644 --- a/test/fixtures/journals.yml +++ b/test/fixtures/journals.yml @@ -20,4 +20,10 @@ journals_003: journalized_type: Issue user_id: 2 journalized_id: 2 - \ No newline at end of file +journals_004: + created_on: <%= 1.days.ago.to_date.to_s(:db) %> + notes: "A comment with a private version." + id: 4 + journalized_type: Issue + user_id: 1 + journalized_id: 6 diff --git a/test/fixtures/members.yml b/test/fixtures/members.yml index 65e3fd6..504d64f 100644 --- a/test/fixtures/members.yml +++ b/test/fixtures/members.yml @@ -42,4 +42,9 @@ members_007: project_id: 5 user_id: 8 mail_notification: false - \ No newline at end of file +members_008: + created_on: 2006-07-19 19:35:33 +02:00 + project_id: 5 + id: 8 + user_id: 1 + mail_notification: true diff --git a/test/fixtures/versions.yml b/test/fixtures/versions.yml index bcecb67..c9e6fd4 100644 --- a/test/fixtures/versions.yml +++ b/test/fixtures/versions.yml @@ -1,29 +1,71 @@ ---- -versions_001: - created_on: 2006-07-19 21:00:07 +02:00 - name: "0.1" - project_id: 1 - updated_on: 2006-07-19 21:00:07 +02:00 - id: 1 - description: Beta - effective_date: 2006-07-01 - status: closed -versions_002: - created_on: 2006-07-19 21:00:33 +02:00 - name: "1.0" - project_id: 1 - updated_on: 2006-07-19 21:00:33 +02:00 - id: 2 - description: Stable release - effective_date: <%= 20.day.from_now.to_date.to_s(:db) %> - status: locked -versions_003: - created_on: 2006-07-19 21:00:33 +02:00 - name: "2.0" - project_id: 1 - updated_on: 2006-07-19 21:00:33 +02:00 - id: 3 - description: Future version - effective_date: - status: open - \ No newline at end of file +--- +versions_001: + created_on: 2006-07-19 21:00:07 +02:00 + name: "0.1" + project_id: 1 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 1 + description: Beta + effective_date: 2006-07-01 + status: closed + shared: 'none' +versions_002: + created_on: 2006-07-19 21:00:33 +02:00 + name: "1.0" + project_id: 1 + updated_on: 2006-07-19 21:00:33 +02:00 + id: 2 + description: Stable release + effective_date: <%= 20.day.from_now.to_date.to_s(:db) %> + status: locked + shared: 'none' +versions_003: + created_on: 2006-07-19 21:00:33 +02:00 + name: "2.0" + project_id: 1 + updated_on: 2006-07-19 21:00:33 +02:00 + id: 3 + description: Future version + effective_date: + status: open + shared: 'none' +versions_004: + created_on: 2006-07-19 21:00:33 +02:00 + name: "2.0" + project_id: 3 + updated_on: 2006-07-19 21:00:33 +02:00 + id: 4 + description: Future version on subproject + effective_date: + status: open + shared: 'hierarchy' +versions_005: + created_on: 2006-07-19 21:00:07 +02:00 + name: "Alpha" + project_id: 2 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 5 + description: Private Alpha + effective_date: 2006-07-01 + status: open + shared: 'none' +versions_006: + created_on: 2006-07-19 21:00:07 +02:00 + name: "Private Version of public subproject" + project_id: 5 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 6 + description: "Should be done any day now..." + effective_date: + status: open + shared: 'hierarchy' +versions_007: + created_on: 2006-07-19 21:00:07 +02:00 + name: "Systemwide visible version" + project_id: 2 + updated_on: 2006-07-19 21:00:07 +02:00 + id: 7 + description: + effective_date: + status: open + shared: 'system' diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 93e2995..768189f 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -925,6 +925,22 @@ class IssuesControllerTest < ActionController::TestCase assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" } end + def test_post_edit_should_allow_fixed_version_to_be_set_to_a_subproject + issue = Issue.find(2) + @request.session[:user_id] = 2 + + post :edit, + :id => issue.id, + :issue => { + :fixed_version_id => 4 + } + + assert_response :redirect + issue.reload + assert_equal 4, issue.fixed_version_id + assert_not_equal issue.project_id, issue.fixed_version.project_id + end + def test_get_bulk_edit @request.session[:user_id] = 2 get :bulk_edit, :ids => [1, 2] @@ -1005,6 +1021,21 @@ class IssuesControllerTest < ActionController::TestCase assert_nil Issue.find(2).assigned_to end + def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject + @request.session[:user_id] = 2 + + post :bulk_edit, + :ids => [1,2], + :fixed_version_id => 4 + + assert_response :redirect + issues = Issue.find([1,2]) + issues.each do |issue| + assert_equal 4, issue.fixed_version_id + assert_not_equal issue.project_id, issue.fixed_version.project_id + end + end + def test_move_routing assert_routing( {:method => :get, :path => '/issues/1/move'}, @@ -1080,6 +1111,17 @@ class IssuesControllerTest < ActionController::TestCase assert_tag :tag => 'a', :content => 'Immediate', :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&priority_id=8', :class => '' } + # Versions + assert_tag :tag => 'a', :content => 'eCookbook - 0.1', + :attributes => { :href => '/issues/bulk_edit?fixed_version_id=1&ids%5B%5D=1', + :class => '' } + assert_tag :tag => 'a', :content => 'eCookbook - 1.0', + :attributes => { :href => '/issues/bulk_edit?fixed_version_id=2&ids%5B%5D=1', + :class => '' } + assert_tag :tag => 'a', :content => 'eCookbook Subproject 1 - 2.0', + :attributes => { :href => '/issues/bulk_edit?fixed_version_id=4&ids%5B%5D=1', + :class => '' } + assert_tag :tag => 'a', :content => 'Dave Lopper', :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1', :class => '' } diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb index 6704d4f..1c49d0e 100644 --- a/test/functional/projects_controller_test.rb +++ b/test/functional/projects_controller_test.rb @@ -343,6 +343,16 @@ class ProjectsControllerTest < ActionController::TestCase :attributes => { :href => '/attachments/download/9/version_file.zip' } end + def test_list_files_with_shared_versions + get :list_files, :id => 1 + assert_response :success + assert_not_nil assigns(:containers) + + # file attached to a subproject's version + assert_tag :a, :content => 'version_file.zip', + :attributes => { :href => '/attachments/download/12/version_file.zip' } + end + def test_list_files_routing assert_routing( {:method => :get, :path => '/projects/33/files'}, @@ -364,6 +374,15 @@ class ProjectsControllerTest < ActionController::TestCase assert_not_nil assigns(:versions) end + def test_changelog_showing_shared_versions + get :changelog, :id => 1, :shared_versions => 1 + assert_response :success + assert_template 'changelog' + assert_not_nil assigns(:versions) + # Version on subproject appears + assert assigns(:versions).include?(Version.find(4)) + end + def test_roadmap_routing assert_routing( {:method => :get, :path => 'projects/33/roadmap'}, @@ -392,6 +411,15 @@ class ProjectsControllerTest < ActionController::TestCase # Completed version appears assert assigns(:versions).include?(Version.find(1)) end + + def test_roadmap_showing_shared_versions + get :roadmap, :id => 1, :shared_versions => 1 + assert_response :success + assert_template 'roadmap' + assert_not_nil assigns(:versions) + # Version on subproject appears + assert assigns(:versions).include?(Version.find(4)) + end def test_project_activity_routing assert_routing( diff --git a/test/integration/account_test.rb b/test/integration/account_test.rb index c612ea2..f82e681 100644 --- a/test/integration/account_test.rb +++ b/test/integration/account_test.rb @@ -24,7 +24,7 @@ rescue end class AccountTest < ActionController::IntegrationTest - fixtures :users + fixtures :users, :roles # Replace this with your real tests. def test_login diff --git a/test/test_helper.rb b/test/test_helper.rb index 07d4af7..4b8e03d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -49,6 +49,7 @@ class ActiveSupport::TestCase # Add more helper methods to be used by all tests here... def log_user(login, password) + User.anonymous get "/login" assert_equal nil, session[:user_id] assert_response :success diff --git a/test/unit/enumeration_test.rb b/test/unit/enumeration_test.rb index abb1535..d9d3307 100644 --- a/test/unit/enumeration_test.rb +++ b/test/unit/enumeration_test.rb @@ -25,7 +25,7 @@ class EnumerationTest < ActiveSupport::TestCase def test_objects_count # low priority - assert_equal 5, Enumeration.find(4).objects_count + assert_equal 6, Enumeration.find(4).objects_count # urgent assert_equal 0, Enumeration.find(7).objects_count end @@ -79,7 +79,7 @@ class EnumerationTest < ActiveSupport::TestCase def test_destroy_with_reassign Enumeration.find(4).destroy(Enumeration.find(6)) assert_nil Issue.find(:first, :conditions => {:priority_id => 4}) - assert_equal 5, Enumeration.find(6).objects_count + assert_equal 6, Enumeration.find(6).objects_count end def test_should_be_customizable diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index 90eaed4..fecf2b2 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -32,6 +32,21 @@ class ApplicationHelperTest < HelperTestCase def setup super end + + def test_format_version_name_is_authorized + User.current = User.find(1) + assert_equal "eCookbook - 0.1", format_version_name(Version.find(1)) + end + + def test_format_version_name_is_unauthorized + User.current = User.find(3) + assert_equal "You are not authorized to view this.", format_version_name(Version.find(5)) + end + + def test_format_version_name_for_system_version + User.current = User.find(3) + assert_equal "OnlineStore - Systemwide visible version", format_version_name(Version.find(7)) + end def test_auto_links to_test = { @@ -135,7 +150,7 @@ RAW def test_redmine_links issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3}, - :class => 'issue status-1 priority-1 overdue', :title => 'Error 281 when updating a recipe (New)') + :class => 'issue status-1 priority-1 overdue assigned-to-me', :title => 'Error 281 when updating a recipe (New)') changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1}, :class => 'changeset', :title => 'My very first commit') diff --git a/test/unit/helpers/projects_helper_test.rb b/test/unit/helpers/projects_helper_test.rb new file mode 100644 index 0000000..3b379a9 --- /dev/null +++ b/test/unit/helpers/projects_helper_test.rb @@ -0,0 +1,44 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../../test_helper' + +class ProjectsHelperTest < HelperTestCase + include ApplicationHelper + include ProjectsHelper + + fixtures :all + + def setup + super + set_language_if_valid('en') + end + + def test_link_to_version + User.current = User.find(1) + assert_equal 'eCookbook - 0.1', link_to_version(Version.find(1)) + end + + def test_link_to_version_invalid_version + assert_equal '', link_to_version(Object) + end + + def test_link_to_version_unauthorized + User.current = User.find(3) + assert_equal "You are not authorized to view this.", link_to_version(Version.find(5)) + end +end diff --git a/test/unit/issue_priority_test.rb b/test/unit/issue_priority_test.rb index 6574bf3..51a6b82 100644 --- a/test/unit/issue_priority_test.rb +++ b/test/unit/issue_priority_test.rb @@ -26,7 +26,7 @@ class IssuePriorityTest < ActiveSupport::TestCase def test_objects_count # low priority - assert_equal 5, IssuePriority.find(4).objects_count + assert_equal 6, IssuePriority.find(4).objects_count # urgent assert_equal 0, IssuePriority.find(7).objects_count end diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index afde6c7..5adad60 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -329,6 +329,46 @@ class IssueTest < ActiveSupport::TestCase assert_nil issue.category_id end + def test_move_to_another_project_should_clear_fixed_version_when_not_shared + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 1) + assert issue.move_to(Project.find(2)) + issue.reload + assert_equal 2, issue.project_id + # Cleared fixed_version + assert_equal nil, issue.fixed_version + end + + def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 4) + assert issue.move_to(Project.find(5)) + issue.reload + assert_equal 5, issue.project_id + # Keep fixed_version + assert_equal 4, issue.fixed_version_id + end + + def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 1) + assert issue.move_to(Project.find(5)) + issue.reload + assert_equal 5, issue.project_id + # Cleared fixed_version + assert_equal nil, issue.fixed_version + end + + def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide + issue = Issue.find(1) + issue.update_attribute(:fixed_version_id, 7) + assert issue.move_to(Project.find(2)) + issue.reload + assert_equal 2, issue.project_id + # Keep fixed_version + assert_equal 7, issue.fixed_version_id + end + def test_copy_to_the_same_project issue = Issue.find(1) copy = nil diff --git a/test/unit/mailer_test.rb b/test/unit/mailer_test.rb index b8ff4f0..4395156 100644 --- a/test/unit/mailer_test.rb +++ b/test/unit/mailer_test.rb @@ -256,4 +256,23 @@ class MailerTest < ActiveSupport::TestCase assert mail.bcc.include?('dlopper@somenet.foo') assert mail.body.include?('Bug #3: Error 281 when updating a recipe') end + + def test_issue_edit_should_not_show_private_version_changes_if_any_recipients_are_unauthorized + Setting.default_language = 'en' + # Move issue to a public project but with a Journal showing a + # Private Version + issue = Issue.find(6) + issue.update_attribute(:project_id, 1) + + # User is allowed to see the Private Version + User.current = User.find(1) + # but another Member of Project #1 is not (dlopper@somenet.foo) + + journal = Journal.find(4) + Mailer.deliver_issue_edit(journal) + mail = ActionMailer::Base.deliveries.last + + assert !mail.body.include?('Private Version of public subproject'), "Private version exposed to unauthorized user" + assert mail.body.include?('You are not authorized to view this.'), "Unauthorized message not displayed" + end end diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb index 93e4bbf..8dbd8ce 100644 --- a/test/unit/project_test.rb +++ b/test/unit/project_test.rb @@ -21,7 +21,7 @@ class ProjectTest < ActiveSupport::TestCase fixtures :projects, :enabled_modules, :issues, :issue_statuses, :journals, :journal_details, :users, :members, :member_roles, :roles, :projects_trackers, :trackers, :boards, - :queries + :queries, :versions def setup @ecookbook = Project.find(1) @@ -206,6 +206,38 @@ class ProjectTest < ActiveSupport::TestCase assert_equal 4, parent.children.size assert_equal parent.children.sort_by(&:name), parent.children end + + + def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy + # Parent issue with a hierarchy project's fixed version + parent_issue = Issue.find(1) + parent_issue.update_attribute(:fixed_version_id, 4) + parent_issue.reload + assert_equal 4, parent_issue.fixed_version_id + + # Should keep fixed versions for the issues + issue_with_local_fixed_version = Issue.find(5) + issue_with_local_fixed_version.update_attribute(:fixed_version_id, 4) + issue_with_local_fixed_version.reload + assert_equal 4, issue_with_local_fixed_version.fixed_version_id + + # Local issue with hierarchy fixed_version + issue_with_hierarchy_fixed_version = Issue.find(13) + issue_with_hierarchy_fixed_version.update_attribute(:fixed_version_id, 6) + issue_with_hierarchy_fixed_version.reload + assert_equal 6, issue_with_hierarchy_fixed_version.fixed_version_id + + # Move project out of the issue's hierarchy + moved_project = Project.find(3) + moved_project.set_parent!(Project.find(2)) + parent_issue.reload + issue_with_local_fixed_version.reload + issue_with_hierarchy_fixed_version.reload + + assert_equal 4, issue_with_local_fixed_version.fixed_version_id, "Fixed version was not keep on an issue local to the moved project" + assert_equal nil, issue_with_hierarchy_fixed_version.fixed_version_id, "Fixed version is still set after moving the Project out of the hierarchy where the version is defined in" + assert_equal nil, parent_issue.fixed_version_id, "Fixed version is still set after moving the Version out of the hierarchy for the issue." + end def test_parent p = Project.find(6).parent @@ -277,13 +309,61 @@ class ProjectTest < ActiveSupport::TestCase assert_equal [1,2], parent.rolled_up_trackers.collect(&:id) end + + def test_shared_versions + parent = Project.find(1) + child = parent.children.find(3) + private_child = parent.children.find(5) + + assert_equal [1,2,3], parent.version_ids.sort + assert_equal [4], child.version_ids + assert_equal [6], private_child.version_ids + assert_equal [7], Version.find_all_by_shared('system').collect(&:id) + + assert_equal 6, parent.shared_versions.size + parent.shared_versions.each do |version| + assert_kind_of Version, version + end + + assert_equal [1,2,3,4,6,7], parent.shared_versions.collect(&:id).sort + end + + def test_shared_versions_should_ignore_archived_subprojects + parent = Project.find(1) + child = parent.children.find(3) + child.archive + parent.reload + + assert_equal [1,2,3], parent.version_ids.sort + assert_equal [4], child.version_ids + assert !parent.shared_versions.collect(&:id).include?(4) + end + + def test_shared_versions_visible_to_user + user = User.find(3) + parent = Project.find(1) + child = parent.children.find(5) + + assert_equal [1,2,3], parent.version_ids.sort + assert_equal [6], child.version_ids + + versions = parent.shared_versions_visible_to_user(user) + + assert_equal 4, versions.size + versions.each do |version| + assert_kind_of Version, version + end + + assert !versions.collect(&:id).include?(6) + end + def test_next_identifier ProjectCustomField.delete_all Project.create!(:name => 'last', :identifier => 'p2008040') assert_equal 'p2008041', Project.next_identifier end - + def test_next_identifier_first_project Project.delete_all assert_nil Project.next_identifier @@ -429,13 +509,15 @@ class ProjectTest < ActiveSupport::TestCase end should "change the new issues to use the copied version" do - assigned_version = Version.generate!(:name => "Assigned Issues") + User.current = User.find(1) + assigned_version = Version.generate!(:name => "Assigned Issues", :status => 'open') @source_project.versions << assigned_version - assert_equal 1, @source_project.versions.size - @source_project.issues << Issue.generate!(:fixed_version_id => assigned_version.id, - :subject => "change the new issues to use the copied version", - :tracker_id => 1, - :project_id => @source_project.id) + assert_equal 3, @source_project.versions.size + Issue.generate_for_project!(@source_project, + :fixed_version_id => assigned_version.id, + :subject => "change the new issues to use the copied version", + :tracker_id => 1, + :project_id => @source_project.id) assert @project.copy(@source_project) @project.reload diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index 31d3cd1..2044747 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -31,6 +31,14 @@ class QueryTest < ActiveSupport::TestCase :include => [ :assigned_to, :status, :tracker, :project, :priority ], :conditions => query.statement end + + def test_query_should_allow_shared_versions_for_a_project_query + subproject_version = Version.find(4) + query = Query.new(:project => Project.find(1), :name => '_') + query.add_filter('fixed_version_id', '=', [subproject_version.id.to_s]) + + assert query.statement.include?("#{Issue.table_name}.fixed_version_id IN ('4')") + end def test_query_with_multiple_custom_fields query = Query.find(1) diff --git a/test/unit/version_test.rb b/test/unit/version_test.rb index 5702fd1..f05b7ed 100644 --- a/test/unit/version_test.rb +++ b/test/unit/version_test.rb @@ -104,6 +104,47 @@ class VersionTest < ActiveSupport::TestCase assert_progress_equal (25.0*0.2 + 25.0*1 + 10.0*0.3 + 40.0*0.1)/100.0*100, v.completed_pourcent assert_progress_equal 25.0/100.0*100, v.closed_pourcent end + + def test_systemwide + assert !Version.find(1).systemwide? # not shared + assert !Version.find(4).systemwide? # hierarchy + assert Version.find(7).systemwide? # system + end + + test "should update all issue's fixed_version associations in case the hierarchy changed XXX" do + User.current = User.find(1) # Need the admin's permissions + + @version = Version.find(7) + # Separate hierarchy + project_1_issue = Issue.find(1) + project_1_issue.fixed_version = @version + assert project_1_issue.save, project_1_issue.errors.full_messages + + project_5_issue = Issue.find(6) + project_5_issue.fixed_version = @version + assert project_5_issue.save + + # Project + project_2_issue = Issue.find(4) + project_2_issue.fixed_version = @version + assert project_2_issue.save + + # Update the sharing + @version.shared = 'none' + assert @version.save + + # Project 1 now out of the shared scope + project_1_issue.reload + assert_equal nil, project_1_issue.fixed_version, "Fixed version is still set after changing the Version's sharing" + + # Project 5 now out of the shared scope + project_5_issue.reload + assert_equal nil, project_5_issue.fixed_version, "Fixed version is still set after changing the Version's sharing" + + # Project 2 issue remains + project_2_issue.reload + assert_equal @version, project_2_issue.fixed_version + end private -- 1.6.5