diff options
Diffstat (limited to 'app/models')
-rw-r--r-- | app/models/attachment.rb | 180 | ||||
-rw-r--r-- | app/models/auth_source_ldap.rb | 154 | ||||
-rw-r--r-- | app/models/custom_field.rb | 118 | ||||
-rw-r--r-- | app/models/custom_value.rb | 72 | ||||
-rw-r--r-- | app/models/document.rb | 44 | ||||
-rw-r--r-- | app/models/enumeration.rb | 90 | ||||
-rw-r--r-- | app/models/issue.rb | 202 | ||||
-rw-r--r-- | app/models/issue_category.rb | 54 | ||||
-rw-r--r-- | app/models/issue_custom_field.rb | 52 | ||||
-rw-r--r-- | app/models/issue_history.rb | 44 | ||||
-rw-r--r-- | app/models/issue_status.rb | 98 | ||||
-rw-r--r-- | app/models/mailer.rb | 158 | ||||
-rw-r--r-- | app/models/member.rb | 54 | ||||
-rw-r--r-- | app/models/news.rb | 54 | ||||
-rw-r--r-- | app/models/permission.rb | 126 | ||||
-rw-r--r-- | app/models/project.rb | 138 | ||||
-rw-r--r-- | app/models/project_custom_field.rb | 44 | ||||
-rw-r--r-- | app/models/role.rb | 62 | ||||
-rw-r--r-- | app/models/svn_repos.rb | 430 | ||||
-rw-r--r-- | app/models/tracker.rb | 62 | ||||
-rw-r--r-- | app/models/user.rb | 280 | ||||
-rw-r--r-- | app/models/user_custom_field.rb | 44 | ||||
-rw-r--r-- | app/models/version.rb | 62 | ||||
-rw-r--r-- | app/models/workflow.rb | 46 |
24 files changed, 1334 insertions, 1334 deletions
diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 773f2ebe9..82fcdadf5 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -1,92 +1,92 @@ -# redMine - project management software
-# Copyright (C) 2006-2007 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.
-
-require "digest/md5"
-
-class Attachment < ActiveRecord::Base
- belongs_to :container, :polymorphic => true
- belongs_to :author, :class_name => "User", :foreign_key => "author_id"
-
- validates_presence_of :container, :filename
-
- cattr_accessor :storage_path
- @@storage_path = "#{RAILS_ROOT}/files"
-
- def validate
- errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes
- end
-
- def file=(incomming_file)
- unless incomming_file.nil?
- @temp_file = incomming_file
- if @temp_file.size > 0
- self.filename = sanitize_filename(@temp_file.original_filename)
- self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename
- self.content_type = @temp_file.content_type
- self.filesize = @temp_file.size
- end
- end
- end
-
- def file
- nil
- end
-
- # Copy temp file to its final location
- def before_save
- if @temp_file && (@temp_file.size > 0)
- logger.debug("saving '#{self.diskfile}'")
- File.open(diskfile, "wb") do |f|
- f.write(@temp_file.read)
- end
- self.digest = Digest::MD5.hexdigest(File.read(diskfile))
- end
- end
-
- # Deletes file on the disk
- def after_destroy
- if self.filename?
- File.delete(diskfile) if File.exist?(diskfile)
- end
- end
-
- # Returns file's location on disk
- def diskfile
- "#{@@storage_path}/#{self.disk_filename}"
- end
-
- def increment_download
- increment!(:downloads)
- end
-
- # returns last created projects
- def self.most_downloaded
- find(:all, :limit => 5, :order => "downloads DESC")
- end
-
-private
- def sanitize_filename(value)
- # get only the filename, not the whole path
- just_filename = value.gsub(/^.*(\\|\/)/, '')
- # NOTE: File.basename doesn't work right with Windows paths on Unix
- # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
-
- # Finally, replace all non alphanumeric, underscore or periods with underscore
- @filename = just_filename.gsub(/[^\w\.\-]/,'_')
- end
+# redMine - project management software +# Copyright (C) 2006-2007 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. + +require "digest/md5" + +class Attachment < ActiveRecord::Base + belongs_to :container, :polymorphic => true + belongs_to :author, :class_name => "User", :foreign_key => "author_id" + + validates_presence_of :container, :filename + + cattr_accessor :storage_path + @@storage_path = "#{RAILS_ROOT}/files" + + def validate + errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes + end + + def file=(incomming_file) + unless incomming_file.nil? + @temp_file = incomming_file + if @temp_file.size > 0 + self.filename = sanitize_filename(@temp_file.original_filename) + self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename + self.content_type = @temp_file.content_type + self.filesize = @temp_file.size + end + end + end + + def file + nil + end + + # Copy temp file to its final location + def before_save + if @temp_file && (@temp_file.size > 0) + logger.debug("saving '#{self.diskfile}'") + File.open(diskfile, "wb") do |f| + f.write(@temp_file.read) + end + self.digest = Digest::MD5.hexdigest(File.read(diskfile)) + end + end + + # Deletes file on the disk + def after_destroy + if self.filename? + File.delete(diskfile) if File.exist?(diskfile) + end + end + + # Returns file's location on disk + def diskfile + "#{@@storage_path}/#{self.disk_filename}" + end + + def increment_download + increment!(:downloads) + end + + # returns last created projects + def self.most_downloaded + find(:all, :limit => 5, :order => "downloads DESC") + end + +private + def sanitize_filename(value) + # get only the filename, not the whole path + just_filename = value.gsub(/^.*(\\|\/)/, '') + # NOTE: File.basename doesn't work right with Windows paths on Unix + # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/')) + + # Finally, replace all non alphanumeric, underscore or periods with underscore + @filename = just_filename.gsub(/[^\w\.\-]/,'_') + end end diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb index 895cf1c63..31259afc9 100644 --- a/app/models/auth_source_ldap.rb +++ b/app/models/auth_source_ldap.rb @@ -1,79 +1,79 @@ -# 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.
-
-require 'net/ldap'
-require 'iconv'
-
-class AuthSourceLdap < AuthSource
- validates_presence_of :host, :port, :attr_login
-
- def after_initialize
- self.port = 389 if self.port == 0
- end
-
- def authenticate(login, password)
- attrs = []
- # get user's DN
- ldap_con = initialize_ldap_con(self.account, self.account_password)
- login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
- object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
- dn = String.new
- ldap_con.search( :base => self.base_dn,
- :filter => object_filter & login_filter,
- :attributes=> ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]) do |entry|
- dn = entry.dn
- attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
- :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
- :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
- :auth_source_id => self.id ]
- end
- return nil if dn.empty?
- logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug?
- # authenticate user
- ldap_con = initialize_ldap_con(dn, password)
- return nil unless ldap_con.bind
- # return user's attributes
- logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
- attrs
- rescue Net::LDAP::LdapError => text
- raise "LdapError: " + text
- end
-
- # test the connection to the LDAP
- def test_connection
- ldap_con = initialize_ldap_con(self.account, self.account_password)
- ldap_con.open { }
- rescue Net::LDAP::LdapError => text
- raise "LdapError: " + text
- end
-
- def auth_method_name
- "LDAP"
- end
-
-private
- def initialize_ldap_con(ldap_user, ldap_password)
- Net::LDAP.new( {:host => self.host,
- :port => self.port,
- :auth => { :method => :simple, :username => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_user), :password => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_password) }}
- )
- end
-
- def self.get_attr(entry, attr_name)
- entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
+# 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. + +require 'net/ldap' +require 'iconv' + +class AuthSourceLdap < AuthSource + validates_presence_of :host, :port, :attr_login + + def after_initialize + self.port = 389 if self.port == 0 + end + + def authenticate(login, password) + attrs = [] + # get user's DN + ldap_con = initialize_ldap_con(self.account, self.account_password) + login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) + object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) + dn = String.new + ldap_con.search( :base => self.base_dn, + :filter => object_filter & login_filter, + :attributes=> ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]) do |entry| + dn = entry.dn + attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname), + :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), + :mail => AuthSourceLdap.get_attr(entry, self.attr_mail), + :auth_source_id => self.id ] + end + return nil if dn.empty? + logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug? + # authenticate user + ldap_con = initialize_ldap_con(dn, password) + return nil unless ldap_con.bind + # return user's attributes + logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? + attrs + rescue Net::LDAP::LdapError => text + raise "LdapError: " + text + end + + # test the connection to the LDAP + def test_connection + ldap_con = initialize_ldap_con(self.account, self.account_password) + ldap_con.open { } + rescue Net::LDAP::LdapError => text + raise "LdapError: " + text + end + + def auth_method_name + "LDAP" + end + +private + def initialize_ldap_con(ldap_user, ldap_password) + Net::LDAP.new( {:host => self.host, + :port => self.port, + :auth => { :method => :simple, :username => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_user), :password => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_password) }} + ) + end + + def self.get_attr(entry, attr_name) + entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] end end diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index ea11edc46..554504a9f 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -1,60 +1,60 @@ -# 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 CustomField < ActiveRecord::Base
- has_many :custom_values, :dependent => :delete_all
- serialize :possible_values
-
- FIELD_FORMATS = { "string" => { :name => :label_string, :order => 1 },
- "text" => { :name => :label_text, :order => 2 },
- "int" => { :name => :label_integer, :order => 3 },
- "list" => { :name => :label_list, :order => 4 },
- "date" => { :name => :label_date, :order => 5 },
- "bool" => { :name => :label_boolean, :order => 6 }
- }.freeze
-
- validates_presence_of :name, :field_format
- validates_uniqueness_of :name
- validates_format_of :name, :with => /^[\w\s\'\-]*$/i
- validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys
-
- def initialize(attributes = nil)
- super
- self.possible_values ||= []
- end
-
- def before_validation
- # remove empty values
- self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact
- end
-
- def validate
- if self.field_format == "list"
- errors.add(:possible_values, :activerecord_error_blank) if self.possible_values.nil? || self.possible_values.empty?
- errors.add(:possible_values, :activerecord_error_invalid) unless self.possible_values.is_a? Array
- end
- end
-
- # to move in project_custom_field
- def self.for_all
- find(:all, :conditions => ["is_for_all=?", true])
- end
-
- def type_name
- nil
+# 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 CustomField < ActiveRecord::Base + has_many :custom_values, :dependent => :delete_all + serialize :possible_values + + FIELD_FORMATS = { "string" => { :name => :label_string, :order => 1 }, + "text" => { :name => :label_text, :order => 2 }, + "int" => { :name => :label_integer, :order => 3 }, + "list" => { :name => :label_list, :order => 4 }, + "date" => { :name => :label_date, :order => 5 }, + "bool" => { :name => :label_boolean, :order => 6 } + }.freeze + + validates_presence_of :name, :field_format + validates_uniqueness_of :name + validates_format_of :name, :with => /^[\w\s\'\-]*$/i + validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys + + def initialize(attributes = nil) + super + self.possible_values ||= [] end -end
+ + def before_validation + # remove empty values + self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact + end + + def validate + if self.field_format == "list" + errors.add(:possible_values, :activerecord_error_blank) if self.possible_values.nil? || self.possible_values.empty? + errors.add(:possible_values, :activerecord_error_invalid) unless self.possible_values.is_a? Array + end + end + + # to move in project_custom_field + def self.for_all + find(:all, :conditions => ["is_for_all=?", true]) + end + + def type_name + nil + end +end diff --git a/app/models/custom_value.rb b/app/models/custom_value.rb index e93dfb4f3..a1b2c9c40 100644 --- a/app/models/custom_value.rb +++ b/app/models/custom_value.rb @@ -1,38 +1,38 @@ -# 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 CustomValue < ActiveRecord::Base
- belongs_to :custom_field
- belongs_to :customized, :polymorphic => true
-
-protected
- def validate
- errors.add(:value, :activerecord_error_blank) and return if custom_field.is_required? and value.empty?
- errors.add(:value, :activerecord_error_invalid) unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp)
- errors.add(:value, :activerecord_error_too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0
- errors.add(:value, :activerecord_error_too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length
- case custom_field.field_format
- when "int"
- errors.add(:value, :activerecord_error_not_a_number) unless value =~ /^[0-9]*$/
- when "date"
- errors.add(:value, :activerecord_error_not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ or value.empty?
- when "list"
- errors.add(:value, :activerecord_error_inclusion) unless custom_field.possible_values.include? value or value.empty?
- end
+# 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 CustomValue < ActiveRecord::Base + belongs_to :custom_field + belongs_to :customized, :polymorphic => true + +protected + def validate + errors.add(:value, :activerecord_error_blank) and return if custom_field.is_required? and value.empty? + errors.add(:value, :activerecord_error_invalid) unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp) + errors.add(:value, :activerecord_error_too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0 + errors.add(:value, :activerecord_error_too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length + case custom_field.field_format + when "int" + errors.add(:value, :activerecord_error_not_a_number) unless value =~ /^[0-9]*$/ + when "date" + errors.add(:value, :activerecord_error_not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ or value.empty? + when "list" + errors.add(:value, :activerecord_error_inclusion) unless custom_field.possible_values.include? value or value.empty? + end end -end
+end diff --git a/app/models/document.rb b/app/models/document.rb index 40a9765a4..141489a79 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -1,24 +1,24 @@ -# 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 Document < ActiveRecord::Base
- belongs_to :project
- belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id"
- has_many :attachments, :as => :container, :dependent => :destroy
-
+# 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 Document < ActiveRecord::Base + belongs_to :project + belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id" + has_many :attachments, :as => :container, :dependent => :destroy + validates_presence_of :project, :title, :category end diff --git a/app/models/enumeration.rb b/app/models/enumeration.rb index 0d6554f82..251f00fbe 100644 --- a/app/models/enumeration.rb +++ b/app/models/enumeration.rb @@ -1,47 +1,47 @@ -# 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 Enumeration < ActiveRecord::Base
- before_destroy :check_integrity
-
- validates_presence_of :opt, :name
- validates_uniqueness_of :name, :scope => [:opt]
- validates_format_of :name, :with => /^[\w\s\'\-]*$/i
-
- OPTIONS = {
- "IPRI" => :enumeration_issue_priorities,
- "DCAT" => :enumeration_doc_categories
- }.freeze
-
- def self.get_values(option)
- find(:all, :conditions => ['opt=?', option])
- end
-
- def option_name
- OPTIONS[self.opt]
- end
-
-private
- def check_integrity
- case self.opt
- when "IPRI"
- raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id])
- when "DCAT"
- raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id])
- end
+# 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 Enumeration < ActiveRecord::Base + before_destroy :check_integrity + + validates_presence_of :opt, :name + validates_uniqueness_of :name, :scope => [:opt] + validates_format_of :name, :with => /^[\w\s\'\-]*$/i + + OPTIONS = { + "IPRI" => :enumeration_issue_priorities, + "DCAT" => :enumeration_doc_categories + }.freeze + + def self.get_values(option) + find(:all, :conditions => ['opt=?', option]) + end + + def option_name + OPTIONS[self.opt] + end + +private + def check_integrity + case self.opt + when "IPRI" + raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id]) + when "DCAT" + raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id]) + end end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 6f77bef30..140071872 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -1,102 +1,102 @@ -# 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 Issue < ActiveRecord::Base
-
- belongs_to :project
- belongs_to :tracker
- belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
- belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
- belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
- belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
- belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
- belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
-
- has_many :journals, :as => :journalized, :dependent => :destroy
- has_many :attachments, :as => :container, :dependent => :destroy
-
- has_many :custom_values, :dependent => :delete_all, :as => :customized
- has_many :custom_fields, :through => :custom_values
-
- validates_presence_of :subject, :description, :priority, :tracker, :author, :status
- validates_inclusion_of :done_ratio, :in => 0..100
- validates_associated :custom_values, :on => :update
-
- # set default status for new issues
- def before_validation
- self.status = IssueStatus.default if new_record?
- end
-
- def validate
- if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
- errors.add :due_date, :activerecord_error_not_a_date
- end
-
- if self.due_date and self.start_date and self.due_date < self.start_date
- errors.add :due_date, :activerecord_error_greater_than_start_date
- end
- end
-
- #def before_create
- # build_history
- #end
-
- def before_save
- if @current_journal
- # attributes changes
- (Issue.column_names - %w(id description)).each {|c|
- @current_journal.details << JournalDetail.new(:property => 'attr',
- :prop_key => c,
- :old_value => @issue_before_change.send(c),
- :value => send(c)) unless send(c)==@issue_before_change.send(c)
- }
- # custom fields changes
- custom_values.each {|c|
- @current_journal.details << JournalDetail.new(:property => 'cf',
- :prop_key => c.custom_field_id,
- :old_value => @custom_values_before_change[c.custom_field_id],
- :value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value
- }
- @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty?
- end
- end
-
- def long_id
- "%05d" % self.id
- end
-
- def custom_value_for(custom_field)
- self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id }
- return nil
- end
-
- def init_journal(user, notes = "")
- @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
- @issue_before_change = self.clone
- @custom_values_before_change = {}
- self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
- @current_journal
- end
-
-private
- # Creates an history for the issue
- #def build_history
- # @history = self.histories.build
- # @history.status = self.status
- # @history.author = self.author
- #end
+# 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 Issue < ActiveRecord::Base + + belongs_to :project + belongs_to :tracker + belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' + belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' + belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id' + belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' + + has_many :journals, :as => :journalized, :dependent => :destroy + has_many :attachments, :as => :container, :dependent => :destroy + + has_many :custom_values, :dependent => :delete_all, :as => :customized + has_many :custom_fields, :through => :custom_values + + validates_presence_of :subject, :description, :priority, :tracker, :author, :status + validates_inclusion_of :done_ratio, :in => 0..100 + validates_associated :custom_values, :on => :update + + # set default status for new issues + def before_validation + self.status = IssueStatus.default if new_record? + end + + def validate + if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? + errors.add :due_date, :activerecord_error_not_a_date + end + + if self.due_date and self.start_date and self.due_date < self.start_date + errors.add :due_date, :activerecord_error_greater_than_start_date + end + end + + #def before_create + # build_history + #end + + def before_save + if @current_journal + # attributes changes + (Issue.column_names - %w(id description)).each {|c| + @current_journal.details << JournalDetail.new(:property => 'attr', + :prop_key => c, + :old_value => @issue_before_change.send(c), + :value => send(c)) unless send(c)==@issue_before_change.send(c) + } + # custom fields changes + custom_values.each {|c| + @current_journal.details << JournalDetail.new(:property => 'cf', + :prop_key => c.custom_field_id, + :old_value => @custom_values_before_change[c.custom_field_id], + :value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value + } + @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty? + end + end + + def long_id + "%05d" % self.id + end + + def custom_value_for(custom_field) + self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id } + return nil + end + + def init_journal(user, notes = "") + @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) + @issue_before_change = self.clone + @custom_values_before_change = {} + self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } + @current_journal + end + +private + # Creates an history for the issue + #def build_history + # @history = self.histories.build + # @history.status = self.status + # @history.author = self.author + #end end diff --git a/app/models/issue_category.rb b/app/models/issue_category.rb index 74adb8f52..1a1daffb2 100644 --- a/app/models/issue_category.rb +++ b/app/models/issue_category.rb @@ -1,29 +1,29 @@ -# 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 IssueCategory < ActiveRecord::Base
- before_destroy :check_integrity
- belongs_to :project
-
- validates_presence_of :name
- validates_uniqueness_of :name, :scope => [:project_id]
-
-private
- def check_integrity
- raise "Can't delete category" if Issue.find(:first, :conditions => ["category_id=?", self.id])
+# 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 IssueCategory < ActiveRecord::Base + before_destroy :check_integrity + belongs_to :project + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:project_id] + +private + def check_integrity + raise "Can't delete category" if Issue.find(:first, :conditions => ["category_id=?", self.id]) end end diff --git a/app/models/issue_custom_field.rb b/app/models/issue_custom_field.rb index 209ae206b..7759c9059 100644 --- a/app/models/issue_custom_field.rb +++ b/app/models/issue_custom_field.rb @@ -1,27 +1,27 @@ -# 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 IssueCustomField < CustomField
- has_and_belongs_to_many :projects, :join_table => "custom_fields_projects", :foreign_key => "custom_field_id"
- has_and_belongs_to_many :trackers, :join_table => "custom_fields_trackers", :foreign_key => "custom_field_id"
- has_many :issues, :through => :issue_custom_values
-
- def type_name
- :label_issue_plural
- end
-end
+# 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 IssueCustomField < CustomField + has_and_belongs_to_many :projects, :join_table => "custom_fields_projects", :foreign_key => "custom_field_id" + has_and_belongs_to_many :trackers, :join_table => "custom_fields_trackers", :foreign_key => "custom_field_id" + has_many :issues, :through => :issue_custom_values + + def type_name + :label_issue_plural + end +end diff --git a/app/models/issue_history.rb b/app/models/issue_history.rb index 4b6682600..38366bbc3 100644 --- a/app/models/issue_history.rb +++ b/app/models/issue_history.rb @@ -1,24 +1,24 @@ -# 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.
-
+# 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 IssueHistory < ActiveRecord::Base - belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
- belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
- belongs_to :issue
-
- validates_presence_of :status
+ belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + belongs_to :issue + + validates_presence_of :status end diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb index 1a690b449..fd6194c9a 100644 --- a/app/models/issue_status.rb +++ b/app/models/issue_status.rb @@ -1,51 +1,51 @@ -# 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 IssueStatus < ActiveRecord::Base
- before_destroy :check_integrity
- has_many :workflows, :foreign_key => "old_status_id"
- acts_as_list
-
- validates_presence_of :name
- validates_uniqueness_of :name
- validates_format_of :name, :with => /^[\w\s\'\-]*$/i
- validates_length_of :html_color, :is => 6
- validates_format_of :html_color, :with => /^[a-f0-9]*$/i
-
- def before_save
- IssueStatus.update_all "is_default=#{connection.quoted_false}" if self.is_default?
- end
-
- # Returns the default status for new issues
- def self.default
- find(:first, :conditions =>["is_default=?", true])
- end
-
- # Returns an array of all statuses the given role can switch to
- def new_statuses_allowed_to(role, tracker)
- statuses = []
- for workflow in self.workflows
- statuses << workflow.new_status if workflow.role_id == role.id and workflow.tracker_id == tracker.id
- end unless role.nil? or tracker.nil?
- statuses
- end
-
-private
- def check_integrity
- raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id])
+# 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 IssueStatus < ActiveRecord::Base + before_destroy :check_integrity + has_many :workflows, :foreign_key => "old_status_id" + acts_as_list + + validates_presence_of :name + validates_uniqueness_of :name + validates_format_of :name, :with => /^[\w\s\'\-]*$/i + validates_length_of :html_color, :is => 6 + validates_format_of :html_color, :with => /^[a-f0-9]*$/i + + def before_save + IssueStatus.update_all "is_default=#{connection.quoted_false}" if self.is_default? + end + + # Returns the default status for new issues + def self.default + find(:first, :conditions =>["is_default=?", true]) + end + + # Returns an array of all statuses the given role can switch to + def new_statuses_allowed_to(role, tracker) + statuses = [] + for workflow in self.workflows + statuses << workflow.new_status if workflow.role_id == role.id and workflow.tracker_id == tracker.id + end unless role.nil? or tracker.nil? + statuses + end + +private + def check_integrity + raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id]) end end diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 42d20ecac..36bcddc2a 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -1,88 +1,88 @@ -# redMine - project management software
-# Copyright (C) 2006-2007 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 Mailer < ActionMailer::Base
+# redMine - project management software +# Copyright (C) 2006-2007 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 Mailer < ActionMailer::Base helper IssuesHelper - def issue_add(issue)
+ def issue_add(issue) + set_language_if_valid(Setting.default_language) + # Sends to all project members + @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact + @from = Setting.mail_from + @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" + @body['issue'] = issue + end + + def issue_edit(journal) set_language_if_valid(Setting.default_language) # Sends to all project members + issue = journal.journalized @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact @from = Setting.mail_from @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" - @body['issue'] = issue
- end
-
- def issue_edit(journal)
- set_language_if_valid(Setting.default_language)
- # Sends to all project members
- issue = journal.journalized
- @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact
- @from = Setting.mail_from
- @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
- @body['issue'] = issue
- @body['journal']= journal
- end
-
- def document_add(document)
- set_language_if_valid(Setting.default_language)
- @recipients = document.project.users.collect { |u| u.mail if u.mail_notification }.compact
- @from = Setting.mail_from
- @subject = "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
- @body['document'] = document
- end
-
- def attachments_add(attachments)
- set_language_if_valid(Setting.default_language)
- container = attachments.first.container
- url = "http://#{Setting.host_name}/"
- added_to = ""
- case container.class.to_s
- when 'Version'
- url << "projects/list_files/#{container.project_id}"
- added_to = "#{l(:label_version)}: #{container.name}"
- when 'Document'
- url << "documents/show/#{container.id}"
- added_to = "#{l(:label_document)}: #{container.title}"
- when 'Issue'
- url << "issues/show/#{container.id}"
- added_to = "#{container.tracker.name} ##{container.id}: #{container.subject}"
- end
- @recipients = container.project.users.collect { |u| u.mail if u.mail_notification }.compact
- @from = Setting.mail_from
- @subject = "[#{container.project.name}] #{l(:label_attachment_new)}"
- @body['attachments'] = attachments
- @body['url'] = url
- @body['added_to'] = added_to
- end
-
- def lost_password(token)
- set_language_if_valid(token.user.language)
- @recipients = token.user.mail
- @from = Setting.mail_from
- @subject = l(:mail_subject_lost_password)
- @body['token'] = token
+ @body['issue'] = issue + @body['journal']= journal + end + + def document_add(document) + set_language_if_valid(Setting.default_language) + @recipients = document.project.users.collect { |u| u.mail if u.mail_notification }.compact + @from = Setting.mail_from + @subject = "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}" + @body['document'] = document + end + + def attachments_add(attachments) + set_language_if_valid(Setting.default_language) + container = attachments.first.container + url = "http://#{Setting.host_name}/" + added_to = "" + case container.class.to_s + when 'Version' + url << "projects/list_files/#{container.project_id}" + added_to = "#{l(:label_version)}: #{container.name}" + when 'Document' + url << "documents/show/#{container.id}" + added_to = "#{l(:label_document)}: #{container.title}" + when 'Issue' + url << "issues/show/#{container.id}" + added_to = "#{container.tracker.name} ##{container.id}: #{container.subject}" + end + @recipients = container.project.users.collect { |u| u.mail if u.mail_notification }.compact + @from = Setting.mail_from + @subject = "[#{container.project.name}] #{l(:label_attachment_new)}" + @body['attachments'] = attachments + @body['url'] = url + @body['added_to'] = added_to + end + + def lost_password(token) + set_language_if_valid(token.user.language) + @recipients = token.user.mail + @from = Setting.mail_from + @subject = l(:mail_subject_lost_password) + @body['token'] = token end -
- def register(token)
- set_language_if_valid(token.user.language)
- @recipients = token.user.mail
- @from = Setting.mail_from
- @subject = l(:mail_subject_register)
- @body['token'] = token
- end
+ + def register(token) + set_language_if_valid(token.user.language) + @recipients = token.user.mail + @from = Setting.mail_from + @subject = l(:mail_subject_register) + @body['token'] = token + end end diff --git a/app/models/member.rb b/app/models/member.rb index 1214b6443..9814faa51 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -1,29 +1,29 @@ -# 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 Member < ActiveRecord::Base
- belongs_to :user
- belongs_to :role
- belongs_to :project
-
- validates_presence_of :role, :user, :project
- validates_uniqueness_of :user_id, :scope => :project_id
-
- def name
- self.user.display_name
+# 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 Member < ActiveRecord::Base + belongs_to :user + belongs_to :role + belongs_to :project + + validates_presence_of :role, :user, :project + validates_uniqueness_of :user_id, :scope => :project_id + + def name + self.user.display_name end end diff --git a/app/models/news.rb b/app/models/news.rb index 89e94f1ce..848517302 100644 --- a/app/models/news.rb +++ b/app/models/news.rb @@ -1,29 +1,29 @@ -# 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 News < ActiveRecord::Base
- belongs_to :project
- belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
- has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
-
- validates_presence_of :title, :description
-
- # returns latest news for projects visible by user
- def self.latest(user=nil, count=5)
- find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "news.created_on DESC")
+# 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 News < ActiveRecord::Base + belongs_to :project + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on" + + validates_presence_of :title, :description + + # returns latest news for projects visible by user + def self.latest(user=nil, count=5) + find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "news.created_on DESC") end end diff --git a/app/models/permission.rb b/app/models/permission.rb index 65b9253c7..3ce40d116 100644 --- a/app/models/permission.rb +++ b/app/models/permission.rb @@ -1,65 +1,65 @@ -# 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 Permission < ActiveRecord::Base
- has_and_belongs_to_many :roles
-
- validates_presence_of :controller, :action, :description
-
- GROUPS = {
- 100 => :label_project,
- 200 => :label_member_plural,
- 300 => :label_version_plural,
- 400 => :label_issue_category_plural,
- 600 => :label_query_plural,
- 1000 => :label_issue_plural,
- 1100 => :label_news_plural,
- 1200 => :label_document_plural,
- 1300 => :label_attachment_plural,
- 1400 => :label_repository
- }.freeze
-
- @@cached_perms_for_public = nil
- @@cached_perms_for_roles = nil
-
- def name
- self.controller + "/" + self.action
- end
-
- def group_id
- (self.sort / 100)*100
- end
-
- def self.allowed_to_public(action)
- @@cached_perms_for_public ||= find(:all, :conditions => ["is_public=?", true]).collect {|p| "#{p.controller}/#{p.action}"}
- @@cached_perms_for_public.include? action
- end
-
- def self.allowed_to_role(action, role)
- @@cached_perms_for_roles ||=
- begin
- perms = {}
- find(:all, :include => :roles).each {|p| perms.store "#{p.controller}/#{p.action}", p.roles.collect {|r| r.id } }
- perms
- end
- allowed_to_public(action) or (@@cached_perms_for_roles[action] and @@cached_perms_for_roles[action].include? role)
- end
-
- def self.allowed_to_role_expired
- @@cached_perms_for_roles = nil
+# 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 Permission < ActiveRecord::Base + has_and_belongs_to_many :roles + + validates_presence_of :controller, :action, :description + + GROUPS = { + 100 => :label_project, + 200 => :label_member_plural, + 300 => :label_version_plural, + 400 => :label_issue_category_plural, + 600 => :label_query_plural, + 1000 => :label_issue_plural, + 1100 => :label_news_plural, + 1200 => :label_document_plural, + 1300 => :label_attachment_plural, + 1400 => :label_repository + }.freeze + + @@cached_perms_for_public = nil + @@cached_perms_for_roles = nil + + def name + self.controller + "/" + self.action + end + + def group_id + (self.sort / 100)*100 + end + + def self.allowed_to_public(action) + @@cached_perms_for_public ||= find(:all, :conditions => ["is_public=?", true]).collect {|p| "#{p.controller}/#{p.action}"} + @@cached_perms_for_public.include? action + end + + def self.allowed_to_role(action, role) + @@cached_perms_for_roles ||= + begin + perms = {} + find(:all, :include => :roles).each {|p| perms.store "#{p.controller}/#{p.action}", p.roles.collect {|r| r.id } } + perms + end + allowed_to_public(action) or (@@cached_perms_for_roles[action] and @@cached_perms_for_roles[action].include? role) + end + + def self.allowed_to_role_expired + @@cached_perms_for_roles = nil end end diff --git a/app/models/project.rb b/app/models/project.rb index 3f9ec1680..3cf5a816a 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,71 +1,71 @@ -# 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
- has_many :versions, :dependent => :destroy, :order => "versions.effective_date DESC, versions.name DESC"
- has_many :members, :dependent => :delete_all, :include => :user, :conditions => "users.status=#{User::STATUS_ACTIVE}"
- has_many :users, :through => :members
- has_many :custom_values, :dependent => :delete_all, :as => :customized
- has_many :issues, :dependent => :destroy, :order => "issues.created_on DESC", :include => [:status, :tracker]
- has_many :queries, :dependent => :delete_all
- has_many :documents, :dependent => :destroy
- has_many :news, :dependent => :delete_all, :include => :author
- has_many :issue_categories, :dependent => :delete_all, :order => "issue_categories.name"
- has_one :repository, :dependent => :destroy
- has_one :wiki, :dependent => :destroy
- has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_projects', :association_foreign_key => 'custom_field_id'
- acts_as_tree :order => "name", :counter_cache => true
-
- validates_presence_of :name, :description
- validates_uniqueness_of :name
- validates_associated :custom_values, :on => :update
- validates_associated :repository, :wiki
- validates_format_of :name, :with => /^[\w\s\'\-]*$/i
-
- # returns latest created projects
- # non public projects will be returned only if user is a member of those
- def self.latest(user=nil, count=5)
- find(:all, :limit => count, :conditions => visible_by(user), :order => "projects.created_on DESC")
- end
-
- def self.visible_by(user=nil)
- if user && !user.memberships.empty?
- return ["projects.is_public = ? or projects.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')})", true]
- else
- return ["projects.is_public = ?", true]
- end
- end
-
- # 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)
- tracker.custom_fields.find(:all, :include => :projects,
- :conditions => ["is_for_all=? or project_id=?", true, self.id])
- #(CustomField.for_all + custom_fields).uniq
- end
-
- def all_custom_fields
- @all_custom_fields ||= IssueCustomField.find(:all, :include => :projects,
- :conditions => ["is_for_all=? or project_id=?", true, self.id])
- end
-
-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
+# 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 + has_many :versions, :dependent => :destroy, :order => "versions.effective_date DESC, versions.name DESC" + has_many :members, :dependent => :delete_all, :include => :user, :conditions => "users.status=#{User::STATUS_ACTIVE}" + has_many :users, :through => :members + has_many :custom_values, :dependent => :delete_all, :as => :customized + has_many :issues, :dependent => :destroy, :order => "issues.created_on DESC", :include => [:status, :tracker] + has_many :queries, :dependent => :delete_all + has_many :documents, :dependent => :destroy + has_many :news, :dependent => :delete_all, :include => :author + has_many :issue_categories, :dependent => :delete_all, :order => "issue_categories.name" + has_one :repository, :dependent => :destroy + has_one :wiki, :dependent => :destroy + has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_projects', :association_foreign_key => 'custom_field_id' + acts_as_tree :order => "name", :counter_cache => true + + validates_presence_of :name, :description + validates_uniqueness_of :name + validates_associated :custom_values, :on => :update + validates_associated :repository, :wiki + validates_format_of :name, :with => /^[\w\s\'\-]*$/i + + # returns latest created projects + # non public projects will be returned only if user is a member of those + def self.latest(user=nil, count=5) + find(:all, :limit => count, :conditions => visible_by(user), :order => "projects.created_on DESC") + end + + def self.visible_by(user=nil) + if user && !user.memberships.empty? + return ["projects.is_public = ? or projects.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')})", true] + else + return ["projects.is_public = ?", true] + end + end + + # 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) + tracker.custom_fields.find(:all, :include => :projects, + :conditions => ["is_for_all=? or project_id=?", true, self.id]) + #(CustomField.for_all + custom_fields).uniq + end + + def all_custom_fields + @all_custom_fields ||= IssueCustomField.find(:all, :include => :projects, + :conditions => ["is_for_all=? or project_id=?", true, self.id]) + end + +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 end end diff --git a/app/models/project_custom_field.rb b/app/models/project_custom_field.rb index baa533812..f0dab6913 100644 --- a/app/models/project_custom_field.rb +++ b/app/models/project_custom_field.rb @@ -1,22 +1,22 @@ -# 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 ProjectCustomField < CustomField
- def type_name
- :label_project_plural
- end
-end
+# 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 ProjectCustomField < CustomField + def type_name + :label_project_plural + end +end diff --git a/app/models/role.rb b/app/models/role.rb index d00a2b218..7798f3bc6 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,33 +1,33 @@ -# 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 Role < ActiveRecord::Base
- before_destroy :check_integrity
- has_and_belongs_to_many :permissions
- has_many :workflows, :dependent => :delete_all
- has_many :members
- acts_as_list
-
- validates_presence_of :name
- validates_uniqueness_of :name
- validates_format_of :name, :with => /^[\w\s\'\-]*$/i
-
-private
- def check_integrity
- raise "Can't delete role" if Member.find(:first, :conditions =>["role_id=?", self.id])
+# 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 Role < ActiveRecord::Base + before_destroy :check_integrity + has_and_belongs_to_many :permissions + has_many :workflows, :dependent => :delete_all + has_many :members + acts_as_list + + validates_presence_of :name + validates_uniqueness_of :name + validates_format_of :name, :with => /^[\w\s\'\-]*$/i + +private + def check_integrity + raise "Can't delete role" if Member.find(:first, :conditions =>["role_id=?", self.id]) end end diff --git a/app/models/svn_repos.rb b/app/models/svn_repos.rb index aed9f1b58..3ed81403d 100644 --- a/app/models/svn_repos.rb +++ b/app/models/svn_repos.rb @@ -1,216 +1,216 @@ -# 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.
-
-require 'rexml/document'
-
-module SvnRepos
-
- class CommandFailed < StandardError #:nodoc:
- end
-
- class Base
-
- def initialize(url, login=nil, password=nil)
- @url = url
- @login = login if login && !login.empty?
- @password = (password || "") if @login
- end
-
- # Returns the entry identified by path and revision identifier
- # or nil if entry doesn't exist in the repository
- def entry(path=nil, identifier=nil)
- e = entries(path, identifier)
- e ? e.first : nil
- end
-
- # Returns an Entries collection
- # or nil if the given path doesn't exist in the repository
- def entries(path=nil, identifier=nil)
- path ||= ''
- identifier = 'HEAD' unless identifier and identifier > 0
- entries = Entries.new
- cmd = "svn list --xml #{target(path)}@#{identifier}"
- cmd << " --username #{@login} --password #{@password}" if @login
- shellout(cmd) do |io|
- begin
- doc = REXML::Document.new(io)
- doc.elements.each("lists/list/entry") do |entry|
- entries << Entry.new({:name => entry.elements['name'].text,
- :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text),
- :kind => entry.attributes['kind'],
- :size => (entry.elements['size'] and entry.elements['size'].text).to_i,
- :lastrev => Revision.new({
- :identifier => entry.elements['commit'].attributes['revision'],
- :time => Time.parse(entry.elements['commit'].elements['date'].text),
- :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "anonymous")
- })
- })
- end
- rescue
- end
- end
- return nil if $? && $?.exitstatus != 0
- entries.sort_by_name
- rescue Errno::ENOENT => e
- raise CommandFailed
- end
-
- def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
- path ||= ''
- identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
- identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
- revisions = Revisions.new
- cmd = "svn log --xml -r #{identifier_from}:#{identifier_to}"
- cmd << " --username #{@login} --password #{@password}" if @login
- cmd << " --verbose " if options[:with_paths]
- cmd << target(path)
- shellout(cmd) do |io|
- begin
- doc = REXML::Document.new(io)
- doc.elements.each("log/logentry") do |logentry|
- paths = []
- logentry.elements.each("paths/path") do |path|
- paths << {:action => path.attributes['action'],
- :path => path.text
- }
- end
- paths.sort! { |x,y| x[:path] <=> y[:path] }
-
- revisions << Revision.new({:identifier => logentry.attributes['revision'],
- :author => (logentry.elements['author'] ? logentry.elements['author'].text : "anonymous"),
- :time => Time.parse(logentry.elements['date'].text),
- :message => logentry.elements['msg'].text,
- :paths => paths
- })
- end
- rescue
- end
- end
- return nil if $? && $?.exitstatus != 0
- revisions
- rescue Errno::ENOENT => e
- raise CommandFailed
- end
-
- def diff(path, identifier_from, identifier_to=nil)
- path ||= ''
- if identifier_to and identifier_to.to_i > 0
- identifier_to = identifier_to.to_i
- else
- identifier_to = identifier_from.to_i - 1
- end
- cmd = "svn diff -r "
- cmd << "#{identifier_to}:"
- cmd << "#{identifier_from}"
- cmd << "#{target(path)}@#{identifier_from}"
- cmd << " --username #{@login} --password #{@password}" if @login
- diff = []
- shellout(cmd) do |io|
- io.each_line do |line|
- diff << line
- end
- end
- return nil if $? && $?.exitstatus != 0
- diff
- rescue Errno::ENOENT => e
- raise CommandFailed
- end
-
- def cat(path, identifier=nil)
- identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
- cmd = "svn cat #{target(path)}@#{identifier}"
- cmd << " --username #{@login} --password #{@password}" if @login
- cat = nil
- shellout(cmd) do |io|
- cat = io.read
- end
- return nil if $? && $?.exitstatus != 0
- cat
- rescue Errno::ENOENT => e
- raise CommandFailed
- end
-
- private
- def target(path)
- " \"" << "#{@url}/#{path}".gsub(/["'?<>\*]/, '') << "\""
- end
-
- def logger
- RAILS_DEFAULT_LOGGER
- end
-
- def shellout(cmd, &block)
- logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
- IO.popen(cmd, "r+") do |io|
- io.close_write
- block.call(io) if block_given?
- end
- end
- end
-
- class Entries < Array
- def sort_by_name
- sort {|x,y|
- if x.kind == y.kind
- x.name <=> y.name
- else
- x.kind <=> y.kind
- end
- }
- end
-
- def revisions
- revisions ||= Revisions.new(collect{|entry| entry.lastrev})
- end
- end
-
- class Entry
- attr_accessor :name, :path, :kind, :size, :lastrev
- def initialize(attributes={})
- self.name = attributes[:name] if attributes[:name]
- self.path = attributes[:path] if attributes[:path]
- self.kind = attributes[:kind] if attributes[:kind]
- self.size = attributes[:size].to_i if attributes[:size]
- self.lastrev = attributes[:lastrev]
- end
-
- def is_file?
- 'file' == self.kind
- end
-
- def is_dir?
- 'dir' == self.kind
- end
- end
-
- class Revisions < Array
- def latest
- sort {|x,y| x.time <=> y.time}.last
- end
- end
-
- class Revision
- attr_accessor :identifier, :author, :time, :message, :paths
- def initialize(attributes={})
- self.identifier = attributes[:identifier]
- self.author = attributes[:author]
- self.time = attributes[:time]
- self.message = attributes[:message] || ""
- self.paths = attributes[:paths]
- end
- end
+# 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. + +require 'rexml/document' + +module SvnRepos + + class CommandFailed < StandardError #:nodoc: + end + + class Base + + def initialize(url, login=nil, password=nil) + @url = url + @login = login if login && !login.empty? + @password = (password || "") if @login + end + + # Returns the entry identified by path and revision identifier + # or nil if entry doesn't exist in the repository + def entry(path=nil, identifier=nil) + e = entries(path, identifier) + e ? e.first : nil + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil) + path ||= '' + identifier = 'HEAD' unless identifier and identifier > 0 + entries = Entries.new + cmd = "svn list --xml #{target(path)}@#{identifier}" + cmd << " --username #{@login} --password #{@password}" if @login + shellout(cmd) do |io| + begin + doc = REXML::Document.new(io) + doc.elements.each("lists/list/entry") do |entry| + entries << Entry.new({:name => entry.elements['name'].text, + :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text), + :kind => entry.attributes['kind'], + :size => (entry.elements['size'] and entry.elements['size'].text).to_i, + :lastrev => Revision.new({ + :identifier => entry.elements['commit'].attributes['revision'], + :time => Time.parse(entry.elements['commit'].elements['date'].text), + :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "anonymous") + }) + }) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + entries.sort_by_name + rescue Errno::ENOENT => e + raise CommandFailed + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + path ||= '' + identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0 + identifier_to = 1 unless identifier_to and identifier_to.to_i > 0 + revisions = Revisions.new + cmd = "svn log --xml -r #{identifier_from}:#{identifier_to}" + cmd << " --username #{@login} --password #{@password}" if @login + cmd << " --verbose " if options[:with_paths] + cmd << target(path) + shellout(cmd) do |io| + begin + doc = REXML::Document.new(io) + doc.elements.each("log/logentry") do |logentry| + paths = [] + logentry.elements.each("paths/path") do |path| + paths << {:action => path.attributes['action'], + :path => path.text + } + end + paths.sort! { |x,y| x[:path] <=> y[:path] } + + revisions << Revision.new({:identifier => logentry.attributes['revision'], + :author => (logentry.elements['author'] ? logentry.elements['author'].text : "anonymous"), + :time => Time.parse(logentry.elements['date'].text), + :message => logentry.elements['msg'].text, + :paths => paths + }) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + revisions + rescue Errno::ENOENT => e + raise CommandFailed + end + + def diff(path, identifier_from, identifier_to=nil) + path ||= '' + if identifier_to and identifier_to.to_i > 0 + identifier_to = identifier_to.to_i + else + identifier_to = identifier_from.to_i - 1 + end + cmd = "svn diff -r " + cmd << "#{identifier_to}:" + cmd << "#{identifier_from}" + cmd << "#{target(path)}@#{identifier_from}" + cmd << " --username #{@login} --password #{@password}" if @login + diff = [] + shellout(cmd) do |io| + io.each_line do |line| + diff << line + end + end + return nil if $? && $?.exitstatus != 0 + diff + rescue Errno::ENOENT => e + raise CommandFailed + end + + def cat(path, identifier=nil) + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + cmd = "svn cat #{target(path)}@#{identifier}" + cmd << " --username #{@login} --password #{@password}" if @login + cat = nil + shellout(cmd) do |io| + cat = io.read + end + return nil if $? && $?.exitstatus != 0 + cat + rescue Errno::ENOENT => e + raise CommandFailed + end + + private + def target(path) + " \"" << "#{@url}/#{path}".gsub(/["'?<>\*]/, '') << "\"" + end + + def logger + RAILS_DEFAULT_LOGGER + end + + def shellout(cmd, &block) + logger.debug "Shelling out: #{cmd}" if logger && logger.debug? + IO.popen(cmd, "r+") do |io| + io.close_write + block.call(io) if block_given? + end + end + end + + class Entries < Array + def sort_by_name + sort {|x,y| + if x.kind == y.kind + x.name <=> y.name + else + x.kind <=> y.kind + end + } + end + + def revisions + revisions ||= Revisions.new(collect{|entry| entry.lastrev}) + end + end + + class Entry + attr_accessor :name, :path, :kind, :size, :lastrev + def initialize(attributes={}) + self.name = attributes[:name] if attributes[:name] + self.path = attributes[:path] if attributes[:path] + self.kind = attributes[:kind] if attributes[:kind] + self.size = attributes[:size].to_i if attributes[:size] + self.lastrev = attributes[:lastrev] + end + + def is_file? + 'file' == self.kind + end + + def is_dir? + 'dir' == self.kind + end + end + + class Revisions < Array + def latest + sort {|x,y| x.time <=> y.time}.last + end + end + + class Revision + attr_accessor :identifier, :author, :time, :message, :paths + def initialize(attributes={}) + self.identifier = attributes[:identifier] + self.author = attributes[:author] + self.time = attributes[:time] + self.message = attributes[:message] || "" + self.paths = attributes[:paths] + end + end end
\ No newline at end of file diff --git a/app/models/tracker.rb b/app/models/tracker.rb index b584704c2..51ae73d1c 100644 --- a/app/models/tracker.rb +++ b/app/models/tracker.rb @@ -1,33 +1,33 @@ -# 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 Tracker < ActiveRecord::Base
- before_destroy :check_integrity
- has_many :issues
- has_many :workflows, :dependent => :delete_all
- has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_trackers', :association_foreign_key => 'custom_field_id'
- acts_as_list
-
- validates_presence_of :name
- validates_uniqueness_of :name
- validates_format_of :name, :with => /^[\w\s\'\-]*$/i
-
-private
- def check_integrity
- raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id])
+# 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 Tracker < ActiveRecord::Base + before_destroy :check_integrity + has_many :issues + has_many :workflows, :dependent => :delete_all + has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_trackers', :association_foreign_key => 'custom_field_id' + acts_as_list + + validates_presence_of :name + validates_uniqueness_of :name + validates_format_of :name, :with => /^[\w\s\'\-]*$/i + +private + def check_integrity + raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id]) end end diff --git a/app/models/user.rb b/app/models/user.rb index bf2930a0f..3a315239c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,142 +1,142 @@ -# redMine - project management software
-# Copyright (C) 2006-2007 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.
-
-require "digest/sha1"
-
-class User < ActiveRecord::Base
- has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => :delete_all
- has_many :projects, :through => :memberships
- has_many :custom_values, :dependent => :delete_all, :as => :customized
- has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
- belongs_to :auth_source
-
- attr_accessor :password, :password_confirmation
- attr_accessor :last_before_login_on
- # Prevents unauthorized assignments
- attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
-
- validates_presence_of :login, :firstname, :lastname, :mail
- validates_uniqueness_of :login, :mail
- # Login must contain lettres, numbers, underscores only
- validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-]*$/i
- validates_format_of :login, :with => /^[a-z0-9_\-@\.]+$/i
- validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
- # Password length between 4 and 12
- validates_length_of :password, :in => 4..12, :allow_nil => true
- validates_confirmation_of :password, :allow_nil => true
- validates_associated :custom_values, :on => :update
-
- # Account statuses
- STATUS_ACTIVE = 1
- STATUS_REGISTERED = 2
- STATUS_LOCKED = 3
-
- def before_save
- # update hashed_password if password was set
- self.hashed_password = User.hash_password(self.password) if self.password
- end
-
- def self.active
- with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do
- yield
- end
- end
-
- def self.find_active(*args)
- active do
- find(*args)
- end
- end
-
- # Returns the user that matches provided login and password, or nil
- def self.try_to_login(login, password)
- user = find(:first, :conditions => ["login=?", login])
- if user
- # user is already in local database
- return nil if !user.active?
- if user.auth_source
- # user has an external authentication method
- return nil unless user.auth_source.authenticate(login, password)
- else
- # authentication with local password
- return nil unless User.hash_password(password) == user.hashed_password
- end
- else
- # user is not yet registered, try to authenticate with available sources
- attrs = AuthSource.authenticate(login, password)
- if attrs
- onthefly = new(*attrs)
- onthefly.login = login
- onthefly.language = Setting.default_language
- if onthefly.save
- user = find(:first, :conditions => ["login=?", login])
- logger.info("User '#{user.login}' created on the fly.") if logger
- end
- end
- end
- user.update_attribute(:last_login_on, Time.now) if user
- user
-
- rescue => text
- raise text
- end
-
- # Return user's full name for display
- def display_name
- firstname + " " + lastname
- end
-
- def name
- display_name
- end
-
- def active?
- self.status == STATUS_ACTIVE
- end
-
- def registered?
- self.status == STATUS_REGISTERED
- end
-
- def locked?
- self.status == STATUS_LOCKED
- end
-
- def check_password?(clear_password)
- User.hash_password(clear_password) == self.hashed_password
- end
-
- def role_for_project(project_id)
- @role_for_projects ||=
- begin
- roles = {}
- self.memberships.each { |m| roles.store m.project_id, m.role_id }
- roles
- end
- @role_for_projects[project_id]
- end
-
- def pref
- self.preference ||= UserPreference.new(:user => self)
- end
-
-private
- # Return password digest
- def self.hash_password(clear_password)
- Digest::SHA1.hexdigest(clear_password || "")
+# redMine - project management software +# Copyright (C) 2006-2007 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. + +require "digest/sha1" + +class User < ActiveRecord::Base + has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => :delete_all + has_many :projects, :through => :memberships + has_many :custom_values, :dependent => :delete_all, :as => :customized + has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' + belongs_to :auth_source + + attr_accessor :password, :password_confirmation + attr_accessor :last_before_login_on + # Prevents unauthorized assignments + attr_protected :login, :admin, :password, :password_confirmation, :hashed_password + + validates_presence_of :login, :firstname, :lastname, :mail + validates_uniqueness_of :login, :mail + # Login must contain lettres, numbers, underscores only + validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-]*$/i + validates_format_of :login, :with => /^[a-z0-9_\-@\.]+$/i + validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i + # Password length between 4 and 12 + validates_length_of :password, :in => 4..12, :allow_nil => true + validates_confirmation_of :password, :allow_nil => true + validates_associated :custom_values, :on => :update + + # Account statuses + STATUS_ACTIVE = 1 + STATUS_REGISTERED = 2 + STATUS_LOCKED = 3 + + def before_save + # update hashed_password if password was set + self.hashed_password = User.hash_password(self.password) if self.password + end + + def self.active + with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do + yield + end + end + + def self.find_active(*args) + active do + find(*args) + end + end + + # Returns the user that matches provided login and password, or nil + def self.try_to_login(login, password) + user = find(:first, :conditions => ["login=?", login]) + if user + # user is already in local database + return nil if !user.active? + if user.auth_source + # user has an external authentication method + return nil unless user.auth_source.authenticate(login, password) + else + # authentication with local password + return nil unless User.hash_password(password) == user.hashed_password + end + else + # user is not yet registered, try to authenticate with available sources + attrs = AuthSource.authenticate(login, password) + if attrs + onthefly = new(*attrs) + onthefly.login = login + onthefly.language = Setting.default_language + if onthefly.save + user = find(:first, :conditions => ["login=?", login]) + logger.info("User '#{user.login}' created on the fly.") if logger + end + end + end + user.update_attribute(:last_login_on, Time.now) if user + user + + rescue => text + raise text + end + + # Return user's full name for display + def display_name + firstname + " " + lastname + end + + def name + display_name + end + + def active? + self.status == STATUS_ACTIVE + end + + def registered? + self.status == STATUS_REGISTERED + end + + def locked? + self.status == STATUS_LOCKED + end + + def check_password?(clear_password) + User.hash_password(clear_password) == self.hashed_password + end + + def role_for_project(project_id) + @role_for_projects ||= + begin + roles = {} + self.memberships.each { |m| roles.store m.project_id, m.role_id } + roles + end + @role_for_projects[project_id] + end + + def pref + self.preference ||= UserPreference.new(:user => self) + end + +private + # Return password digest + def self.hash_password(clear_password) + Digest::SHA1.hexdigest(clear_password || "") end end diff --git a/app/models/user_custom_field.rb b/app/models/user_custom_field.rb index 866234a7f..99e76eea5 100644 --- a/app/models/user_custom_field.rb +++ b/app/models/user_custom_field.rb @@ -1,23 +1,23 @@ -# 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 UserCustomField < CustomField
- def type_name
- :label_user_plural
- end
-end
+# 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 UserCustomField < CustomField + def type_name + :label_user_plural + end +end diff --git a/app/models/version.rb b/app/models/version.rb index 71a8a8807..611500c8c 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -1,32 +1,32 @@ -# 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 Version < ActiveRecord::Base
- before_destroy :check_integrity
- belongs_to :project
- has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
- has_many :attachments, :as => :container, :dependent => :destroy
-
- validates_presence_of :name
- validates_uniqueness_of :name, :scope => [:project_id]
- validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date
-
-private
- def check_integrity
- raise "Can't delete version" if self.fixed_issues.find(:first)
- end
+# 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 Version < ActiveRecord::Base + before_destroy :check_integrity + belongs_to :project + has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id' + has_many :attachments, :as => :container, :dependent => :destroy + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:project_id] + validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date + +private + def check_integrity + raise "Can't delete version" if self.fixed_issues.find(:first) + end end diff --git a/app/models/workflow.rb b/app/models/workflow.rb index 22c873fc7..89322aa58 100644 --- a/app/models/workflow.rb +++ b/app/models/workflow.rb @@ -1,24 +1,24 @@ -# 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 Workflow < ActiveRecord::Base
- belongs_to :role
- belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id'
- belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id'
-
- validates_presence_of :role, :old_status, :new_status
+# 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 Workflow < ActiveRecord::Base + belongs_to :role + belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id' + belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id' + + validates_presence_of :role, :old_status, :new_status end |