##// END OF EJS Templates
Adds a user search field with autocompleter on project members screen....
Adds a user search field with autocompleter on project members screen. User selection with checkboxes is disabled if there are more than 300 users available (#2993). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2638 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r2536:c2dfffd7f267
r2549:04e181b8b05d
Show More
project.rb
337 lines | 13.1 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
Added the ability to archive projects:...
r546 # Project statuses
STATUS_ACTIVE = 1
STATUS_ARCHIVED = 9
Jean-Philippe Lang
Merged Rails 2.0 compatibility changes....
r962 has_many :members, :include => :user, :conditions => "#{User.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
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
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 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
Ability to search all projects or the projects the user belongs to (#791)....
r1420 acts_as_searchable :columns => ['name', '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: no :author method error on projects atom feed (#1623)....
r1639 :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}},
:author => nil
Jean-Philippe Lang
Search engines now supports pagination....
r755
Jean-Philippe Lang
Added project module concept....
r714 attr_protected :status, :enabled_module_names
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
Initial commit for svn repository management and access control:...
r393 validates_uniqueness_of :name, :identifier
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 validates_associated :repository, :wiki
Jean-Philippe Lang
Added some attributes length validations....
r397 validates_length_of :name, :maximum => 30
Jean-Philippe Lang
Change projects homepage limit to 255 chars (#663, #1095)....
r1443 validates_length_of :homepage, :maximum => 255
Jean-Philippe Lang
Lower the project identifier limit to a minimum of two characters (#2003)....
r2219 validates_length_of :identifier, :in => 2..20
Jean-Philippe Lang
Initial commit for svn repository management and access control:...
r393 validates_format_of :identifier, :with => /^[a-z0-9\-]*$/
Jean-Philippe Lang
Merged Rails 2.0 compatibility changes....
r962 before_destroy :delete_all_members
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}"}
Jean-Philippe Lang
Replaces the obsolete robots.txt with a cached action (#2491)....
r2317 named_scope :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
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 the ability to include subprojects issues on calendar & gantt (options box)...
r395 def issues_with_subprojects(include_subprojects=false)
conditions = nil
Jean-Philippe Lang
Fixed: Calendar and Gantt show private subprojects even if current user is not a member of them (#1217)....
r1416 if include_subprojects
Jean-Philippe Lang
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 ids = [id] + descendants.collect(&:id)
Jean-Philippe Lang
Fixed: Calendar and Gantt show private subprojects even if current user is not a member of them (#1217)....
r1416 conditions = ["#{Project.table_name}.id IN (#{ids.join(',')}) AND #{Project.visible_by}"]
Jean-Philippe Lang
Added the ability to include subprojects issues on calendar & gantt (options box)...
r395 end
Jean-Philippe Lang
Include subprojects versions on calendar and gantt (#1116)....
r1349 conditions ||= ["#{Project.table_name}.id = ?", id]
Jean-Philippe Lang
Fixed: calendar and gantt broken with Rails 2.0...
r969 # Quick and dirty fix for Rails 2 compatibility
Issue.send(:with_scope, :find => { :conditions => conditions }) do
Jean-Philippe Lang
Include subprojects versions on calendar and gantt (#1116)....
r1349 Version.send(:with_scope, :find => { :conditions => conditions }) do
yield
end
Jean-Philippe Lang
Added the ability to include subprojects issues on calendar & gantt (options box)...
r395 end
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
base_statement << " AND EXISTS (SELECT em.id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.project_module}' AND em.project_id=#{Project.table_name}.id)"
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?
statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" if Role.non_member.allowed_to?(permission)
allowed_project_ids = user.memberships.select {|m| m.role.allowed_to?(permission)}.collect {|m| m.project_id}
statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any?
elsif Role.anonymous.allowed_to?(permission)
# anonymous user allowed on public project
statements << "#{Project.table_name}.is_public = #{connection.quoted_true}"
else
# anonymous user is not authorized
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
# 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
Merged nested projects branch. Removes limit on subproject nesting (#594)....
r2302 # Archives the project and its descendants recursively
Jean-Philippe Lang
Added the ability to archive projects:...
r546 def archive
# Archive subprojects if any
children.each do |subproject|
subproject.archive
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Added the ability to archive projects:...
r546 update_attribute :status, STATUS_ARCHIVED
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
def possible_parents
@possible_parents ||= (Project.active.find(:all) - self_and_descendants)
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
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
Merged Rails 2.0 compatibility changes....
r962 # Deletes all project's members
def delete_all_members
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
'Assigned to' drop down list is now sorted by user's lastname....
r926 members.select {|m| m.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
members.select {|m| m.mail_notification? || m.user.mail_notification?}.collect {|m| m.user.mail}
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
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)
module_names = module_names.collect(&:to_s)
# remove disabled modules
enabled_modules.each {|mod| mod.destroy unless module_names.include?(mod.name)}
# add new modules
module_names.each {|name| enabled_modules << EnabledModule.new(:name => name)}
else
enabled_modules.clear
Jean-Philippe Lang
Added project module concept....
r714 end
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
protected
def validate
Jean-Philippe Lang
Merged Rails 2.2 branch. Redmine now requires Rails 2.2.2....
r2430 errors.add(:identifier, :invalid) if !identifier.blank? && identifier.match(/^\d*$/)
Jean-Philippe Lang
v0.2.0...
r5 end
Jean-Philippe Lang
Added project module concept....
r714
private
def allowed_permissions
@allowed_permissions ||= begin
module_names = enabled_modules.collect {|m| m.name}
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
Jean-Philippe Lang
Initial commit...
r2 end