##// END OF EJS Templates
Added several validates_length_of...
Jean-Philippe Lang -
r590:fcefdb22bfc3
parent child
Show More
@@ -1,96 +1,98
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require "digest/md5"
19 19
20 20 class Attachment < ActiveRecord::Base
21 21 belongs_to :container, :polymorphic => true
22 22 belongs_to :author, :class_name => "User", :foreign_key => "author_id"
23 23
24 24 validates_presence_of :container, :filename
25
25 validates_length_of :filename, :maximum => 255
26 validates_length_of :disk_filename, :maximum => 255
27
26 28 cattr_accessor :storage_path
27 29 @@storage_path = "#{RAILS_ROOT}/files"
28 30
29 31 def validate
30 32 errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes
31 33 end
32 34
33 35 def file=(incomming_file)
34 36 unless incomming_file.nil?
35 37 @temp_file = incomming_file
36 38 if @temp_file.size > 0
37 39 self.filename = sanitize_filename(@temp_file.original_filename)
38 40 self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename
39 41 self.content_type = @temp_file.content_type
40 42 self.filesize = @temp_file.size
41 43 end
42 44 end
43 45 end
44 46
45 47 def file
46 48 nil
47 49 end
48 50
49 51 # Copy temp file to its final location
50 52 def before_save
51 53 if @temp_file && (@temp_file.size > 0)
52 54 logger.debug("saving '#{self.diskfile}'")
53 55 File.open(diskfile, "wb") do |f|
54 56 f.write(@temp_file.read)
55 57 end
56 58 self.digest = Digest::MD5.hexdigest(File.read(diskfile))
57 59 end
58 60 end
59 61
60 62 # Deletes file on the disk
61 63 def after_destroy
62 64 if self.filename?
63 65 File.delete(diskfile) if File.exist?(diskfile)
64 66 end
65 67 end
66 68
67 69 # Returns file's location on disk
68 70 def diskfile
69 71 "#{@@storage_path}/#{self.disk_filename}"
70 72 end
71 73
72 74 def increment_download
73 75 increment!(:downloads)
74 76 end
75 77
76 78 # returns last created projects
77 79 def self.most_downloaded
78 80 find(:all, :limit => 5, :order => "downloads DESC")
79 81 end
80 82
81 83 def project
82 84 container.is_a?(Project) ? container : container.project
83 85 end
84 86
85 87 private
86 88 def sanitize_filename(value)
87 89 # get only the filename, not the whole path
88 90 just_filename = value.gsub(/^.*(\\|\/)/, '')
89 91 # NOTE: File.basename doesn't work right with Windows paths on Unix
90 92 # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
91 93
92 94 # Finally, replace all non alphanumeric, underscore or periods with underscore
93 95 @filename = just_filename.gsub(/[^\w\.\-]/,'_')
94 96 end
95 97
96 98 end
@@ -1,60 +1,61
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class CustomField < ActiveRecord::Base
19 19 has_many :custom_values, :dependent => :delete_all
20 20 serialize :possible_values
21 21
22 22 FIELD_FORMATS = { "string" => { :name => :label_string, :order => 1 },
23 23 "text" => { :name => :label_text, :order => 2 },
24 24 "int" => { :name => :label_integer, :order => 3 },
25 25 "list" => { :name => :label_list, :order => 4 },
26 26 "date" => { :name => :label_date, :order => 5 },
27 27 "bool" => { :name => :label_boolean, :order => 6 }
28 28 }.freeze
29 29
30 30 validates_presence_of :name, :field_format
31 31 validates_uniqueness_of :name
32 validates_length_of :name, :maximum => 30
32 33 validates_format_of :name, :with => /^[\w\s\'\-]*$/i
33 34 validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys
34 35
35 36 def initialize(attributes = nil)
36 37 super
37 38 self.possible_values ||= []
38 39 end
39 40
40 41 def before_validation
41 42 # remove empty values
42 43 self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact
43 44 end
44 45
45 46 def validate
46 47 if self.field_format == "list"
47 48 errors.add(:possible_values, :activerecord_error_blank) if self.possible_values.nil? || self.possible_values.empty?
48 49 errors.add(:possible_values, :activerecord_error_invalid) unless self.possible_values.is_a? Array
49 50 end
50 51 end
51 52
52 53 # to move in project_custom_field
53 54 def self.for_all
54 55 find(:all, :conditions => ["is_for_all=?", true])
55 56 end
56 57
57 58 def type_name
58 59 nil
59 60 end
60 61 end
@@ -1,24 +1,25
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Document < ActiveRecord::Base
19 19 belongs_to :project
20 20 belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id"
21 21 has_many :attachments, :as => :container, :dependent => :destroy
22 22
23 23 validates_presence_of :project, :title, :category
24 validates_length_of :title, :maximum => 60
24 25 end
@@ -1,50 +1,51
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Enumeration < ActiveRecord::Base
19 19 before_destroy :check_integrity
20 20
21 21 validates_presence_of :opt, :name
22 22 validates_uniqueness_of :name, :scope => [:opt]
23 validates_length_of :name, :maximum => 30
23 24 validates_format_of :name, :with => /^[\w\s\'\-]*$/i
24 25
25 26 OPTIONS = {
26 27 "IPRI" => :enumeration_issue_priorities,
27 28 "DCAT" => :enumeration_doc_categories,
28 29 "ACTI" => :enumeration_activities
29 30 }.freeze
30 31
31 32 def self.get_values(option)
32 33 find(:all, :conditions => ['opt=?', option])
33 34 end
34 35
35 36 def option_name
36 37 OPTIONS[self.opt]
37 38 end
38 39
39 40 private
40 41 def check_integrity
41 42 case self.opt
42 43 when "IPRI"
43 44 raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id])
44 45 when "DCAT"
45 46 raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id])
46 47 when "ACTI"
47 48 raise "Can't delete enumeration" if TimeEntry.find(:first, :conditions => ["activity_id=?", self.id])
48 49 end
49 50 end
50 51 end
@@ -1,131 +1,132
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Issue < ActiveRecord::Base
19 19 belongs_to :project
20 20 belongs_to :tracker
21 21 belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
22 22 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
23 23 belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
24 24 belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
25 25 belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
26 26 belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
27 27
28 28 has_many :journals, :as => :journalized, :dependent => :destroy
29 29 has_many :attachments, :as => :container, :dependent => :destroy
30 30 has_many :time_entries, :dependent => :nullify
31 31 has_many :custom_values, :dependent => :delete_all, :as => :customized
32 32 has_many :custom_fields, :through => :custom_values
33 33 has_and_belongs_to_many :changesets, :order => "revision ASC"
34 34
35 35 has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
36 36 has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
37 37
38 38 acts_as_watchable
39 39
40 40 validates_presence_of :subject, :description, :priority, :tracker, :author, :status
41 validates_length_of :subject, :maximum => 255
41 42 validates_inclusion_of :done_ratio, :in => 0..100
42 43 validates_associated :custom_values, :on => :update
43 44
44 45 # set default status for new issues
45 46 def before_validation
46 47 self.status = IssueStatus.default if status.nil?
47 48 end
48 49
49 50 def validate
50 51 if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
51 52 errors.add :due_date, :activerecord_error_not_a_date
52 53 end
53 54
54 55 if self.due_date and self.start_date and self.due_date < self.start_date
55 56 errors.add :due_date, :activerecord_error_greater_than_start_date
56 57 end
57 58
58 59 if start_date && soonest_start && start_date < soonest_start
59 60 errors.add :start_date, :activerecord_error_invalid
60 61 end
61 62 end
62 63
63 64 def before_create
64 65 # default assignment based on category
65 66 if assigned_to.nil? && category && category.assigned_to
66 67 self.assigned_to = category.assigned_to
67 68 end
68 69 end
69 70
70 71 def before_save
71 72 if @current_journal
72 73 # attributes changes
73 74 (Issue.column_names - %w(id description)).each {|c|
74 75 @current_journal.details << JournalDetail.new(:property => 'attr',
75 76 :prop_key => c,
76 77 :old_value => @issue_before_change.send(c),
77 78 :value => send(c)) unless send(c)==@issue_before_change.send(c)
78 79 }
79 80 # custom fields changes
80 81 custom_values.each {|c|
81 82 @current_journal.details << JournalDetail.new(:property => 'cf',
82 83 :prop_key => c.custom_field_id,
83 84 :old_value => @custom_values_before_change[c.custom_field_id],
84 85 :value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value
85 86 }
86 87 @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty?
87 88 end
88 89 end
89 90
90 91 def after_save
91 92 relations_from.each(&:set_issue_to_dates)
92 93 end
93 94
94 95 def custom_value_for(custom_field)
95 96 self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id }
96 97 return nil
97 98 end
98 99
99 100 def init_journal(user, notes = "")
100 101 @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
101 102 @issue_before_change = self.clone
102 103 @custom_values_before_change = {}
103 104 self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
104 105 @current_journal
105 106 end
106 107
107 108 def spent_hours
108 109 @spent_hours ||= time_entries.sum(:hours) || 0
109 110 end
110 111
111 112 def relations
112 113 (relations_from + relations_to).sort
113 114 end
114 115
115 116 def all_dependent_issues
116 117 dependencies = []
117 118 relations_from.each do |relation|
118 119 dependencies << relation.issue_to
119 120 dependencies += relation.issue_to.all_dependent_issues
120 121 end
121 122 dependencies
122 123 end
123 124
124 125 def duration
125 126 (start_date && due_date) ? due_date - start_date : 0
126 127 end
127 128
128 129 def soonest_start
129 130 @soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min
130 131 end
131 132 end
@@ -1,58 +1,59
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class IssueStatus < ActiveRecord::Base
19 19 before_destroy :check_integrity
20 20 has_many :workflows, :foreign_key => "old_status_id", :dependent => :delete_all
21 21 acts_as_list
22 22
23 23 validates_presence_of :name
24 24 validates_uniqueness_of :name
25 validates_length_of :name, :maximum => 30
25 26 validates_format_of :name, :with => /^[\w\s\'\-]*$/i
26 27 validates_length_of :html_color, :is => 6
27 28 validates_format_of :html_color, :with => /^[a-f0-9]*$/i
28 29
29 30 def before_save
30 31 IssueStatus.update_all "is_default=#{connection.quoted_false}" if self.is_default?
31 32 end
32 33
33 34 # Returns the default status for new issues
34 35 def self.default
35 36 find(:first, :conditions =>["is_default=?", true])
36 37 end
37 38
38 39 # Returns an array of all statuses the given role can switch to
39 40 # Uses association cache when called more than one time
40 41 def new_statuses_allowed_to(role, tracker)
41 42 new_statuses = workflows.select {|w| w.role_id == role.id && w.tracker_id == tracker.id}.collect{|w| w.new_status} if role && tracker
42 43 new_statuses ? new_statuses.compact.sort{|x, y| x.position <=> y.position } : []
43 44 end
44 45
45 46 # Same thing as above but uses a database query
46 47 # More efficient than the previous method if called just once
47 48 def find_new_statuses_allowed_to(role, tracker)
48 49 new_statuses = workflows.find(:all,
49 50 :include => :new_status,
50 51 :conditions => ["role_id=? and tracker_id=?", role.id, tracker.id]).collect{ |w| w.new_status }.compact if role && tracker
51 52 new_statuses ? new_statuses.sort{|x, y| x.position <=> y.position } : []
52 53 end
53 54
54 55 private
55 56 def check_integrity
56 57 raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id])
57 58 end
58 59 end
@@ -1,29 +1,31
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class News < ActiveRecord::Base
19 19 belongs_to :project
20 20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
21 21 has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
22 22
23 23 validates_presence_of :title, :description
24 validates_length_of :title, :maximum => 60
25 validates_length_of :summary, :maximum => 255
24 26
25 27 # returns latest news for projects visible by user
26 28 def self.latest(user=nil, count=5)
27 29 find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
28 30 end
29 31 end
@@ -1,239 +1,240
1 1 # redMine - project management software
2 2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Query < ActiveRecord::Base
19 19 belongs_to :project
20 20 belongs_to :user
21 21 serialize :filters
22 22
23 23 attr_protected :project, :user
24 24 attr_accessor :executed_by
25 25
26 26 validates_presence_of :name, :on => :save
27 validates_length_of :name, :maximum => 255
27 28
28 29 @@operators = { "=" => :label_equals,
29 30 "!" => :label_not_equals,
30 31 "o" => :label_open_issues,
31 32 "c" => :label_closed_issues,
32 33 "!*" => :label_none,
33 34 "*" => :label_all,
34 35 "<t+" => :label_in_less_than,
35 36 ">t+" => :label_in_more_than,
36 37 "t+" => :label_in,
37 38 "t" => :label_today,
38 39 ">t-" => :label_less_than_ago,
39 40 "<t-" => :label_more_than_ago,
40 41 "t-" => :label_ago,
41 42 "~" => :label_contains,
42 43 "!~" => :label_not_contains }
43 44
44 45 cattr_reader :operators
45 46
46 47 @@operators_by_filter_type = { :list => [ "=", "!" ],
47 48 :list_status => [ "o", "=", "!", "c", "*" ],
48 49 :list_optional => [ "=", "!", "!*", "*" ],
49 50 :list_one_or_more => [ "*", "=" ],
50 51 :date => [ "<t+", ">t+", "t+", "t", ">t-", "<t-", "t-" ],
51 52 :date_past => [ ">t-", "<t-", "t-", "t" ],
52 53 :string => [ "=", "~", "!", "!~" ],
53 54 :text => [ "~", "!~" ] }
54 55
55 56 cattr_reader :operators_by_filter_type
56 57
57 58 def initialize(attributes = nil)
58 59 super attributes
59 60 self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} }
60 61 end
61 62
62 63 def executed_by=(user)
63 64 @executed_by = user
64 65 set_language_if_valid(user.language) if user
65 66 end
66 67
67 68 def validate
68 69 filters.each_key do |field|
69 70 errors.add label_for(field), :activerecord_error_blank unless
70 71 # filter requires one or more values
71 72 (values_for(field) and !values_for(field).first.empty?) or
72 73 # filter doesn't require any value
73 74 ["o", "c", "!*", "*", "t"].include? operator_for(field)
74 75 end if filters
75 76 end
76 77
77 78 def editable_by?(user)
78 79 return false unless user
79 80 return true if !is_public && self.user_id == user.id
80 81 is_public && user.authorized_to(project, "projects/add_query")
81 82 end
82 83
83 84 def available_filters
84 85 return @available_filters if @available_filters
85 86 @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },
86 87 "tracker_id" => { :type => :list, :order => 2, :values => Tracker.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },
87 88 "priority_id" => { :type => :list, :order => 3, :values => Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect{|s| [s.name, s.id.to_s] } },
88 89 "subject" => { :type => :text, :order => 8 },
89 90 "created_on" => { :type => :date_past, :order => 9 },
90 91 "updated_on" => { :type => :date_past, :order => 10 },
91 92 "start_date" => { :type => :date, :order => 11 },
92 93 "due_date" => { :type => :date, :order => 12 } }
93 94 unless project.nil?
94 95 # project specific filters
95 96 user_values = []
96 97 user_values << ["<< #{l(:label_me)} >>", "me"] if executed_by
97 98 user_values += @project.users.collect{|s| [s.name, s.id.to_s] }
98 99
99 100 @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values }
100 101 @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values }
101 102 @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
102 103 @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
103 104 unless @project.active_children.empty?
104 105 @available_filters["subproject_id"] = { :type => :list_one_or_more, :order => 13, :values => @project.active_children.collect{|s| [s.name, s.id.to_s] } }
105 106 end
106 107 @project.all_custom_fields.select(&:is_filter?).each do |field|
107 108 case field.field_format
108 109 when "string", "int"
109 110 options = { :type => :string, :order => 20 }
110 111 when "text"
111 112 options = { :type => :text, :order => 20 }
112 113 when "list"
113 114 options = { :type => :list_optional, :values => field.possible_values, :order => 20}
114 115 when "date"
115 116 options = { :type => :date, :order => 20 }
116 117 when "bool"
117 118 options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]], :order => 20 }
118 119 end
119 120 @available_filters["cf_#{field.id}"] = options.merge({ :name => field.name })
120 121 end
121 122 # remove category filter if no category defined
122 123 @available_filters.delete "category_id" if @available_filters["category_id"][:values].empty?
123 124 end
124 125 @available_filters
125 126 end
126 127
127 128 def add_filter(field, operator, values)
128 129 # values must be an array
129 130 return unless values and values.is_a? Array # and !values.first.empty?
130 131 # check if field is defined as an available filter
131 132 if available_filters.has_key? field
132 133 filter_options = available_filters[field]
133 134 # check if operator is allowed for that filter
134 135 #if @@operators_by_filter_type[filter_options[:type]].include? operator
135 136 # allowed_values = values & ([""] + (filter_options[:values] || []).collect {|val| val[1]})
136 137 # filters[field] = {:operator => operator, :values => allowed_values } if (allowed_values.first and !allowed_values.first.empty?) or ["o", "c", "!*", "*", "t"].include? operator
137 138 #end
138 139 filters[field] = {:operator => operator, :values => values }
139 140 end
140 141 end
141 142
142 143 def add_short_filter(field, expression)
143 144 return unless expression
144 145 parms = expression.scan(/^(o|c|\!|\*)?(.*)$/).first
145 146 add_filter field, (parms[0] || "="), [parms[1] || ""]
146 147 end
147 148
148 149 def has_filter?(field)
149 150 filters and filters[field]
150 151 end
151 152
152 153 def operator_for(field)
153 154 has_filter?(field) ? filters[field][:operator] : nil
154 155 end
155 156
156 157 def values_for(field)
157 158 has_filter?(field) ? filters[field][:values] : nil
158 159 end
159 160
160 161 def label_for(field)
161 162 label = @available_filters[field][:name] if @available_filters.has_key?(field)
162 163 label ||= field.gsub(/\_id$/, "")
163 164 end
164 165
165 166 def statement
166 167 sql = "1=1"
167 168 if has_filter?("subproject_id")
168 169 subproject_ids = []
169 170 if operator_for("subproject_id") == "="
170 171 subproject_ids = values_for("subproject_id").each(&:to_i)
171 172 else
172 173 subproject_ids = project.active_children.collect{|p| p.id}
173 174 end
174 175 sql << " AND #{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
175 176 else
176 177 sql << " AND #{Issue.table_name}.project_id=%d" % project.id if project
177 178 end
178 179 filters.each_key do |field|
179 180 next if field == "subproject_id"
180 181 v = values_for(field).clone
181 182 next unless v and !v.empty?
182 183
183 184 sql = sql + " AND " unless sql.empty?
184 185 sql << "("
185 186
186 187 if field =~ /^cf_(\d+)$/
187 188 # custom field
188 189 db_table = CustomValue.table_name
189 190 db_field = "value"
190 191 sql << "#{db_table}.custom_field_id = #{$1} AND "
191 192 else
192 193 # regular field
193 194 db_table = Issue.table_name
194 195 db_field = field
195 196 end
196 197
197 198 # "me" value subsitution
198 199 if %w(assigned_to_id author_id).include?(field)
199 200 v.push(executed_by ? executed_by.id.to_s : "0") if v.delete("me")
200 201 end
201 202
202 203 case operator_for field
203 204 when "="
204 205 sql = sql + "#{db_table}.#{db_field} IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
205 206 when "!"
206 207 sql = sql + "#{db_table}.#{db_field} NOT IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
207 208 when "!*"
208 209 sql = sql + "#{db_table}.#{db_field} IS NULL"
209 210 when "*"
210 211 sql = sql + "#{db_table}.#{db_field} IS NOT NULL"
211 212 when "o"
212 213 sql = sql + "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id"
213 214 when "c"
214 215 sql = sql + "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id"
215 216 when ">t-"
216 217 sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date((Date.today - v.first.to_i).to_time), connection.quoted_date((Date.today + 1).to_time)]
217 218 when "<t-"
218 219 sql = sql + "#{db_table}.#{db_field} <= '%s'" % connection.quoted_date((Date.today - v.first.to_i).to_time)
219 220 when "t-"
220 221 sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date((Date.today - v.first.to_i).to_time), connection.quoted_date((Date.today - v.first.to_i + 1).to_time)]
221 222 when ">t+"
222 223 sql = sql + "#{db_table}.#{db_field} >= '%s'" % connection.quoted_date((Date.today + v.first.to_i).to_time)
223 224 when "<t+"
224 225 sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(Date.today.to_time), connection.quoted_date((Date.today + v.first.to_i + 1).to_time)]
225 226 when "t+"
226 227 sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date((Date.today + v.first.to_i).to_time), connection.quoted_date((Date.today + v.first.to_i + 1).to_time)]
227 228 when "t"
228 229 sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(Date.today.to_time), connection.quoted_date((Date.today+1).to_time)]
229 230 when "~"
230 231 sql = sql + "#{db_table}.#{db_field} LIKE '%#{connection.quote_string(v.first)}%'"
231 232 when "!~"
232 233 sql = sql + "#{db_table}.#{db_field} NOT LIKE '%#{connection.quote_string(v.first)}%'"
233 234 end
234 235 sql << ")"
235 236
236 237 end if filters and valid?
237 238 sql
238 239 end
239 240 end
@@ -1,37 +1,38
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Role < ActiveRecord::Base
19 19 before_destroy :check_integrity
20 20 has_and_belongs_to_many :permissions
21 21 has_many :workflows, :dependent => :delete_all
22 22 has_many :members
23 23 acts_as_list
24 24
25 25 validates_presence_of :name
26 26 validates_uniqueness_of :name
27 validates_length_of :name, :maximum => 30
27 28 validates_format_of :name, :with => /^[\w\s\'\-]*$/i
28 29
29 30 def <=>(role)
30 31 position <=> role.position
31 32 end
32 33
33 34 private
34 35 def check_integrity
35 36 raise "Can't delete role" if Member.find(:first, :conditions =>["role_id=?", self.id])
36 37 end
37 38 end
@@ -1,33 +1,34
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Tracker < ActiveRecord::Base
19 19 before_destroy :check_integrity
20 20 has_many :issues
21 21 has_many :workflows, :dependent => :delete_all
22 22 has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :association_foreign_key => 'custom_field_id'
23 23 acts_as_list
24 24
25 25 validates_presence_of :name
26 26 validates_uniqueness_of :name
27 validates_length_of :name, :maximum => 30
27 28 validates_format_of :name, :with => /^[\w\s\'\-]*$/i
28 29
29 30 private
30 31 def check_integrity
31 32 raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id])
32 33 end
33 34 end
@@ -1,61 +1,62
1 1 # redMine - project management software
2 2 # Copyright (C) 2006 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class Version < ActiveRecord::Base
19 19 before_destroy :check_integrity
20 20 belongs_to :project
21 21 has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
22 22 has_many :attachments, :as => :container, :dependent => :destroy
23 23
24 24 validates_presence_of :name
25 25 validates_uniqueness_of :name, :scope => [:project_id]
26 validates_length_of :name, :maximum => 30
26 27 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date, :allow_nil => true
27 28
28 29 def start_date
29 30 effective_date
30 31 end
31 32
32 33 def due_date
33 34 effective_date
34 35 end
35 36
36 37 def completed?
37 38 effective_date && effective_date <= Date.today
38 39 end
39 40
40 41 def wiki_page
41 42 if project.wiki && !wiki_page_title.blank?
42 43 @wiki_page ||= project.wiki.find_page(wiki_page_title)
43 44 end
44 45 @wiki_page
45 46 end
46 47
47 48 # Versions are sorted by effective_date
48 49 # Those with no effective_date are at the end, sorted by name
49 50 def <=>(version)
50 51 if self.effective_date
51 52 version.effective_date ? (self.effective_date <=> version.effective_date) : -1
52 53 else
53 54 version.effective_date ? 1 : (self.name <=> version.name)
54 55 end
55 56 end
56 57
57 58 private
58 59 def check_integrity
59 60 raise "Can't delete version" if self.fixed_issues.find(:first)
60 61 end
61 62 end
General Comments 0
You need to be logged in to leave comments. Login now