##// END OF EJS Templates
scm: recovery showing "root @ branch" in repository tree viewing....
scm: recovery showing "root @ branch" in repository tree viewing. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5139 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r4525:9fb770ba503b
r5019:b6dfa0b081d0
Show More
project.rb
841 lines | 30.9 KiB | text/x-ruby | RubyLexer
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # redMine - project management software
# Copyright (C) 2006 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.
class Project < ActiveRecord::Base
Jean-Philippe Lang
Declare safe attributes for User and Projects models....
r4378 include Redmine::SafeAttributes
Jean-Philippe Lang
Added the ability to archive projects:...
r546 # Project statuses
STATUS_ACTIVE = 1
STATUS_ARCHIVED = 9
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
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'
Jean-Philippe Lang
User groups branch merged....
r2755 has_many :member_principals, :class_name => 'Member',
: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
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
fixed #9308 table_name pre/suffix support...
r334 has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :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
has_many :news, :dependent => :delete_all, :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
added svn:eol-style native property on /app files...
r330 has_one :repository, :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
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 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'
Jean-Philippe Lang
Fixed: deleting a project with subprojects breaks the project tree (#4701)....
r3240 acts_as_nested_set :order => 'name'
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
Jean-Philippe Lang
Added the ability to archive projects:...
r546
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
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: deleting a project with subprojects breaks the project tree (#4701)....
r3240 before_destroy :delete_all_members, :destroy_children
Jean-Philippe Lang
Merged nbc branch @ r1812 (commit access permission and reposman improvements)....
r1812
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] } }
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 named_scope :active, { :conditions => "#{Project.table_name}.status = #{STATUS_ACTIVE}"}
Eric Davis
Renamed Project#public named_scope so it will not override Ruby's public method...
r2827 named_scope :all_public, { :conditions => { :is_public => true } }
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 named_scope :visible, lambda { { :conditions => Project.visible_by(User.current) } }
Jean-Philippe Lang
Merged Rails 2.0 compatibility changes....
r962
Jean-Philippe Lang
Moves project attributes default assignments from ProjectsController#new to the model (#6064)....
r4346 def initialize(attributes = nil)
super
initialized = (attributes || {}).stringify_keys
if !initialized.key?('identifier') && Setting.sequential_project_identifiers?
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')
self.trackers = Tracker.all
end
end
Jean-Philippe Lang
Initial commit for svn repository management and access control:...
r393 def identifier=(identifier)
super unless identifier_frozen?
end
def identifier_frozen?
errors[:identifier].nil? && !(new_record? || identifier.blank?)
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
fixed #9308 table_name pre/suffix support...
r334 find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC")
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Eric Davis
Added some RDoc documentation for some models....
r2536 # Returns a SQL :conditions string used to find all active projects for the specified user.
#
# Examples:
# Projects.visible_by(admin) => "projects.status = 1"
# Projects.visible_by(normal_user) => "projects.status = 1 AND projects.is_public = 1"
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 def self.visible_by(user=nil)
Jean-Philippe Lang
Fixed: Calendar and Gantt show private subprojects even if current user is not a member of them (#1217)....
r1416 user ||= User.current
Jean-Philippe Lang
Projects menu item now shows the list of public projects and projects for which the user is a member (marked with a star)....
r457 if user && user.admin?
Jean-Philippe Lang
Added a cross-project issue list. It displays the issues of all the projects visible by the user....
r673 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
Jean-Philippe Lang
Fixed an error on welcome screen for users with no membership...
r566 elsif user && user.memberships.any?
Jean-Philippe Lang
Added a cross-project issue list. It displays the issues of all the projects visible by the user....
r673 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(',')}))"
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 else
Jean-Philippe Lang
Added a cross-project issue list. It displays the issues of all the projects visible by the user....
r673 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}"
Jean-Philippe Lang
Added the ability to archive projects:...
r546 end
end
Jean-Philippe Lang
Activity enhancements:...
r1213 def self.allowed_to_condition(user, permission, options={})
Jean-Philippe Lang
Propagates time tracking to the parent project (closes #433). Time report enhancements....
r1162 statements = []
Jean-Philippe Lang
Activity enhancements:...
r1213 base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
Jean-Philippe Lang
Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled....
r1905 if perm = Redmine::AccessControl.permission(permission)
unless perm.project_module.nil?
# If the permission belongs to a project module, make sure the module is enabled
Jean-Philippe Lang
Slight change to the visibility SQL statement....
r2764 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
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
Jean-Philippe Lang
Propagates time tracking to the parent project (closes #433). Time report enhancements....
r1162 if user.admin?
# no restriction
else
Jean-Philippe Lang
Activity enhancements:...
r1213 statements << "1=0"
Jean-Philippe Lang
Fixed: search engine may reveal private projects (#1613)....
r1635 if user.logged?
Jean-Philippe Lang
Allow non admin users to add subprojects (#2963)....
r2945 if Role.non_member.allowed_to?(permission) && !options[:member]
statements << "#{Project.table_name}.is_public = #{connection.quoted_true}"
end
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 allowed_project_ids = user.memberships.select {|m| m.roles.detect {|role| role.allowed_to?(permission)}}.collect {|m| m.project_id}
Jean-Philippe Lang
Fixed: search engine may reveal private projects (#1613)....
r1635 statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any?
else
Jean-Philippe Lang
Allow non admin users to add subprojects (#2963)....
r2945 if Role.anonymous.allowed_to?(permission) && !options[:member]
# anonymous user allowed on public project
statements << "#{Project.table_name}.is_public = #{connection.quoted_true}"
end
Jean-Philippe Lang
Fixed: search engine may reveal private projects (#1613)....
r1635 end
Jean-Philippe Lang
Propagates time tracking to the parent project (closes #433). Time report enhancements....
r1162 end
Jean-Philippe Lang
Activity enhancements:...
r1213 statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))"
Jean-Philippe Lang
Propagates time tracking to the parent project (closes #433). Time report enhancements....
r1162 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
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']
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
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
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)
@to_param ||= (identifier.to_s =~ %r{^\d*$} ? id : identifier)
Jean-Philippe Lang
Project identifier is now used in URLs (instead of project id)....
r994 end
Jean-Philippe Lang
Added the ability to archive projects:...
r546 def active?
self.status == STATUS_ACTIVE
end
Jean-Philippe Lang
Improved error message when trying to access an archived project (#2995)....
r4171 def archived?
self.status == STATUS_ARCHIVED
end
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
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
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
# 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
# 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))
# Insert the project so that target's children or root projects stay alphabetically sorted
sibs = (p.nil? ? self.class.roots : p.children)
to_be_inserted_before = sibs.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 p.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(p)
end
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
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 ||=
Tracker.find(:all, :include => :projects,
:select => "DISTINCT #{Tracker.table_name}.*",
Jean-Philippe Lang
Ignore archived subprojects in Project#rolled_up_trackers (#2550)....
r2309 :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", 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
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,
:conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt])
end
Jean-Philippe Lang
Adds a link to automatically close completed versions in project settings (#1245)....
r2909
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
@shared_versions ||=
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')" +
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 "))")
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
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
Jean-Philippe Lang
Added 'Bulk edit' functionality....
r806 # Users issues can be assigned to
def assignable_users
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 members.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.user}.sort
Jean-Philippe Lang
Added 'Bulk edit' functionality....
r806 end
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
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
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
Jean-Philippe Lang
Subprojects are now grouped by projects in the 'Projects' top navigation drop-down menu....
r692
Jean-Philippe Lang
Ability to search all projects or the projects the user belongs to (#791)....
r1420 def project
self
end
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
Jean-Philippe Lang
Added project module concept....
r714
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
# 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')
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
Jean-Philippe Lang
Unlimited and optional project description. The project list will show truncated descriptions only (the first fews lines)....
r1074
Eric Davis
Added some RDoc documentation for some models....
r2536 # Return true if this project is allowed to do the specified action.
# 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)
if action.is_a? Hash
allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
else
allowed_permissions.include? action
end
end
def module_enabled?(module_name)
module_name = module_name.to_s
enabled_modules.detect {|m| m.name == module_name}
end
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
Do not DELETE/INSERT enabled_modules when updating project modules....
r2412 # remove disabled modules
enabled_modules.each {|mod| mod.destroy unless module_names.include?(mod.name)}
# add new modules
Jean-Philippe Lang
Fixed: Project#enabled_module_names= does not test if a module is already enabled (#4200)....
r2922 module_names.reject {|name| module_enabled?(name)}.each {|name| enabled_modules << 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
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-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) }
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
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)
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?
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
# 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|
while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
ancestors.pop
end
yield project, ancestors.size
ancestors << project
end
end
Eric Davis
Added the ability to copy a project in the Project Administration panel....
r2608
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852 private
Jean-Philippe Lang
Fixed: deleting a project with subprojects breaks the project tree (#4701)....
r3240 # Destroys children before destroying self
def destroy_children
children.each do |child|
child.destroy
end
end
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
# Copies issues from +project+
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 = {}
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
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
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
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)}
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|
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
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
Jean-Philippe Lang
Project copy: let the user choose what to copy from the source project (everything by default)....
r2852
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)
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
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
Initial commit...
r2 end