Mercurial > hg > soundsoftware-site
diff app/models/project.rb @ 441:cbce1fd3b1b7 redmine-1.2
Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author | Chris Cannam |
---|---|
date | Mon, 06 Jun 2011 14:24:13 +0100 |
parents | 8661b858af72 |
children | 753f1380d6bc 0c939c159af4 |
line wrap: on
line diff
--- a/app/models/project.rb Thu Mar 03 11:42:28 2011 +0000 +++ b/app/models/project.rb Mon Jun 06 14:24:13 2011 +0100 @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 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 @@ -43,7 +43,7 @@ has_many :time_entries, :dependent => :delete_all has_many :queries, :dependent => :delete_all has_many :documents, :dependent => :destroy - has_many :news, :dependent => :delete_all, :include => :author + has_many :news, :dependent => :destroy, :include => :author has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name" has_many :boards, :dependent => :destroy, :order => "position ASC" has_one :repository, :dependent => :destroy @@ -56,7 +56,7 @@ :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id' - acts_as_nested_set :order => 'name' + acts_as_nested_set :order => 'name', :dependent => :destroy acts_as_attachable :view_permission => :view_files, :delete_permission => :manage_files @@ -79,12 +79,12 @@ # reserved words validates_exclusion_of :identifier, :in => %w( new ) - before_destroy :delete_all_members, :destroy_children + before_destroy :delete_all_members named_scope :has_module, lambda { |mod| { :conditions => ["#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s] } } named_scope :active, { :conditions => "#{Project.table_name}.status = #{STATUS_ACTIVE}"} named_scope :all_public, { :conditions => { :is_public => true } } - named_scope :visible, lambda { { :conditions => Project.visible_by(User.current) } } + named_scope :visible, lambda {|*args| {:conditions => Project.visible_condition(args.shift || User.current, *args) }} def initialize(attributes = nil) super @@ -115,27 +115,31 @@ # returns latest created projects # non public projects will be returned only if user is a member of those def self.latest(user=nil, count=5) - find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC") + visible(user).find(:all, :limit => count, :order => "created_on DESC") end - # Returns a SQL :conditions string used to find all active projects for the specified user. + def self.visible_by(user=nil) + ActiveSupport::Deprecation.warn "Project.visible_by is deprecated and will be removed in Redmine 1.3.0. Use Project.visible_condition instead." + visible_condition(user || User.current) + end + + # Returns a SQL conditions string used to find all projects visible by the specified user. # # Examples: - # Projects.visible_by(admin) => "projects.status = 1" - # Projects.visible_by(normal_user) => "projects.status = 1 AND projects.is_public = 1" - def self.visible_by(user=nil) - user ||= User.current - if user && user.admin? - return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}" - elsif user && user.memberships.any? - return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = #{connection.quoted_true} or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))" - else - return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}" - end + # Project.visible_condition(admin) => "projects.status = 1" + # Project.visible_condition(normal_user) => "((projects.status = 1) AND (projects.is_public = 1 OR projects.id IN (1,3,4)))" + # Project.visible_condition(anonymous) => "((projects.status = 1) AND (projects.is_public = 1))" + def self.visible_condition(user, options={}) + allowed_to_condition(user, :view_project, options) end + # Returns a SQL conditions string used to find all projects for which +user+ has the given +permission+ + # + # Valid options: + # * :project => limit the condition to project + # * :with_subprojects => limit the condition to project and its subprojects + # * :member => limit the condition to the user projects def self.allowed_to_condition(user, permission, options={}) - statements = [] base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}" if perm = Redmine::AccessControl.permission(permission) unless perm.project_module.nil? @@ -148,24 +152,37 @@ project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects] base_statement = "(#{project_statement}) AND (#{base_statement})" end + if user.admin? - # no restriction + base_statement else - statements << "1=0" + statement_by_role = {} + unless options[:member] + role = user.logged? ? Role.non_member : Role.anonymous + if role.allowed_to?(permission) + statement_by_role[role] = "#{Project.table_name}.is_public = #{connection.quoted_true}" + end + end if user.logged? - if Role.non_member.allowed_to?(permission) && !options[:member] - statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" + user.projects_by_role.each do |role, projects| + if role.allowed_to?(permission) + statement_by_role[role] = "#{Project.table_name}.id IN (#{projects.collect(&:id).join(',')})" + end end - allowed_project_ids = user.memberships.select {|m| m.roles.detect {|role| role.allowed_to?(permission)}}.collect {|m| m.project_id} - statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any? + end + if statement_by_role.empty? + "1=0" else - if Role.anonymous.allowed_to?(permission) && !options[:member] - # anonymous user allowed on public project - statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" - end + if block_given? + statement_by_role.each do |role, statement| + if s = yield(role, user) + statement_by_role[role] = "(#{statement} AND (#{s}))" + end + end + end + "((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))" end end - statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))" end # Returns the Systemwide and project specific activities @@ -347,7 +364,7 @@ # Returns an array of the trackers used by the project and its active sub projects def rolled_up_trackers @rolled_up_trackers ||= - Tracker.find(:all, :include => :projects, + Tracker.find(:all, :joins => :projects, :select => "DISTINCT #{Tracker.table_name}.*", :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt], :order => "#{Tracker.table_name}.position") @@ -373,15 +390,17 @@ # Returns a scope of the Versions used by the project def shared_versions - @shared_versions ||= + @shared_versions ||= begin + r = root? ? self : root Version.scoped(:include => :project, :conditions => "#{Project.table_name}.id = #{id}" + " OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" + " #{Version.table_name}.sharing = 'system'" + - " OR (#{Project.table_name}.lft >= #{root.lft} AND #{Project.table_name}.rgt <= #{root.rgt} AND #{Version.table_name}.sharing = 'tree')" + + " OR (#{Project.table_name}.lft >= #{r.lft} AND #{Project.table_name}.rgt <= #{r.rgt} AND #{Version.table_name}.sharing = 'tree')" + " OR (#{Project.table_name}.lft < #{lft} AND #{Project.table_name}.rgt > #{rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" + " OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt} AND #{Version.table_name}.sharing = 'hierarchy')" + "))") + end end # Returns a hash of project users grouped by role @@ -423,6 +442,12 @@ def all_issue_custom_fields @all_issue_custom_fields ||= (IssueCustomField.for_all + issue_custom_fields).uniq.sort end + + # Returns an array of all custom fields enabled for project time entries + # (explictly associated custom fields and custom fields enabled for all projects) + def all_time_entry_custom_fields + @all_time_entry_custom_fields ||= (TimeEntryCustomField.for_all + time_entry_custom_fields).uniq.sort + end def project self @@ -509,10 +534,7 @@ def enabled_module_names=(module_names) if module_names && module_names.is_a?(Array) module_names = module_names.collect(&:to_s).reject(&:blank?) - # remove disabled modules - enabled_modules.each {|mod| mod.destroy unless module_names.include?(mod.name)} - # add new modules - module_names.reject {|name| module_enabled?(name)}.each {|name| enabled_modules << EnabledModule.new(:name => name)} + self.enabled_modules = module_names.collect {|name| enabled_modules.detect {|mod| mod.name == name} || EnabledModule.new(:name => name)} else enabled_modules.clear end @@ -621,13 +643,6 @@ private - # Destroys children before destroying self - def destroy_children - children.each do |child| - child.destroy - end - end - # Copies wiki from +project+ def copy_wiki(project) # Check that the source project has a wiki first @@ -674,6 +689,7 @@ end # Copies issues from +project+ + # Note: issues assigned to a closed version won't be copied due to validation rules def copy_issues(project) # Stores the source issue id as a key and the copied issues as the # value. Used to map the two togeather for issue relations.