diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/controllers/issues_controller.rb --- a/app/controllers/issues_controller.rb Sun Jun 15 14:27:25 2008 +0200 +++ b/app/controllers/issues_controller.rb Fri Jun 27 13:12:14 2008 +0200 @@ -20,6 +20,7 @@ class IssuesController < ApplicationCont menu_item :new_issue, :only => :new before_filter :find_issue, :only => [:show, :edit, :destroy_attachment] + before_filter :check_issue_perms, :only => [:show, :edit] before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] before_filter :find_project, :only => [:new, :update_form, :preview] before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu] @@ -28,7 +29,7 @@ class IssuesController < ApplicationCont helper :journals helper :projects - include ProjectsHelper + include ProjectsHelper helper :custom_fields include CustomFieldsHelper helper :ifpdf @@ -63,6 +64,7 @@ class IssuesController < ApplicationCont :conditions => @query.statement, :limit => limit, :offset => @issue_pages.current.offset + @issues.map!{ |issue| issue_without_hidden_fields(issue) } # don't show forbidden fields respond_to do |format| format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? } format.atom { render_feed(@issues, :title => l(:label_issue_plural)) } @@ -100,6 +102,8 @@ class IssuesController < ApplicationCont @journals.reverse! if User.current.wants_comments_in_reverse_order? @allowed_statuses = @issue.new_statuses_allowed_to(User.current) @edit_allowed = User.current.allowed_to?(:edit_issues, @project) + @issue = issue_without_hidden_fields(@issue) + @journals = journals_without_hidden_entries(@journals) @activities = Enumeration::get_values('ACTI') @priorities = Enumeration::get_values('IPRI') @time_entry = TimeEntry.new @@ -388,6 +392,54 @@ private render_404 end + + + def issue_fixed_version_allowed?(issue) + ((not issue.fixed_version) || + (User.current.allowed_to?(:view_issues, + issue.fixed_version.project))) + end + + def check_issue_perms + @forbidden_fixed_version = (not issue_fixed_version_allowed?(@issue)) + end + + ## Filter journals to remove non allowed entries. This assumes there + ## is only 1 parent, so it won't work with more depth. We want here + ## to handle the _specific case_ of a user 'Joe' browsing 'Project + ## B' issues. 'Project B' is a subproject of 'Project A' and + ## inherits its versions. Joe can't see 'Project A, but issue + ## fixed_versions has been set at some point to a version belonging + ## to 'Project A', by an other member of 'Project B'. Joe should not + ## see this sensitive information. + def journals_without_hidden_entries(journals) + unless (journals.empty? || (not @project.parent_id) || + (@project.parent_id && User.current.allowed_to?(:view_issues, @project.parent))) + journals = journals.dup + # we kill totally the journal entry when some of its elements are forbidden + journals.delete_if do |j| + j.details.map{ |d| (d.property == 'attr' && + d.prop_key == 'fixed_version_id' && + ((d.old_value && + (@project.parent_id == Version.find(d.old_value.to_i).project_id)) || + (d.value && + (@project.parent_id == Version.find(d.value.to_i).project_id))) + ) }.include?(true) + end + end + journals + end + + ## Filter issue to remove non allowed fields. For more information, + ## see documentation of journals_without_hidden_entries + def issue_without_hidden_fields(issue) + unless issue_fixed_version_allowed?(issue) + issue = issue.dup + issue.fixed_version = nil + end + issue + end + # Retrieve query from session or build a new query def retrieve_query if !params[:query_id].blank? diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/controllers/projects_controller.rb --- a/app/controllers/projects_controller.rb Sun Jun 15 14:27:25 2008 +0200 +++ b/app/controllers/projects_controller.rb Fri Jun 27 13:12:14 2008 +0200 @@ -195,18 +195,18 @@ class ProjectsController < ApplicationCo def add_file if request.post? - @version = @project.versions.find_by_id(params[:version_id]) + @version = @project.related_versions.find_by_id(params[:version_id]) attachments = attach_files(@version, params[:attachments]) Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('file_added') redirect_to :controller => 'projects', :action => 'list_files', :id => @project end - @versions = @project.versions.sort + @versions = @project.related_versions.sort end def list_files sort_init "#{Attachment.table_name}.filename", "asc" sort_update - @versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse + @versions = @project.related_versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse render :layout => !request.xhr? end @@ -214,14 +214,14 @@ class ProjectsController < ApplicationCo def changelog @trackers = @project.trackers.find(:all, :conditions => ["is_in_chlog=?", true], :order => 'position') retrieve_selected_tracker_ids(@trackers) - @versions = @project.versions.sort + @versions = @project.related_versions.sort end def roadmap @trackers = @project.trackers.find(:all, :conditions => ["is_in_roadmap=?", true]) retrieve_selected_tracker_ids(@trackers) - @versions = @project.versions.sort - @versions = @versions.select {|v| !v.completed? } unless params[:completed] + # retrieve_related_versions could be integrated right here. + @versions = retrieve_related_versions end def activity @@ -342,8 +342,12 @@ class ProjectsController < ApplicationCo :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?)) AND #{Issue.table_name}.tracker_id IN (#{@selected_tracker_ids.join(',')})", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] ) unless @selected_tracker_ids.empty? events += Version.find(:all, :include => :project, - :conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) + :conditions => { :effective_date => @calendar.startdt..@calendar.enddt}) end + # add parent versions if relevant + events += @project.related_versions.select{ |v| ((v.project_id == @project.parent_id) && + v.effective_date) } + @calendar.events = events render :layout => false if request.xhr? @@ -390,6 +394,11 @@ class ProjectsController < ApplicationCo @events += Version.find(:all, :include => :project, :conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to]) end + + # add parent versions if relevant + @events += @project.related_versions.select{ |v| ((v.project_id == @project.parent_id) && + v.effective_date) } + @events.sort! {|x,y| x.start_date <=> y.start_date } if params[:format]=='pdf' @@ -423,6 +432,12 @@ private render_404 end + def retrieve_related_versions + related_versions=@project.related_versions + # should this test be moved to projects_helper.rb : version_visible_issues ? + params[:completed] ? related_versions : related_versions.select {|v| !v.completed? } + end + def retrieve_selected_tracker_ids(selectable_trackers) if ids = params[:tracker_ids] @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/controllers/reports_controller.rb --- a/app/controllers/reports_controller.rb Sun Jun 15 14:27:25 2008 +0200 +++ b/app/controllers/reports_controller.rb Fri Jun 27 13:12:14 2008 +0200 @@ -32,7 +32,7 @@ class ReportsController < ApplicationCon render :template => "reports/issue_report_details" when "version" @field = "fixed_version_id" - @rows = @project.versions.sort + @rows = @project.related_versions.sort @data = issues_by_version @report_title = l(:field_version) render :template => "reports/issue_report_details" @@ -68,7 +68,7 @@ class ReportsController < ApplicationCon render :template => "reports/issue_report_details" else @trackers = @project.trackers - @versions = @project.versions.sort + @versions = @project.related_versions.sort @priorities = Enumeration::get_values('IPRI') @categories = @project.issue_categories @assignees = @project.members.collect { |m| m.user } diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/controllers/versions_controller.rb --- a/app/controllers/versions_controller.rb Sun Jun 15 14:27:25 2008 +0200 +++ b/app/controllers/versions_controller.rb Fri Jun 27 13:12:14 2008 +0200 @@ -20,7 +20,11 @@ class VersionsController < ApplicationCo menu_item :roadmap before_filter :find_project, :authorize + helper :projects + include ProjectsHelper + def show + @issues = version_visible_issues(@version,@project,@project.tracker_ids) end def edit diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/helpers/projects_helper.rb --- a/app/helpers/projects_helper.rb Sun Jun 15 14:27:25 2008 +0200 +++ b/app/helpers/projects_helper.rb Fri Jun 27 13:12:14 2008 +0200 @@ -46,6 +46,27 @@ module ProjectsHelper tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} end + ## return an array of the issues attached to version that a user should see + ## As a convenience, allow limitation by trackers with Array of tracker_ids + def version_visible_issues(version,project,tracker_ids=[],user=User.current) + # Returns void when user can not see issues or if tracker_ids is void + return [] if ((not user.allowed_to?(:view_issues, + version.project)) or + tracker_ids.empty?) + # user can see project issues, carry on, retrieve them ... + issues = version. + fixed_issues.find(:all, + :include => [:status, :tracker], + :conditions => ["tracker_id in (#{tracker_ids.join(',')})"], + :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") + # Only keep issues from self, parent or children, + related_projects=[project.id].concat(project.child_ids) # project and children + related_projects.push project.parent.id if project.parent # parent if relevant + related_projects = related_projects.select{|x| user.allowed_to?(:view_issues, Project.find(x))} + # now only keep related issues. (issues from brother projects are discarded) + issues.select {|x| related_projects.include?(x.project.id) } + end + # Generates a gantt image # Only defined if RMagick is avalaible def gantt_image(events, date_from, months, zoom) diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/models/project.rb --- a/app/models/project.rb Sun Jun 15 14:27:25 2008 +0200 +++ b/app/models/project.rb Fri Jun 27 13:12:14 2008 +0200 @@ -237,6 +237,18 @@ class Project < ActiveRecord::Base end end + ## Return versions attached to self, and to parent if relevant. + ## Sorting is done in the SQL request to take advantage of cache + def related_versions(user=User.current) + Version.find(:all, + :conditions => {:project_id => if self.parent && + user.allowed_to?(:view_issues, + self.parent) then + [self.id, self.parent_id] + else [self.id]; end}, + :order => "effective_date ASC, name ASC ") + end + protected def validate errors.add(parent_id, " must be a root project") if parent and parent.parent diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/models/query.rb --- a/app/models/query.rb Sun Jun 15 14:27:25 2008 +0200 +++ b/app/models/query.rb Fri Jun 27 13:12:14 2008 +0200 @@ -168,7 +168,7 @@ class Query < ActiveRecord::Base if project # project specific filters @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } } - @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } } + @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.related_versions.sort.collect{|s| [s.name, s.id.to_s] } } unless @project.active_children.empty? @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.active_children.collect{|s| [s.name, s.id.to_s] } } end diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/views/issues/_form.rhtml --- a/app/views/issues/_form.rhtml Sun Jun 15 14:27:25 2008 +0200 +++ b/app/views/issues/_form.rhtml Fri Jun 27 13:12:14 2008 +0200 @@ -29,9 +29,11 @@ l(:label_issue_category_new), 'category[name]', {:controller => 'projects', :action => 'add_issue_category', :id => @project}, :class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %>
-<%= content_tag('p', f.select(:fixed_version_id, - (@project.versions.sort.collect {|v| [v.name, v.id]}), - { :include_blank => true })) unless @project.versions.empty? %> +<%= unless (@project.related_versions.empty? || @forbidden_fixed_version) then + content_tag('p', f.select(:fixed_version_id, + (@project.related_versions.sort.collect {|v| [v.name, v.id]}), + { :include_blank => true })) + end %><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>
-<%= content_tag('p', f.select(:fixed_version_id, - (@project.versions.sort.collect {|v| [v.name, v.id]}), - { :include_blank => true })) unless @project.versions.empty? %> +<%= unless (@issue.fixed_version && + (not User.current.allowed_to?(:view_issues, + @issue.fixed_version.project)) || + @project.related_versions.empty?) then + content_tag('p', f.select(:fixed_version_id, + (@project.related_versions.sort.collect {|v| [v.name, v.id]}), + { :include_blank => true })) + end %>diff -r c3db7e7d7ce3 -r 8a2b5b43c23a app/views/projects/roadmap.rhtml --- a/app/views/projects/roadmap.rhtml Sun Jun 15 14:27:25 2008 +0200 +++ b/app/views/projects/roadmap.rhtml Fri Jun 27 13:12:14 2008 +0200 @@ -1,50 +1,50 @@
<%= l(:label_no_data) %>
+<%= l(:label_no_data) %>
<% else %> -<%= submit_tag l(:button_apply), :class => 'button-small' %>
<% end %> -<% end %> -<%= submit_tag l(:button_apply), :class => 'button-small' %>
-<% end %> - -