##// END OF EJS Templates
Fixed that projects are not ordered alphabetically after renaming project (#11508)....
Fixed that projects are not ordered alphabetically after renaming project (#11508). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@10187 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r10004:e52219f09d23
r10004:e52219f09d23
Show More
project.rb
956 lines | 34.1 KiB | text/x-ruby | RubyLexer
Jean-Philippe Lang
Changed the way the visibility SQL statement is built....
r5020 # Redmine - project management software
Jean-Philippe Lang
Copyright update....
r9453 # Copyright (C) 2006-2012 Jean-Philippe Lang
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 #
# 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.
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397 #
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # 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.
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397 #
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # 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.
class Project < ActiveRecord::Base
Jean-Philippe Lang
Declare safe attributes for User and Projects models....
r4378 include Redmine::SafeAttributes
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Added the ability to archive projects:...
r546 # Project statuses
STATUS_ACTIVE = 1
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 STATUS_CLOSED = 5
Jean-Philippe Lang
Added the ability to archive projects:...
r546 STATUS_ARCHIVED = 9
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Raised maximum length of project names and identifiers to 255 and 100 respectively (#6446)....
r4288 # Maximum length for project identifiers
IDENTIFIER_MAX_LENGTH = 100
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
Added a Activities tab to Project Settings...
r2835 # Specific overidden Activities
Jean-Philippe Lang
Changes misleading scopes on Enumeration....
r2969 has_many :time_entry_activities
Jean-Philippe Lang
Load roles when loading project members....
r2964 has_many :members, :include => [:user, :roles], :conditions => "#{User.table_name}.type='User' AND #{User.table_name}.status=#{User::STATUS_ACTIVE}"
Jean-Philippe Lang
Fixed: project copy doesn't copy group memberships (#3975)....
r3136 has_many :memberships, :class_name => 'Member'
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397 has_many :member_principals, :class_name => 'Member',
Jean-Philippe Lang
User groups branch merged....
r2755 :include => :principal,
:conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{User::STATUS_ACTIVE})"
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 has_many :users, :through => :members
Jean-Philippe Lang
User groups branch merged....
r2755 has_many :principals, :through => :member_principals, :source => :principal
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Added project module concept....
r714 has_many :enabled_modules, :dependent => :delete_all
Jean-Philippe Lang
Added per-project tracker selection. Trackers can be selected on project settings....
r907 has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
Jean-Philippe Lang
Removed sort order on issues association....
r8955 has_many :issues, :dependent => :destroy, :include => [:status, :tracker]
Jean-Philippe Lang
Activity view improvements:...
r640 has_many :issue_changes, :through => :issues, :source => :journals
Jean-Philippe Lang
Fixed an error when trying to delete a project (versions/issues dependency)...
r571 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
Jean-Philippe Lang
Simple time tracking functionality added. Time can be logged at issue or project level....
r365 has_many :time_entries, :dependent => :delete_all
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 has_many :queries, :dependent => :delete_all
has_many :documents, :dependent => :destroy
Jean-Philippe Lang
Fixed: news comments not deleted when deleting a project (#7904)....
r5056 has_many :news, :dependent => :destroy, :include => :author
Jean-Philippe Lang
fixed #9308 table_name pre/suffix support...
r334 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
Jean-Philippe Lang
Fixed: Boards are not deleted when project is deleted (closes #963)....
r1301 has_many :boards, :dependent => :destroy, :order => "position ASC"
Jean-Philippe Lang
Adds support for multiple repositories per project (#779)....
r8530 has_one :repository, :conditions => ["is_default = ?", true]
has_many :repositories, :dependent => :destroy
Jean-Philippe Lang
Improved Redmine links:...
r703 has_many :changesets, :through => :repository
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 has_one :wiki, :dependent => :destroy
Jean-Philippe Lang
Custom fields can now be reordered....
r888 # Custom field for the project issues
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397 has_and_belongs_to_many :issue_custom_fields,
Jean-Philippe Lang
Custom fields can now be reordered....
r888 :class_name => 'IssueCustomField',
:order => "#{CustomField.table_name}.position",
:join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
:association_foreign_key => 'custom_field_id'
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Fixed: children projects are deleted instead of being destroyed when destroying parent project (#7904)....
r5051 acts_as_nested_set :order => 'name', :dependent => :destroy
Jean-Philippe Lang
Files module: makes version field non required (#1053)....
r2115 acts_as_attachable :view_permission => :view_files,
:delete_permission => :manage_files
Jean-Philippe Lang
Search engines now supports pagination....
r755
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 acts_as_customizable
Jean-Philippe Lang
Makes project identifiers searchable (#4897)....
r3367 acts_as_searchable :columns => ['name', 'identifier', 'description'], :project_key => 'id', :permission => nil
Jean-Philippe Lang
Search engines now supports pagination....
r755 acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"},
Jean-Philippe Lang
Fixed: projects are referenced by id in search results....
r3368 :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o}},
Jean-Philippe Lang
Fixed: no :author method error on projects atom feed (#1623)....
r1639 :author => nil
Jean-Philippe Lang
Search engines now supports pagination....
r755
Jean-Philippe Lang
Moves enabled_module_names param to project attribute so that it can be set through the Project API....
r4525 attr_protected :status
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Unlimited and optional project description. The project list will show truncated descriptions only (the first fews lines)....
r1074 validates_presence_of :name, :identifier
Jean-Philippe Lang
Allow non-unique names for projects (#630)....
r4277 validates_uniqueness_of :identifier
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 validates_associated :repository, :wiki
Jean-Philippe Lang
Raised maximum length of project names and identifiers to 255 and 100 respectively (#6446)....
r4288 validates_length_of :name, :maximum => 255
Jean-Philippe Lang
Change projects homepage limit to 255 chars (#663, #1095)....
r1443 validates_length_of :homepage, :maximum => 255
Jean-Philippe Lang
Raised maximum length of project names and identifiers to 255 and 100 respectively (#6446)....
r4288 validates_length_of :identifier, :in => 1..IDENTIFIER_MAX_LENGTH
Jean-Philippe Lang
Validate project identifier only when changed (#3352)....
r2663 # donwcase letters, digits, dashes but not digits only
Jean-Philippe Lang
Allow underscores in project identifiers (#1363)....
r8588 validates_format_of :identifier, :with => /^(?!\d+$)[a-z0-9\-_]*$/, :if => Proc.new { |p| p.identifier_changed? }
Jean-Philippe Lang
Prevent creation of project with identifier 'new' (#3602)....
r2716 # reserved words
validates_exclusion_of :identifier, :in => %w( new )
Jean-Philippe Lang
Fixed that projects are not ordered alphabetically after renaming project (#11508)....
r10004 after_save :update_position_under_parent, :if => Proc.new {|project| project.name_changed?}
Jean-Philippe Lang
Fixed: children projects are deleted instead of being destroyed when destroying parent project (#7904)....
r5051 before_destroy :delete_all_members
Jean-Philippe Lang
Merged nbc branch @ r1812 (commit access permission and reposman improvements)....
r1812
Toshi MARUYAMA
model: replace Rails2 "named_scope" to Rails3 "scope"...
r9355 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] } }
scope :active, { :conditions => "#{Project.table_name}.status = #{STATUS_ACTIVE}"}
scope :status, lambda {|arg| arg.blank? ? {} : {:conditions => {:status => arg.to_i}} }
scope :all_public, { :conditions => { :is_public => true } }
scope :visible, lambda {|*args| {:conditions => Project.visible_condition(args.shift || User.current, *args) }}
scope :allowed_to, lambda {|*args|
Jean-Philippe Lang
Enable global time logging at /time_entries/new (#10020)....
r8571 user = User.current
permission = nil
if args.first.is_a?(Symbol)
permission = args.shift
else
user = args.shift
permission = args.shift
end
{ :conditions => Project.allowed_to_condition(user, permission, *args) }
}
Toshi MARUYAMA
model: replace Rails2 "named_scope" to Rails3 "scope"...
r9355 scope :like, lambda {|arg|
Jean-Philippe Lang
Adds named scopes for projects index....
r7962 if arg.blank?
{}
else
pattern = "%#{arg.to_s.strip.downcase}%"
{:conditions => ["LOWER(identifier) LIKE :p OR LOWER(name) LIKE :p", {:p => pattern}]}
end
}
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Makes models #initialize accept additional arguments....
r8167 def initialize(attributes=nil, *args)
Jean-Philippe Lang
Moves project attributes default assignments from ProjectsController#new to the model (#6064)....
r4346 super
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Moves project attributes default assignments from ProjectsController#new to the model (#6064)....
r4346 initialized = (attributes || {}).stringify_keys
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397 if !initialized.key?('identifier') && Setting.sequential_project_identifiers?
Jean-Philippe Lang
Moves project attributes default assignments from ProjectsController#new to the model (#6064)....
r4346 self.identifier = Project.next_identifier
end
if !initialized.key?('is_public')
self.is_public = Setting.default_projects_public?
end
if !initialized.key?('enabled_module_names')
self.enabled_module_names = Setting.default_projects_modules
end
if !initialized.key?('trackers') && !initialized.key?('tracker_ids')
Jean-Philippe Lang
Code cleanup....
r9531 self.trackers = Tracker.sorted.all
Jean-Philippe Lang
Moves project attributes default assignments from ProjectsController#new to the model (#6064)....
r4346 end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Initial commit for svn repository management and access control:...
r393 def identifier=(identifier)
super unless identifier_frozen?
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Initial commit for svn repository management and access control:...
r393 def identifier_frozen?
Jean-Philippe Lang
Fixed that project identifier can always be updated (#11028)....
r9527 errors[:identifier].blank? && !(new_record? || identifier.blank?)
Jean-Philippe Lang
Initial commit for svn repository management and access control:...
r393 end
Jean-Philippe Lang
Added issues status changes on the activity view (initial patch by Cyril Mougel)....
r879
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # 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)
Jean-Philippe Lang
Makes visible scopes accept projects option and deprecate Project.visible_by....
r5204 visible(user).find(:all, :limit => count, :order => "created_on DESC")
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Adds visibility condition on parent project in API....
r6084 # Returns true if the project is visible to +user+ or to the current user.
def visible?(user=User.current)
user.allowed_to?(:view_project, self)
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Makes visible scopes accept projects option and deprecate Project.visible_by....
r5204 # Returns a SQL conditions string used to find all projects visible by the specified user.
Eric Davis
Added some RDoc documentation for some models....
r2536 #
# Examples:
Jean-Philippe Lang
Makes visible scopes accept projects option and deprecate Project.visible_by....
r5204 # 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)
Jean-Philippe Lang
Added the ability to archive projects:...
r546 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Makes visible scopes accept projects option and deprecate Project.visible_by....
r5204 # 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
Jean-Philippe Lang
Activity enhancements:...
r1213 def self.allowed_to_condition(user, permission, options={})
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 perm = Redmine::AccessControl.permission(permission)
base_statement = (perm && perm.read? ? "#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED}" : "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}")
if perm && perm.project_module
# If the permission belongs to a project module, make sure the module is enabled
base_statement << " AND #{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.project_module}')"
Jean-Philippe Lang
Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled....
r1905 end
Jean-Philippe Lang
Activity enhancements:...
r1213 if options[:project]
project_statement = "#{Project.table_name}.id = #{options[:project].id}"
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects]
Jean-Philippe Lang
Activity enhancements:...
r1213 base_statement = "(#{project_statement}) AND (#{base_statement})"
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Propagates time tracking to the parent project (closes #433). Time report enhancements....
r1162 if user.admin?
Jean-Philippe Lang
Changed the way the visibility SQL statement is built....
r5020 base_statement
Jean-Philippe Lang
Propagates time tracking to the parent project (closes #433). Time report enhancements....
r1162 else
Jean-Philippe Lang
Changed the way the visibility SQL statement is built....
r5020 statement_by_role = {}
Jean-Philippe Lang
Code cleanup....
r5339 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}"
Jean-Philippe Lang
Changed the way the visibility SQL statement is built....
r5020 end
Jean-Philippe Lang
Code cleanup....
r5339 end
if user.logged?
Jean-Philippe Lang
Changed the way the visibility SQL statement is built....
r5020 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
Jean-Philippe Lang
Allow non admin users to add subprojects (#2963)....
r2945 end
Jean-Philippe Lang
Fixed: search engine may reveal private projects (#1613)....
r1635 end
Jean-Philippe Lang
Changed the way the visibility SQL statement is built....
r5020 if statement_by_role.empty?
"1=0"
else
Jean-Philippe Lang
Adds an issues visibility level on roles (#7412)....
r5296 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
Jean-Philippe Lang
Changed the way the visibility SQL statement is built....
r5020 "((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))"
end
Jean-Philippe Lang
Propagates time tracking to the parent project (closes #433). Time report enhancements....
r1162 end
end
Eric Davis
Added some RDoc documentation for some models....
r2536
Eric Davis
Added a Activities tab to Project Settings...
r2835 # Returns the Systemwide and project specific activities
def activities(include_inactive=false)
if include_inactive
return all_activities
else
return active_activities
end
end
Eric Davis
Changed the Timelogs to use both the Systemwide and Project specific TimeEntryActivities...
r2834
Eric Davis
When a specific TimeEntryActivity are change, associated TimeEntries will be...
r2836 # Will create a new Project specific Activity or update an existing one
#
# This will raise a ActiveRecord::Rollback if the TimeEntryActivity
# does not successfully save.
def update_or_create_time_entry_activity(id, activity_hash)
Eric Davis
Added a Activities tab to Project Settings...
r2835 if activity_hash.respond_to?(:has_key?) && activity_hash.has_key?('parent_id')
Eric Davis
When a specific TimeEntryActivity are change, associated TimeEntries will be...
r2836 self.create_time_entry_activity_if_needed(activity_hash)
Eric Davis
Changed the Timelogs to use both the Systemwide and Project specific TimeEntryActivities...
r2834 else
Eric Davis
Added a Activities tab to Project Settings...
r2835 activity = project.time_entry_activities.find_by_id(id.to_i)
activity.update_attributes(activity_hash) if activity
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
When a specific TimeEntryActivity are change, associated TimeEntries will be...
r2836 # Create a new TimeEntryActivity if it overrides a system TimeEntryActivity
#
# This will raise a ActiveRecord::Rollback if the TimeEntryActivity
# does not successfully save.
def create_time_entry_activity_if_needed(activity)
Eric Davis
Added a Activities tab to Project Settings...
r2835 if activity['parent_id']
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
Added a Activities tab to Project Settings...
r2835 parent_activity = TimeEntryActivity.find(activity['parent_id'])
activity['name'] = parent_activity.name
activity['position'] = parent_activity.position
if Enumeration.overridding_change?(activity, parent_activity)
Eric Davis
When a specific TimeEntryActivity are change, associated TimeEntries will be...
r2836 project_activity = self.time_entry_activities.create(activity)
if project_activity.new_record?
raise ActiveRecord::Rollback, "Overridding TimeEntryActivity was not successfully saved"
else
self.time_entries.update_all("activity_id = #{project_activity.id}", ["activity_id = ?", parent_activity.id])
end
Eric Davis
Added a Activities tab to Project Settings...
r2835 end
Eric Davis
Changed the Timelogs to use both the Systemwide and Project specific TimeEntryActivities...
r2834 end
end
Eric Davis
Added some RDoc documentation for some models....
r2536 # Returns a :conditions SQL string that can be used to find the issues associated with this project.
#
# Examples:
# project.project_condition(true) => "(projects.id = 1 OR (projects.lft > 1 AND projects.rgt < 10))"
# project.project_condition(false) => "projects.id = 1"
Jean-Philippe Lang
If 'Display subprojects issues on main projects' is set to false:...
r1283 def project_condition(with_subprojects)
cond = "#{Project.table_name}.id = #{id}"
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects
Jean-Philippe Lang
If 'Display subprojects issues on main projects' is set to false:...
r1283 cond
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Project identifier is now used in URLs (instead of project id)....
r994 def self.find(*args)
if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/)
project = find_by_identifier(*args)
raise ActiveRecord::RecordNotFound, "Couldn't find Project with identifier=#{args.first}" if project.nil?
project
else
super
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Merged rails-3.2 branch....
r9346 def self.find_by_param(*args)
self.find(*args)
end
Jean-Philippe Lang
Cleanup instance variables when reloading a project....
r8859 def reload(*args)
@shared_versions = nil
@rolled_up_versions = nil
@rolled_up_trackers = nil
@all_issue_custom_fields = nil
@all_time_entry_custom_fields = nil
@to_param = nil
@allowed_parents = nil
@allowed_permissions = nil
@actions_allowed = nil
super
end
Jean-Philippe Lang
Project identifier is now used in URLs (instead of project id)....
r994 def to_param
Jean-Philippe Lang
Fixed: can not access old projects created with a numeric identifier (#1322)....
r1459 # id is used for projects with a numeric identifier (compatibility)
Jean-Philippe Lang
Fixed "can't convert Fixnum into String" error on projects with numerical identifier (#10135)....
r8684 @to_param ||= (identifier.to_s =~ %r{^\d*$} ? id.to_s : identifier)
Jean-Philippe Lang
Project identifier is now used in URLs (instead of project id)....
r994 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Added the ability to archive projects:...
r546 def active?
self.status == STATUS_ACTIVE
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Improved error message when trying to access an archived project (#2995)....
r4171 def archived?
self.status == STATUS_ARCHIVED
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 # Archives the project and its descendants
Jean-Philippe Lang
Added the ability to archive projects:...
r546 def archive
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 # Check that there is no issue of a non descendant project that is assigned
# to one of the project or descendant versions
v_ids = self_and_descendants.collect {|p| p.version_ids}.flatten
if v_ids.any? && Issue.find(:first, :include => :project,
:conditions => ["(#{Project.table_name}.lft < ? OR #{Project.table_name}.rgt > ?)" +
" AND #{Issue.table_name}.fixed_version_id IN (?)", lft, rgt, v_ids])
return false
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 Project.transaction do
archive!
end
true
Jean-Philippe Lang
Added the ability to archive projects:...
r546 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 # Unarchives the project
# All its ancestors must be active
Jean-Philippe Lang
Added the ability to archive projects:...
r546 def unarchive
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 return false if ancestors.detect {|a| !a.active?}
Jean-Philippe Lang
Added the ability to archive projects:...
r546 update_attribute :status, STATUS_ACTIVE
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 def close
self_and_descendants.status(STATUS_ACTIVE).update_all :status => STATUS_CLOSED
end
def reopen
self_and_descendants.status(STATUS_CLOSED).update_all :status => STATUS_ACTIVE
end
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 # Returns an array of projects the project can be moved to
Jean-Philippe Lang
Allow non admin users to add subprojects (#2963)....
r2945 # by the current user
def allowed_parents
return @allowed_parents if @allowed_parents
Jean-Philippe Lang
Adds a 'Add subprojects' permission....
r3124 @allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects))
@allowed_parents = @allowed_parents - self_and_descendants
Jean-Philippe Lang
Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project (#4790)....
r3291 if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?)
Jean-Philippe Lang
Adds a 'Add subprojects' permission....
r3124 @allowed_parents << nil
end
Jean-Philippe Lang
Allow non admin users to add subprojects (#2963)....
r2945 unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent)
@allowed_parents << parent
end
@allowed_parents
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Allow non admin users to add subprojects (#2963)....
r2945 # Sets the parent of the project with authorization check
def set_allowed_parent!(p)
unless p.nil? || p.is_a?(Project)
if p.to_s.blank?
p = nil
else
p = Project.find_by_id(p)
return false unless p
end
end
if p.nil?
if !new_record? && allowed_parents.empty?
return false
end
elsif !allowed_parents.include?(p)
return false
end
set_parent!(p)
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 # Sets the parent of the project
# Argument can be either a Project, a String, a Fixnum or nil
def set_parent!(p)
unless p.nil? || p.is_a?(Project)
if p.to_s.blank?
p = nil
else
p = Project.find_by_id(p)
return false unless p
end
end
if p == parent && !p.nil?
# Nothing to do
true
elsif p.nil? || (p.active? && move_possible?(p))
Jean-Philippe Lang
Fixed that projects are not ordered alphabetically after renaming project (#11508)....
r10004 set_or_update_position_under(p)
Jean-Philippe Lang
Optimize updates of issue's shared versions....
r3023 Issue.update_versions_from_hierarchy_change(self)
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 true
else
# Can not move to the given target
false
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Ignore archived subprojects in Project#rolled_up_trackers (#2550)....
r2309 # Returns an array of the trackers used by the project and its active sub projects
Jean-Philippe Lang
On the calendar, the gantt and in the Tracker filter on the issue list, only active trackers of the project (and its sub projects) can be selected....
r1057 def rolled_up_trackers
@rolled_up_trackers ||=
Jean-Philippe Lang
Do not load projects association in #rolled_up_trackers....
r5173 Tracker.find(:all, :joins => :projects,
Jean-Philippe Lang
On the calendar, the gantt and in the Tracker filter on the issue list, only active trackers of the project (and its sub projects) can be selected....
r1057 :select => "DISTINCT #{Tracker.table_name}.*",
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt],
Jean-Philippe Lang
On the calendar, the gantt and in the Tracker filter on the issue list, only active trackers of the project (and its sub projects) can be selected....
r1057 :order => "#{Tracker.table_name}.position")
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Adds a link to automatically close completed versions in project settings (#1245)....
r2909 # Closes open and locked project versions that are completed
def close_completed_versions
Version.transaction do
versions.find(:all, :conditions => {:status => %w(open locked)}).each do |version|
if version.completed?
version.update_attribute(:status, 'closed')
end
end
end
end
Eric Davis
Show subproject versions on the Roadmap....
r3646
# Returns a scope of the Versions on subprojects
def rolled_up_versions
@rolled_up_versions ||=
Version.scoped(:include => :project,
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt])
Eric Davis
Show subproject versions on the Roadmap....
r3646 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 # Returns a scope of the Versions used by the project
def shared_versions
Jean-Philippe Lang
Fixed: error when creating a project with a version format custom field (#10218)....
r8745 if new_record?
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 Version.scoped(:include => :project,
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 :conditions => "#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND #{Version.table_name}.sharing = 'system'")
Jean-Philippe Lang
Fixed: error when creating a project with a version format custom field (#10218)....
r8745 else
@shared_versions ||= begin
r = root? ? self : root
Version.scoped(:include => :project,
:conditions => "#{Project.table_name}.id = #{id}" +
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 " OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" +
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 " #{Version.table_name}.sharing = 'system'" +
Jean-Philippe Lang
Save 1 query + 1 cache hit in #shared_versions for root projects....
r5123 " OR (#{Project.table_name}.lft >= #{r.lft} AND #{Project.table_name}.rgt <= #{r.rgt} AND #{Version.table_name}.sharing = 'tree')" +
Jean-Philippe Lang
Fixes Project#shared_versions for descendants sharing (#465)....
r3016 " 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')" +
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 "))")
Jean-Philippe Lang
Fixed: error when creating a project with a version format custom field (#10218)....
r8745 end
Jean-Philippe Lang
Save 1 query + 1 cache hit in #shared_versions for root projects....
r5123 end
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 end
Jean-Philippe Lang
Display all users roles on project overview (#3339)....
r2635 # Returns a hash of project users grouped by role
def users_by_role
members.find(:all, :include => [:user, :roles]).inject({}) do |h, m|
m.roles.each do |r|
h[r] ||= []
h[r] << m.user
end
h
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Merged Rails 2.0 compatibility changes....
r962 # Deletes all project's members
def delete_all_members
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 me, mr = Member.table_name, MemberRole.table_name
connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})")
Jean-Philippe Lang
Merged Rails 2.0 compatibility changes....
r962 Member.delete_all(['project_id = ?', id])
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 # Users/groups issues can be assigned to
Jean-Philippe Lang
Added 'Bulk edit' functionality....
r806 def assignable_users
Jean-Philippe Lang
Ability to assign issues to groups (#2964)....
r6186 assignable = Setting.issue_group_assignment? ? member_principals : members
assignable.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.principal}.sort
Jean-Philippe Lang
Added 'Bulk edit' functionality....
r806 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
More flexible mail notifications settings at user level. A user has now 3 options:...
r842 # Returns the mail adresses of users that should be always notified on project events
def recipients
Eric Davis
Change Project#notified_users to check for the 'all' notification option. #6541...
r4133 notified_users.collect {|user| user.mail}
Jean-Philippe Lang
More flexible mail notifications settings at user level. A user has now 3 options:...
r842 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Do not notify users that are no longer allowed to view an issue (#3589, #4263)....
r3007 # Returns the users that should be notified on project events
def notified_users
Eric Davis
Change Project#notified_users to check for the 'all' notification option. #6541...
r4133 # TODO: User part should be extracted to User#notify_about?
members.select {|m| m.mail_notification? || m.user.mail_notification == 'all'}.collect {|m| m.user}
Jean-Philippe Lang
Do not notify users that are no longer allowed to view an issue (#3589, #4263)....
r3007 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # Returns an array of all custom fields enabled for project issues
# (explictly associated custom fields and custom fields enabled for all projects)
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 def all_issue_custom_fields
Jean-Philippe Lang
Fixes custom fields display order at several places (#1768)....
r1730 @all_issue_custom_fields ||= (IssueCustomField.for_all + issue_custom_fields).uniq.sort
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Toshi MARUYAMA
add bulk edit and bulk update actions for time entries (#7996)....
r5193
# 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
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Ability to search all projects or the projects the user belongs to (#791)....
r1420 def project
self
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Subprojects are now grouped by projects in the 'Projects' top navigation drop-down menu....
r692 def <=>(project)
Jean-Philippe Lang
* Added time zone support: users can select their time zone on their account view....
r904 name.downcase <=> project.name.downcase
Jean-Philippe Lang
Subprojects are now grouped by projects in the 'Projects' top navigation drop-down menu....
r692 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Unlimited and optional project description. The project list will show truncated descriptions only (the first fews lines)....
r1074 def to_s
name
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Unlimited and optional project description. The project list will show truncated descriptions only (the first fews lines)....
r1074 # Returns a short description of the projects (first lines)
def short_description(length = 255)
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description
Jean-Philippe Lang
Unlimited and optional project description. The project list will show truncated descriptions only (the first fews lines)....
r1074 end
Eric Davis
Rewrite the Gantt chart. #6276...
r3958
Eric Davis
Refactor: move method to Project#css_classes...
r3966 def css_classes
s = 'project'
s << ' root' if root?
s << ' child' if child?
s << (leaf? ? ' leaf' : ' parent')
Jean-Philippe Lang
Ability to close projects (read-only) (#3640)....
r9700 unless active?
if archived?
s << ' archived'
else
s << ' closed'
end
end
Eric Davis
Refactor: move method to Project#css_classes...
r3966 s
end
Eric Davis
Rewrite the Gantt chart. #6276...
r3958 # The earliest start date of a project, based on it's issues and versions
def start_date
Jean-Philippe Lang
Select projects with issue_tracking module for gantt display and remove the nil start/due dates trick....
r4363 [
issues.minimum('start_date'),
shared_versions.collect(&:effective_date),
Jean-Philippe Lang
Makes Version#start_date return the minimum start_date of its issues....
r4460 shared_versions.collect(&:start_date)
Jean-Philippe Lang
Select projects with issue_tracking module for gantt display and remove the nil start/due dates trick....
r4363 ].flatten.compact.min
Eric Davis
Rewrite the Gantt chart. #6276...
r3958 end
Eric Davis
Revert "Fixed: gantt broken when no due date on project issues and versions."...
r4070 # The latest due date of an issue or version
Eric Davis
Rewrite the Gantt chart. #6276...
r3958 def due_date
Jean-Philippe Lang
Select projects with issue_tracking module for gantt display and remove the nil start/due dates trick....
r4363 [
issues.maximum('due_date'),
shared_versions.collect(&:effective_date),
shared_versions.collect {|v| v.fixed_issues.maximum('due_date')}
].flatten.compact.max
Eric Davis
Rewrite the Gantt chart. #6276...
r3958 end
def overdue?
active? && !due_date.nil? && (due_date < Date.today)
end
# Returns the percent completed for this project, based on the
# progress on it's versions.
def completed_percent(options={:include_subprojects => false})
if options.delete(:include_subprojects)
total = self_and_descendants.collect(&:completed_percent).sum
total / self_and_descendants.count
else
if versions.count > 0
total = versions.collect(&:completed_pourcent).sum
total / versions.count
else
100
end
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Moved logic relative to project status from User to Project model (#3640)....
r9703 # Return true if this project allows to do the specified action.
Eric Davis
Added some RDoc documentation for some models....
r2536 # action can be:
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
# * a permission Symbol (eg. :edit_project)
Jean-Philippe Lang
Added project module concept....
r714 def allows_to?(action)
Jean-Philippe Lang
Moved logic relative to project status from User to Project model (#3640)....
r9703 if archived?
# No action allowed on archived projects
return false
end
unless active? || Redmine::AccessControl.read_action?(action)
# No write action allowed on closed projects
return false
end
# No action allowed on disabled modules
Jean-Philippe Lang
Added project module concept....
r714 if action.is_a? Hash
allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
else
allowed_permissions.include? action
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Added project module concept....
r714 def module_enabled?(module_name)
module_name = module_name.to_s
enabled_modules.detect {|m| m.name == module_name}
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Added project module concept....
r714 def enabled_module_names=(module_names)
Jean-Philippe Lang
Do not DELETE/INSERT enabled_modules when updating project modules....
r2412 if module_names && module_names.is_a?(Array)
Jean-Philippe Lang
Moves project attributes default assignments from ProjectsController#new to the model (#6064)....
r4346 module_names = module_names.collect(&:to_s).reject(&:blank?)
Jean-Philippe Lang
Modules selection lost on project form after validation failure (#8012)....
r5145 self.enabled_modules = module_names.collect {|name| enabled_modules.detect {|mod| mod.name == name} || EnabledModule.new(:name => name)}
Jean-Philippe Lang
Do not DELETE/INSERT enabled_modules when updating project modules....
r2412 else
enabled_modules.clear
Jean-Philippe Lang
Added project module concept....
r714 end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Moves project attributes default assignments from ProjectsController#new to the model (#6064)....
r4346 # Returns an array of the enabled modules names
def enabled_module_names
enabled_modules.collect(&:name)
end
Jean-Baptiste Barth
Added Project#enable_module! and Project#disable_module! (#7115)...
r5978
# Enable a specific module
#
# Examples:
# project.enable_module!(:issue_tracking)
# project.enable_module!("issue_tracking")
def enable_module!(name)
enabled_modules << EnabledModule.new(:name => name.to_s) unless module_enabled?(name)
end
# Disable a module if it exists
#
# Examples:
# project.disable_module!(:issue_tracking)
# project.disable_module!("issue_tracking")
# project.disable_module!(project.enabled_modules.first)
def disable_module!(target)
target = enabled_modules.detect{|mod| target.to_s == mod.name} unless enabled_modules.include?(target)
target.destroy unless target.blank?
end
Jean-Philippe Lang
Declare safe attributes for User and Projects models....
r4378 safe_attributes 'name',
'description',
'homepage',
'is_public',
'identifier',
'custom_field_values',
'custom_fields',
Jean-Philippe Lang
Fixed: r4492 breaks the ability to select issue custom fields available for projects issues (#7121)....
r4415 'tracker_ids',
'issue_custom_field_ids'
Eric Davis
Change the TimelogController's to/from dates based on the project time entries...
r3973
Jean-Philippe Lang
Moves enabled_module_names param to project attribute so that it can be set through the Project API....
r4525 safe_attributes 'enabled_module_names',
:if => lambda {|project, user| project.new_record? || user.allowed_to?(:select_project_modules, project) }
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
Change the TimelogController's to/from dates based on the project time entries...
r3973 # Returns an array of projects that are in this project's hierarchy
#
# Example: parents, children, siblings
def hierarchy
parents = project.self_and_ancestors || []
descendants = project.descendants || []
project_hierarchy = parents | descendants # Set union
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Adds an option to generate sequential project identifiers....
r1776 # Returns an auto-generated project identifier based on the last identifier used
def self.next_identifier
p = Project.find(:first, :order => 'created_on DESC')
p.nil? ? nil : p.identifier.to_s.succ
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608 # Copies and saves the Project instance based on the +project+.
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 # Duplicates the source project's:
# * Wiki
# * Versions
# * Categories
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608 # * Issues
# * Members
# * Queries
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 #
# Accepts an +options+ argument to specify what to copy
#
# Examples:
# project.copy(1) # => copies everything
# project.copy(1, :only => 'members') # => copies members only
# project.copy(1, :only => ['members', 'versions']) # => copies members and versions
def copy(project, options={})
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608 project = project.is_a?(Project) ? project : Project.find(project)
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Allow project forums copy....
r2862 to_be_copied = %w(wiki versions issue_categories issues members queries boards)
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil?
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 Project.transaction do
Jean-Philippe Lang
Fixes project wiki copy....
r2855 if save
reload
to_be_copied.each do |name|
send "copy_#{name}", project
end
Redmine::Hook.call_hook(:model_project_copy_before_save, :source_project => project, :destination_project => self)
save
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608 end
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608 # Copies +project+ and returns the new instance. This will not save
# the copy
def self.copy_from(project)
begin
project = project.is_a?(Project) ? project : Project.find(project)
if project
# clear unique attributes
Jean-Philippe Lang
Prevent mass-assignment warnings....
r2859 attributes = project.attributes.dup.except('id', 'name', 'identifier', 'status', 'parent_id', 'lft', 'rgt')
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608 copy = Project.new(attributes)
copy.enabled_modules = project.enabled_modules
copy.trackers = project.trackers
copy.custom_values = project.custom_values.collect {|v| v.clone}
Eric Davis
Preselect the issue custom fields from the source project when copying. #4045...
r2819 copy.issue_custom_fields = project.issue_custom_fields
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608 return copy
else
return nil
end
rescue ActiveRecord::RecordNotFound
return nil
end
end
Eric Davis
Refactor: move method to model with compatibility wrapper...
r4168
# Yields the given block for each project with its level in the tree
def self.project_tree(projects, &block)
ancestors = []
projects.sort_by(&:lft).each do |project|
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397 while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
Eric Davis
Refactor: move method to model with compatibility wrapper...
r4168 ancestors.pop
end
yield project, ancestors.size
ancestors << project
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 private
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 # Copies wiki from +project+
def copy_wiki(project)
Jean-Philippe Lang
Fixes project wiki copy....
r2855 # Check that the source project has a wiki first
unless project.wiki.nil?
self.wiki ||= Wiki.new
Jean-Philippe Lang
Prevent mass-assignment warnings....
r2857 wiki.attributes = project.wiki.attributes.dup.except("id", "project_id")
Jean-Philippe Lang
Fixed: Project copy loses wiki pages hierarchy (#4797)....
r3298 wiki_pages_map = {}
Jean-Philippe Lang
Fixes project wiki copy....
r2855 project.wiki.pages.each do |page|
Jean-Philippe Lang
Fixed: Project copy loses wiki pages hierarchy (#4797)....
r3298 # Skip pages without content
next if page.content.nil?
Jean-Philippe Lang
Reset timestamps and wiki page hierarchy on project copy....
r2858 new_wiki_content = WikiContent.new(page.content.attributes.dup.except("id", "page_id", "updated_on"))
new_wiki_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id"))
Jean-Philippe Lang
Fixes project wiki copy....
r2855 new_wiki_page.content = new_wiki_content
wiki.pages << new_wiki_page
Jean-Philippe Lang
Fixed: Project copy loses wiki pages hierarchy (#4797)....
r3298 wiki_pages_map[page.id] = new_wiki_page
end
wiki.save
# Reproduce page hierarchy
project.wiki.pages.each do |page|
if page.parent_id && wiki_pages_map[page.id]
wiki_pages_map[page.id].parent = wiki_pages_map[page.parent_id]
wiki_pages_map[page.id].save
end
Jean-Philippe Lang
Fixes project wiki copy....
r2855 end
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 end
end
# Copies versions from +project+
def copy_versions(project)
project.versions.each do |version|
new_version = Version.new
Jean-Philippe Lang
Reset timestamps and wiki page hierarchy on project copy....
r2858 new_version.attributes = version.attributes.dup.except("id", "project_id", "created_on", "updated_on")
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 self.versions << new_version
end
end
# Copies issue categories from +project+
def copy_issue_categories(project)
project.issue_categories.each do |issue_category|
new_issue_category = IssueCategory.new
Jean-Philippe Lang
Prevent mass-assignment warnings....
r2857 new_issue_category.attributes = issue_category.attributes.dup.except("id", "project_id")
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 self.issue_categories << new_issue_category
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 # Copies issues from +project+
Jean-Philippe Lang
Adds functional test for project copy....
r5235 # Note: issues assigned to a closed version won't be copied due to validation rules
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 def copy_issues(project)
Eric Davis
Copy issue relations when copying a project. (#3367)...
r3050 # Stores the source issue id as a key and the copied issues as the
# value. Used to map the two togeather for issue relations.
issues_map = {}
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # Get issues sorted by root_id, lft so that parent issues
# get copied before their children
project.issues.find(:all, :order => 'root_id, lft').each do |issue|
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 new_issue = Issue.new
new_issue.copy_from(issue)
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 new_issue.project = self
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 # Reassign fixed_versions by name, since names are unique per
# project and the versions for self are not yet saved
if issue.fixed_version
new_issue.fixed_version = self.versions.select {|v| v.name == issue.fixed_version.name}.first
end
# Reassign the category by name, since names are unique per
# project and the categories for self are not yet saved
if issue.category
new_issue.category = self.issue_categories.select {|c| c.name == issue.category.name}.first
end
Jean-Philippe Lang
Adds subtasking (#443) including:...
r3459 # Parent issue
if issue.parent_id
if copied_parent = issues_map[issue.parent_id]
new_issue.parent_issue_id = copied_parent.id
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 self.issues << new_issue
Jean-Philippe Lang
Do not try to copy relations for issues that could not be copied....
r4370 if new_issue.new_record?
logger.info "Project#copy_issues: issue ##{issue.id} could not be copied: #{new_issue.errors.full_messages}" if logger && logger.info
else
issues_map[issue.id] = new_issue unless new_issue.new_record?
end
Eric Davis
Copy issue relations when copying a project. (#3367)...
r3050 end
# Relations after in case issues related each other
project.issues.each do |issue|
new_issue = issues_map[issue.id]
Jean-Philippe Lang
Do not try to copy relations for issues that could not be copied....
r4370 unless new_issue
# Issue was not copied
next
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
Copy issue relations when copying a project. (#3367)...
r3050 # Relations
issue.relations_from.each do |source_relation|
new_issue_relation = IssueRelation.new
new_issue_relation.attributes = source_relation.attributes.dup.except("id", "issue_from_id", "issue_to_id")
new_issue_relation.issue_to = issues_map[source_relation.issue_to_id]
if new_issue_relation.issue_to.nil? && Setting.cross_project_issue_relations?
new_issue_relation.issue_to = source_relation.issue_to
end
new_issue.relations_from << new_issue_relation
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
Copy issue relations when copying a project. (#3367)...
r3050 issue.relations_to.each do |source_relation|
new_issue_relation = IssueRelation.new
new_issue_relation.attributes = source_relation.attributes.dup.except("id", "issue_from_id", "issue_to_id")
new_issue_relation.issue_from = issues_map[source_relation.issue_from_id]
if new_issue_relation.issue_from.nil? && Setting.cross_project_issue_relations?
new_issue_relation.issue_from = source_relation.issue_from
end
new_issue.relations_to << new_issue_relation
end
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 end
end
# Copies members from +project+
def copy_members(project)
Jean-Philippe Lang
Additional roles of a user who belongs to a group are not always copied when copying the project (#7213)....
r4495 # Copy users first, then groups to handle members with inherited and given roles
members_to_copy = []
members_to_copy += project.memberships.select {|m| m.principal.is_a?(User)}
members_to_copy += project.memberships.select {|m| !m.principal.is_a?(User)}
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Additional roles of a user who belongs to a group are not always copied when copying the project (#7213)....
r4495 members_to_copy.each do |member|
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 new_member = Member.new
Jean-Philippe Lang
Reset timestamps and wiki page hierarchy on project copy....
r2858 new_member.attributes = member.attributes.dup.except("id", "project_id", "created_on")
Jean-Philippe Lang
Fixed: project copy doesn't copy group memberships (#3975)....
r3136 # only copy non inherited roles
# inherited roles will be added when copying the group membership
role_ids = member.member_roles.reject(&:inherited?).collect(&:role_id)
next if role_ids.empty?
new_member.role_ids = role_ids
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 new_member.project = self
self.members << new_member
end
end
# Copies queries from +project+
def copy_queries(project)
project.queries.each do |query|
Jean-Philippe Lang
Rails3 compatibility....
r8263 new_query = ::Query.new
Jean-Philippe Lang
Prevent mass-assignment warnings....
r2857 new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria")
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 new_query.sort_criteria = query.sort_criteria if query.sort_criteria
new_query.project = self
Jean-Philippe Lang
Fixed: copied private queries not visible after project copy (#9520)....
r7662 new_query.user_id = query.user_id
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 self.queries << new_query
end
end
Jean-Philippe Lang
Allow project forums copy....
r2862
# Copies boards from +project+
def copy_boards(project)
project.boards.each do |board|
new_board = Board.new
new_board.attributes = board.attributes.dup.except("id", "project_id", "topics_count", "messages_count", "last_message_id")
new_board.project = self
self.boards << new_board
end
end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Added project module concept....
r714 def allowed_permissions
@allowed_permissions ||= begin
Eric Davis
Optimize: Only select the name when getting the module names....
r3370 module_names = enabled_modules.all(:select => :name).collect {|m| m.name}
Jean-Philippe Lang
Added project module concept....
r714 Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}
end
end
def allowed_actions
@actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
end
Eric Davis
Changed the Timelogs to use both the Systemwide and Project specific TimeEntryActivities...
r2834
Eric Davis
Added a Activities tab to Project Settings...
r2835 # Returns all the active Systemwide and project specific activities
def active_activities
Eric Davis
Project#activities should check all overridden activities, not just active ones....
r3125 overridden_activity_ids = self.time_entry_activities.collect(&:parent_id)
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Eric Davis
Added a Activities tab to Project Settings...
r2835 if overridden_activity_ids.empty?
Jean-Philippe Lang
Changes misleading scopes on Enumeration....
r2969 return TimeEntryActivity.shared.active
Eric Davis
Added a Activities tab to Project Settings...
r2835 else
return system_activities_and_project_overrides
end
end
# Returns all the Systemwide and project specific activities
# (inactive and active)
def all_activities
overridden_activity_ids = self.time_entry_activities.collect(&:parent_id)
if overridden_activity_ids.empty?
Jean-Philippe Lang
Changes misleading scopes on Enumeration....
r2969 return TimeEntryActivity.shared
Eric Davis
Added a Activities tab to Project Settings...
r2835 else
return system_activities_and_project_overrides(true)
end
end
# Returns the systemwide active activities merged with the project specific overrides
def system_activities_and_project_overrides(include_inactive=false)
if include_inactive
Jean-Philippe Lang
Changes misleading scopes on Enumeration....
r2969 return TimeEntryActivity.shared.
Eric Davis
Added a Activities tab to Project Settings...
r2835 find(:all,
:conditions => ["id NOT IN (?)", self.time_entry_activities.collect(&:parent_id)]) +
self.time_entry_activities
else
Jean-Philippe Lang
Changes misleading scopes on Enumeration....
r2969 return TimeEntryActivity.shared.active.
Eric Davis
Added a Activities tab to Project Settings...
r2835 find(:all,
Eric Davis
Project#activities should check all overridden activities, not just active ones....
r3125 :conditions => ["id NOT IN (?)", self.time_entry_activities.collect(&:parent_id)]) +
Eric Davis
Added a Activities tab to Project Settings...
r2835 self.time_entry_activities.active
end
Eric Davis
Changed the Timelogs to use both the Systemwide and Project specific TimeEntryActivities...
r2834 end
Toshi MARUYAMA
remove trailing white-spaces from app/models/project.rb....
r6397
Jean-Philippe Lang
Version sharing (#465) + optional inclusion of subprojects in the roadmap view (#2666)....
r3009 # Archives subprojects recursively
def archive!
children.each do |subproject|
subproject.send :archive!
end
update_attribute :status, STATUS_ARCHIVED
end
Jean-Philippe Lang
Fixed that projects are not ordered alphabetically after renaming project (#11508)....
r10004
def update_position_under_parent
set_or_update_position_under(parent)
end
# Inserts/moves the project so that target's children or root projects stay alphabetically sorted
def set_or_update_position_under(target_parent)
sibs = (target_parent.nil? ? self.class.roots : target_parent.children)
to_be_inserted_before = sibs.sort_by {|c| c.name.to_s.downcase}.detect {|c| c.name.to_s.downcase > name.to_s.downcase }
if to_be_inserted_before
move_to_left_of(to_be_inserted_before)
elsif target_parent.nil?
if sibs.empty?
# move_to_root adds the project in first (ie. left) position
move_to_root
else
move_to_right_of(sibs.last) unless self == sibs.last
end
else
# move_to_child_of adds the project in last (ie.right) position
move_to_child_of(target_parent)
end
end
Jean-Philippe Lang
Initial commit...
r2 end