@@ -241,6 +241,11 class Issue < ActiveRecord::Base | |||||
241 | recipients.compact.uniq |
|
241 | recipients.compact.uniq | |
242 | end |
|
242 | end | |
243 |
|
243 | |||
|
244 | # Returns the total number of hours spent on this issue. | |||
|
245 | # | |||
|
246 | # Example: | |||
|
247 | # spent_hours => 0 | |||
|
248 | # spent_hours => 50 | |||
244 | def spent_hours |
|
249 | def spent_hours | |
245 | @spent_hours ||= time_entries.sum(:hours) || 0 |
|
250 | @spent_hours ||= time_entries.sum(:hours) || 0 | |
246 | end |
|
251 | end | |
@@ -269,6 +274,11 class Issue < ActiveRecord::Base | |||||
269 | due_date || (fixed_version ? fixed_version.effective_date : nil) |
|
274 | due_date || (fixed_version ? fixed_version.effective_date : nil) | |
270 | end |
|
275 | end | |
271 |
|
276 | |||
|
277 | # Returns the time scheduled for this issue. | |||
|
278 | # | |||
|
279 | # Example: | |||
|
280 | # Start Date: 2/26/09, End Date: 3/04/09 | |||
|
281 | # duration => 6 | |||
272 | def duration |
|
282 | def duration | |
273 | (start_date && due_date) ? due_date - start_date : 0 |
|
283 | (start_date && due_date) ? due_date - start_date : 0 | |
274 | end |
|
284 | end |
@@ -29,6 +29,11 class Mailer < ActionMailer::Base | |||||
29 | { :host => h, :protocol => Setting.protocol } |
|
29 | { :host => h, :protocol => Setting.protocol } | |
30 | end |
|
30 | end | |
31 |
|
31 | |||
|
32 | # Builds a tmail object used to email recipients of the added issue. | |||
|
33 | # | |||
|
34 | # Example: | |||
|
35 | # issue_add(issue) => tmail object | |||
|
36 | # Mailer.deliver_issue_add(issue) => sends an email to issue recipients | |||
32 | def issue_add(issue) |
|
37 | def issue_add(issue) | |
33 | redmine_headers 'Project' => issue.project.identifier, |
|
38 | redmine_headers 'Project' => issue.project.identifier, | |
34 | 'Issue-Id' => issue.id, |
|
39 | 'Issue-Id' => issue.id, | |
@@ -42,6 +47,11 class Mailer < ActionMailer::Base | |||||
42 | :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue) |
|
47 | :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue) | |
43 | end |
|
48 | end | |
44 |
|
49 | |||
|
50 | # Builds a tmail object used to email recipients of the edited issue. | |||
|
51 | # | |||
|
52 | # Example: | |||
|
53 | # issue_edit(journal) => tmail object | |||
|
54 | # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients | |||
45 | def issue_edit(journal) |
|
55 | def issue_edit(journal) | |
46 | issue = journal.journalized |
|
56 | issue = journal.journalized | |
47 | redmine_headers 'Project' => issue.project.identifier, |
|
57 | redmine_headers 'Project' => issue.project.identifier, | |
@@ -72,6 +82,11 class Mailer < ActionMailer::Base | |||||
72 | :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc') |
|
82 | :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc') | |
73 | end |
|
83 | end | |
74 |
|
84 | |||
|
85 | # Builds a tmail object used to email users belonging to the added document's project. | |||
|
86 | # | |||
|
87 | # Example: | |||
|
88 | # document_added(document) => tmail object | |||
|
89 | # Mailer.deliver_document_added(document) => sends an email to the document's project recipients | |||
75 | def document_added(document) |
|
90 | def document_added(document) | |
76 | redmine_headers 'Project' => document.project.identifier |
|
91 | redmine_headers 'Project' => document.project.identifier | |
77 | recipients document.project.recipients |
|
92 | recipients document.project.recipients | |
@@ -80,6 +95,11 class Mailer < ActionMailer::Base | |||||
80 | :document_url => url_for(:controller => 'documents', :action => 'show', :id => document) |
|
95 | :document_url => url_for(:controller => 'documents', :action => 'show', :id => document) | |
81 | end |
|
96 | end | |
82 |
|
97 | |||
|
98 | # Builds a tmail object used to email recipients of a project when an attachements are added. | |||
|
99 | # | |||
|
100 | # Example: | |||
|
101 | # attachments_added(attachments) => tmail object | |||
|
102 | # Mailer.deliver_attachments_added(attachments) => sends an email to the project's recipients | |||
83 | def attachments_added(attachments) |
|
103 | def attachments_added(attachments) | |
84 | container = attachments.first.container |
|
104 | container = attachments.first.container | |
85 | added_to = '' |
|
105 | added_to = '' | |
@@ -102,7 +122,12 class Mailer < ActionMailer::Base | |||||
102 | :added_to => added_to, |
|
122 | :added_to => added_to, | |
103 | :added_to_url => added_to_url |
|
123 | :added_to_url => added_to_url | |
104 | end |
|
124 | end | |
105 |
|
125 | |||
|
126 | # Builds a tmail object used to email recipients of a news' project when a news item is added. | |||
|
127 | # | |||
|
128 | # Example: | |||
|
129 | # news_added(news) => tmail object | |||
|
130 | # Mailer.deliver_news_added(news) => sends an email to the news' project recipients | |||
106 | def news_added(news) |
|
131 | def news_added(news) | |
107 | redmine_headers 'Project' => news.project.identifier |
|
132 | redmine_headers 'Project' => news.project.identifier | |
108 | message_id news |
|
133 | message_id news | |
@@ -112,6 +137,11 class Mailer < ActionMailer::Base | |||||
112 | :news_url => url_for(:controller => 'news', :action => 'show', :id => news) |
|
137 | :news_url => url_for(:controller => 'news', :action => 'show', :id => news) | |
113 | end |
|
138 | end | |
114 |
|
139 | |||
|
140 | # Builds a tmail object used to email the specified recipients of the specified message that was posted. | |||
|
141 | # | |||
|
142 | # Example: | |||
|
143 | # message_posted(message, recipients) => tmail object | |||
|
144 | # Mailer.deliver_message_posted(message, recipients) => sends an email to the recipients | |||
115 | def message_posted(message, recipients) |
|
145 | def message_posted(message, recipients) | |
116 | redmine_headers 'Project' => message.project.identifier, |
|
146 | redmine_headers 'Project' => message.project.identifier, | |
117 | 'Topic-Id' => (message.parent_id || message.id) |
|
147 | 'Topic-Id' => (message.parent_id || message.id) | |
@@ -123,6 +153,11 class Mailer < ActionMailer::Base | |||||
123 | :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root) |
|
153 | :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root) | |
124 | end |
|
154 | end | |
125 |
|
155 | |||
|
156 | # Builds a tmail object used to email the specified user their account information. | |||
|
157 | # | |||
|
158 | # Example: | |||
|
159 | # account_information(user, password) => tmail object | |||
|
160 | # Mailer.deliver_account_information(user, password) => sends account information to the user | |||
126 | def account_information(user, password) |
|
161 | def account_information(user, password) | |
127 | set_language_if_valid user.language |
|
162 | set_language_if_valid user.language | |
128 | recipients user.mail |
|
163 | recipients user.mail | |
@@ -132,6 +167,11 class Mailer < ActionMailer::Base | |||||
132 | :login_url => url_for(:controller => 'account', :action => 'login') |
|
167 | :login_url => url_for(:controller => 'account', :action => 'login') | |
133 | end |
|
168 | end | |
134 |
|
169 | |||
|
170 | # Builds a tmail object used to email all active administrators of an account activation request. | |||
|
171 | # | |||
|
172 | # Example: | |||
|
173 | # account_activation_request(user) => tmail object | |||
|
174 | # Mailer.deliver_account_activation_request(user)=> sends an email to all active administrators | |||
135 | def account_activation_request(user) |
|
175 | def account_activation_request(user) | |
136 | # Send the email to all active administrators |
|
176 | # Send the email to all active administrators | |
137 | recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact |
|
177 | recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact | |
@@ -140,7 +180,11 class Mailer < ActionMailer::Base | |||||
140 | :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc') |
|
180 | :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc') | |
141 | end |
|
181 | end | |
142 |
|
182 | |||
143 |
# |
|
183 | # Builds a tmail object used to email the specified user that their account was activated by an administrator. | |
|
184 | # | |||
|
185 | # Example: | |||
|
186 | # account_activated(user) => tmail object | |||
|
187 | # Mailer.deliver_account_activated(user) => sends an email to the registered user | |||
144 | def account_activated(user) |
|
188 | def account_activated(user) | |
145 | set_language_if_valid user.language |
|
189 | set_language_if_valid user.language | |
146 | recipients user.mail |
|
190 | recipients user.mail |
@@ -99,6 +99,11 class Project < ActiveRecord::Base | |||||
99 | find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC") |
|
99 | find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC") | |
100 | end |
|
100 | end | |
101 |
|
101 | |||
|
102 | # Returns a SQL :conditions string used to find all active projects for the specified user. | |||
|
103 | # | |||
|
104 | # Examples: | |||
|
105 | # Projects.visible_by(admin) => "projects.status = 1" | |||
|
106 | # Projects.visible_by(normal_user) => "projects.status = 1 AND projects.is_public = 1" | |||
102 | def self.visible_by(user=nil) |
|
107 | def self.visible_by(user=nil) | |
103 | user ||= User.current |
|
108 | user ||= User.current | |
104 | if user && user.admin? |
|
109 | if user && user.admin? | |
@@ -141,7 +146,12 class Project < ActiveRecord::Base | |||||
141 | end |
|
146 | end | |
142 | statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))" |
|
147 | statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))" | |
143 | end |
|
148 | end | |
144 |
|
149 | |||
|
150 | # Returns a :conditions SQL string that can be used to find the issues associated with this project. | |||
|
151 | # | |||
|
152 | # Examples: | |||
|
153 | # project.project_condition(true) => "(projects.id = 1 OR (projects.lft > 1 AND projects.rgt < 10))" | |||
|
154 | # project.project_condition(false) => "projects.id = 1" | |||
145 | def project_condition(with_subprojects) |
|
155 | def project_condition(with_subprojects) | |
146 | cond = "#{Project.table_name}.id = #{id}" |
|
156 | cond = "#{Project.table_name}.id = #{id}" | |
147 | cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects |
|
157 | cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects | |
@@ -273,6 +283,10 class Project < ActiveRecord::Base | |||||
273 | description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description |
|
283 | description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description | |
274 | end |
|
284 | end | |
275 |
|
285 | |||
|
286 | # Return true if this project is allowed to do the specified action. | |||
|
287 | # action can be: | |||
|
288 | # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') | |||
|
289 | # * a permission Symbol (eg. :edit_project) | |||
276 | def allows_to?(action) |
|
290 | def allows_to?(action) | |
277 | if action.is_a? Hash |
|
291 | if action.is_a? Hash | |
278 | allowed_actions.include? "#{action[:controller]}/#{action[:action]}" |
|
292 | allowed_actions.include? "#{action[:controller]}/#{action[:action]}" |
@@ -286,6 +286,8 class User < ActiveRecord::Base | |||||
286 | @current_user ||= User.anonymous |
|
286 | @current_user ||= User.anonymous | |
287 | end |
|
287 | end | |
288 |
|
288 | |||
|
289 | # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only | |||
|
290 | # one anonymous user per database. | |||
289 | def self.anonymous |
|
291 | def self.anonymous | |
290 | anonymous_user = AnonymousUser.find(:first) |
|
292 | anonymous_user = AnonymousUser.find(:first) | |
291 | if anonymous_user.nil? |
|
293 | if anonymous_user.nil? |
@@ -50,6 +50,8 class Version < ActiveRecord::Base | |||||
50 | effective_date && (effective_date <= Date.today) && (open_issues_count == 0) |
|
50 | effective_date && (effective_date <= Date.today) && (open_issues_count == 0) | |
51 | end |
|
51 | end | |
52 |
|
52 | |||
|
53 | # Returns the completion percentage of this version based on the amount of open/closed issues | |||
|
54 | # and the time spent on the open issues. | |||
53 | def completed_pourcent |
|
55 | def completed_pourcent | |
54 | if issues_count == 0 |
|
56 | if issues_count == 0 | |
55 | 0 |
|
57 | 0 | |
@@ -60,6 +62,7 class Version < ActiveRecord::Base | |||||
60 | end |
|
62 | end | |
61 | end |
|
63 | end | |
62 |
|
64 | |||
|
65 | # Returns the percentage of issues that have been marked as 'closed'. | |||
63 | def closed_pourcent |
|
66 | def closed_pourcent | |
64 | if issues_count == 0 |
|
67 | if issues_count == 0 | |
65 | 0 |
|
68 | 0 | |
@@ -78,10 +81,12 class Version < ActiveRecord::Base | |||||
78 | @issue_count ||= fixed_issues.count |
|
81 | @issue_count ||= fixed_issues.count | |
79 | end |
|
82 | end | |
80 |
|
83 | |||
|
84 | # Returns the total amount of open issues for this version. | |||
81 | def open_issues_count |
|
85 | def open_issues_count | |
82 | @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status) |
|
86 | @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status) | |
83 | end |
|
87 | end | |
84 |
|
88 | |||
|
89 | # Returns the total amount of closed issues for this version. | |||
85 | def closed_issues_count |
|
90 | def closed_issues_count | |
86 | @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status) |
|
91 | @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status) | |
87 | end |
|
92 | end | |
@@ -124,17 +129,22 private | |||||
124 | @estimated_average |
|
129 | @estimated_average | |
125 | end |
|
130 | end | |
126 |
|
131 | |||
127 | # Returns the total progress of open or closed issues |
|
132 | # Returns the total progress of open or closed issues. The returned percentage takes into account | |
|
133 | # the amount of estimated time set for this version. | |||
|
134 | # | |||
|
135 | # Examples: | |||
|
136 | # issues_progress(true) => returns the progress percentage for open issues. | |||
|
137 | # issues_progress(false) => returns the progress percentage for closed issues. | |||
128 | def issues_progress(open) |
|
138 | def issues_progress(open) | |
129 | @issues_progress ||= {} |
|
139 | @issues_progress ||= {} | |
130 | @issues_progress[open] ||= begin |
|
140 | @issues_progress[open] ||= begin | |
131 | progress = 0 |
|
141 | progress = 0 | |
132 | if issues_count > 0 |
|
142 | if issues_count > 0 | |
133 | ratio = open ? 'done_ratio' : 100 |
|
143 | ratio = open ? 'done_ratio' : 100 | |
|
144 | ||||
134 | done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}", |
|
145 | done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}", | |
135 | :include => :status, |
|
146 | :include => :status, | |
136 | :conditions => ["is_closed = ?", !open]).to_f |
|
147 | :conditions => ["is_closed = ?", !open]).to_f | |
137 |
|
||||
138 | progress = done / (estimated_average * issues_count) |
|
148 | progress = done / (estimated_average * issues_count) | |
139 | end |
|
149 | end | |
140 | progress |
|
150 | progress |
General Comments 0
You need to be logged in to leave comments.
Login now