2007-03-12 20:59:02 +03:00
# 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
2007-05-27 21:42:04 +04:00
# Project statuses
STATUS_ACTIVE = 1
STATUS_ARCHIVED = 9
2007-03-16 01:11:02 +03:00
has_many :members , :dependent = > :delete_all , :include = > :user , :conditions = > " #{ User . table_name } .status= #{ User :: STATUS_ACTIVE } "
2007-03-12 20:59:02 +03:00
has_many :users , :through = > :members
has_many :custom_values , :dependent = > :delete_all , :as = > :customized
2007-09-14 15:34:08 +04:00
has_many :enabled_modules , :dependent = > :delete_all
2007-11-20 23:29:03 +03:00
has_and_belongs_to_many :trackers , :order = > " #{ Tracker . table_name } .position "
2007-03-16 01:11:02 +03:00
has_many :issues , :dependent = > :destroy , :order = > " #{ Issue . table_name } .created_on DESC " , :include = > [ :status , :tracker ]
2007-08-16 14:38:23 +04:00
has_many :issue_changes , :through = > :issues , :source = > :journals
2007-06-25 23:17:58 +04:00
has_many :versions , :dependent = > :destroy , :order = > " #{ Version . table_name } .effective_date DESC, #{ Version . table_name } .name DESC "
2007-03-23 15:22:31 +03:00
has_many :time_entries , :dependent = > :delete_all
2007-03-12 20:59:02 +03:00
has_many :queries , :dependent = > :delete_all
has_many :documents , :dependent = > :destroy
has_many :news , :dependent = > :delete_all , :include = > :author
2007-03-16 01:11:02 +03:00
has_many :issue_categories , :dependent = > :delete_all , :order = > " #{ IssueCategory . table_name } .name "
2007-05-13 21:09:56 +04:00
has_many :boards , :order = > " position ASC "
2007-03-12 20:59:02 +03:00
has_one :repository , :dependent = > :destroy
2007-09-08 00:07:54 +04:00
has_many :changesets , :through = > :repository
2007-03-12 20:59:02 +03:00
has_one :wiki , :dependent = > :destroy
2007-11-12 20:23:14 +03:00
# Custom field for the project issues
has_and_belongs_to_many :custom_fields ,
: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'
2007-03-12 20:59:02 +03:00
acts_as_tree :order = > " name " , :counter_cache = > true
2007-09-27 21:28:22 +04:00
acts_as_searchable :columns = > [ 'name' , 'description' ] , :project_key = > 'id'
acts_as_event :title = > Proc . new { | o | " #{ l ( :label_project ) } : #{ o . name } " } ,
:url = > Proc . new { | o | { :controller = > 'projects' , :action = > 'show' , :id = > o . id } }
2007-09-14 15:34:08 +04:00
attr_protected :status , :enabled_module_names
2007-05-27 21:42:04 +04:00
2007-04-01 23:43:59 +04:00
validates_presence_of :name , :description , :identifier
validates_uniqueness_of :name , :identifier
2007-03-12 20:59:02 +03:00
validates_associated :custom_values , :on = > :update
validates_associated :repository , :wiki
2007-04-02 22:44:35 +04:00
validates_length_of :name , :maximum = > 30
2007-03-12 20:59:02 +03:00
validates_format_of :name , :with = > / ^[ \ w \ s \ ' \ -]*$ /i
2007-04-02 22:44:35 +04:00
validates_length_of :description , :maximum = > 255
2007-09-20 22:58:19 +04:00
validates_length_of :homepage , :maximum = > 60
2007-04-02 22:44:35 +04:00
validates_length_of :identifier , :in = > 3 .. 12
2007-04-01 23:43:59 +04:00
validates_format_of :identifier , :with = > / ^[a-z0-9 \ -]*$ /
def identifier = ( identifier )
super unless identifier_frozen?
end
def identifier_frozen?
errors [ :identifier ] . nil? && ! ( new_record? || identifier . blank? )
end
2007-04-02 21:12:02 +04:00
def issues_with_subprojects ( include_subprojects = false )
conditions = nil
2007-05-27 21:42:04 +04:00
if include_subprojects && ! active_children . empty?
ids = [ id ] + active_children . collect { | c | c . id }
2007-04-02 21:12:02 +04:00
conditions = [ " #{ Issue . table_name } .project_id IN ( #{ ids . join ( ',' ) } ) " ]
end
2007-05-27 21:42:04 +04:00
conditions || = [ " #{ Issue . table_name } .project_id = ? " , id ]
2007-04-02 21:12:02 +04:00
Issue . with_scope :find = > { :conditions = > conditions } do
yield
end
end
2007-11-08 22:00:37 +03:00
# Return all issues status changes for the project between the 2 given dates
def issues_status_changes ( from , to )
Journal . find ( :all , :include = > [ :issue , :details , :user ] ,
:conditions = > [ " #{ Journal . table_name } .journalized_type = 'Issue' " +
" AND #{ Issue . table_name } .project_id = ? " +
" AND #{ JournalDetail . table_name } .prop_key = 'status_id' " +
" AND #{ Journal . table_name } .created_on BETWEEN ? AND ? " ,
id , from , to + 1 ] )
end
2007-03-12 20:59:02 +03:00
# 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 )
2007-03-16 01:11:02 +03:00
find ( :all , :limit = > count , :conditions = > visible_by ( user ) , :order = > " created_on DESC " )
2007-03-12 20:59:02 +03:00
end
def self . visible_by ( user = nil )
2007-04-21 20:40:56 +04:00
if user && user . admin?
2007-08-31 21:02:44 +04:00
return " #{ Project . table_name } .status= #{ Project :: STATUS_ACTIVE } "
2007-06-23 20:36:01 +04:00
elsif user && user . memberships . any?
2007-08-31 21:02:44 +04:00
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 ( ',' ) } )) "
2007-03-12 20:59:02 +03:00
else
2007-08-31 21:02:44 +04:00
return " #{ Project . table_name } .status= #{ Project :: STATUS_ACTIVE } AND #{ Project . table_name } .is_public = #{ connection . quoted_true } "
2007-05-27 21:42:04 +04:00
end
end
def active?
self . status == STATUS_ACTIVE
end
def archive
# Archive subprojects if any
children . each do | subproject |
subproject . archive
2007-03-12 20:59:02 +03:00
end
2007-05-27 21:42:04 +04:00
update_attribute :status , STATUS_ARCHIVED
end
def unarchive
return false if parent && ! parent . active?
update_attribute :status , STATUS_ACTIVE
end
def active_children
children . select { | child | child . active? }
2007-03-12 20:59:02 +03:00
end
2007-10-09 23:07:19 +04:00
# Users issues can be assigned to
def assignable_users
members . select { | m | m . role . assignable? } . collect { | m | m . user }
end
2007-10-20 16:47:05 +04:00
# 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
2007-03-12 20:59:02 +03:00
# Returns an array of all custom fields enabled for project issues
# (explictly associated custom fields and custom fields enabled for all projects)
def custom_fields_for_issues ( tracker )
2007-03-16 01:11:02 +03:00
all_custom_fields . select { | c | tracker . custom_fields . include? c }
2007-03-12 20:59:02 +03:00
end
def all_custom_fields
2007-03-16 01:11:02 +03:00
@all_custom_fields || = ( IssueCustomField . for_all + custom_fields ) . uniq
2007-03-12 20:59:02 +03:00
end
2007-09-05 21:24:22 +04:00
def <=> ( project )
2007-11-20 01:28:43 +03:00
name . downcase < = > project . name . downcase
2007-09-05 21:24:22 +04:00
end
2007-09-14 15:34:08 +04:00
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 )
enabled_modules . clear
module_names = [ ] unless module_names && module_names . is_a? ( Array )
module_names . each do | name |
enabled_modules << EnabledModule . new ( :name = > name . to_s )
end
end
2007-03-12 20:59:02 +03:00
protected
def validate
errors . add ( parent_id , " must be a root project " ) if parent and parent . parent
errors . add_to_base ( " A project with subprojects can't be a subproject " ) if parent and children . size > 0
2006-07-09 20:30:01 +04:00
end
2007-09-14 15:34:08 +04:00
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
2006-06-28 22:11:03 +04:00
end