@@ -687,14 +687,6 class Issue < ActiveRecord::Base | |||||
687 |
|
687 | |||
688 | def init_journal(user, notes = "") |
|
688 | def init_journal(user, notes = "") | |
689 | @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) |
|
689 | @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) | |
690 | if new_record? |
|
|||
691 | @current_journal.notify = false |
|
|||
692 | else |
|
|||
693 | @attributes_before_change = attributes.dup |
|
|||
694 | @custom_values_before_change = {} |
|
|||
695 | self.custom_field_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } |
|
|||
696 | end |
|
|||
697 | @current_journal |
|
|||
698 | end |
|
690 | end | |
699 |
|
691 | |||
700 | # Returns the current journal or nil if it's not initialized |
|
692 | # Returns the current journal or nil if it's not initialized | |
@@ -702,6 +694,11 class Issue < ActiveRecord::Base | |||||
702 | @current_journal |
|
694 | @current_journal | |
703 | end |
|
695 | end | |
704 |
|
696 | |||
|
697 | # Returns the names of attributes that are journalized when updating the issue | |||
|
698 | def journalized_attribute_names | |||
|
699 | Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on closed_on) | |||
|
700 | end | |||
|
701 | ||||
705 | # Returns the id of the last journal or nil |
|
702 | # Returns the id of the last journal or nil | |
706 | def last_journal_id |
|
703 | def last_journal_id | |
707 | if new_record? |
|
704 | if new_record? | |
@@ -1522,41 +1519,33 class Issue < ActiveRecord::Base | |||||
1522 | end |
|
1519 | end | |
1523 |
|
1520 | |||
1524 | # Callback on file attachment |
|
1521 | # Callback on file attachment | |
1525 |
def attachment_added( |
|
1522 | def attachment_added(attachment) | |
1526 |
if |
|
1523 | if current_journal && !attachment.new_record? | |
1527 | @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename) |
|
1524 | current_journal.journalize_attachment(attachment, :added) | |
1528 | end |
|
1525 | end | |
1529 | end |
|
1526 | end | |
1530 |
|
1527 | |||
1531 | # Callback on attachment deletion |
|
1528 | # Callback on attachment deletion | |
1532 |
def attachment_removed( |
|
1529 | def attachment_removed(attachment) | |
1533 |
if |
|
1530 | if current_journal && !attachment.new_record? | |
1534 | @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :old_value => obj.filename) |
|
1531 | current_journal.journalize_attachment(attachment, :removed) | |
1535 |
|
|
1532 | current_journal.save | |
1536 | end |
|
1533 | end | |
1537 | end |
|
1534 | end | |
1538 |
|
1535 | |||
1539 | # Called after a relation is added |
|
1536 | # Called after a relation is added | |
1540 | def relation_added(relation) |
|
1537 | def relation_added(relation) | |
1541 |
if |
|
1538 | if current_journal | |
1542 |
|
|
1539 | current_journal.journalize_relation(relation, :added) | |
1543 | :property => 'relation', |
|
1540 | current_journal.save | |
1544 | :prop_key => relation.relation_type_for(self), |
|
|||
1545 | :value => relation.other_issue(self).try(:id) |
|
|||
1546 | ) |
|
|||
1547 | @current_journal.save |
|
|||
1548 | end |
|
1541 | end | |
1549 | end |
|
1542 | end | |
1550 |
|
1543 | |||
1551 | # Called after a relation is removed |
|
1544 | # Called after a relation is removed | |
1552 | def relation_removed(relation) |
|
1545 | def relation_removed(relation) | |
1553 |
if |
|
1546 | if current_journal | |
1554 |
|
|
1547 | current_journal.journalize_relation(relation, :removed) | |
1555 | :property => 'relation', |
|
1548 | current_journal.save | |
1556 | :prop_key => relation.relation_type_for(self), |
|
|||
1557 | :old_value => relation.other_issue(self).try(:id) |
|
|||
1558 | ) |
|
|||
1559 | @current_journal.save |
|
|||
1560 | end |
|
1549 | end | |
1561 | end |
|
1550 | end | |
1562 |
|
1551 | |||
@@ -1616,55 +1605,8 class Issue < ActiveRecord::Base | |||||
1616 | # Saves the changes in a Journal |
|
1605 | # Saves the changes in a Journal | |
1617 | # Called after_save |
|
1606 | # Called after_save | |
1618 | def create_journal |
|
1607 | def create_journal | |
1619 |
if |
|
1608 | if current_journal | |
1620 | # attributes changes |
|
1609 | current_journal.save | |
1621 | if @attributes_before_change |
|
|||
1622 | (Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on closed_on)).each {|c| |
|
|||
1623 | before = @attributes_before_change[c] |
|
|||
1624 | after = send(c) |
|
|||
1625 | next if before == after || (before.blank? && after.blank?) |
|
|||
1626 | @current_journal.details << JournalDetail.new(:property => 'attr', |
|
|||
1627 | :prop_key => c, |
|
|||
1628 | :old_value => before, |
|
|||
1629 | :value => after) |
|
|||
1630 | } |
|
|||
1631 | end |
|
|||
1632 | if @custom_values_before_change |
|
|||
1633 | # custom fields changes |
|
|||
1634 | custom_field_values.each {|c| |
|
|||
1635 | before = @custom_values_before_change[c.custom_field_id] |
|
|||
1636 | after = c.value |
|
|||
1637 | next if before == after || (before.blank? && after.blank?) |
|
|||
1638 |
|
||||
1639 | if before.is_a?(Array) || after.is_a?(Array) |
|
|||
1640 | before = [before] unless before.is_a?(Array) |
|
|||
1641 | after = [after] unless after.is_a?(Array) |
|
|||
1642 |
|
||||
1643 | # values removed |
|
|||
1644 | (before - after).reject(&:blank?).each do |value| |
|
|||
1645 | @current_journal.details << JournalDetail.new(:property => 'cf', |
|
|||
1646 | :prop_key => c.custom_field_id, |
|
|||
1647 | :old_value => value, |
|
|||
1648 | :value => nil) |
|
|||
1649 | end |
|
|||
1650 | # values added |
|
|||
1651 | (after - before).reject(&:blank?).each do |value| |
|
|||
1652 | @current_journal.details << JournalDetail.new(:property => 'cf', |
|
|||
1653 | :prop_key => c.custom_field_id, |
|
|||
1654 | :old_value => nil, |
|
|||
1655 | :value => value) |
|
|||
1656 | end |
|
|||
1657 | else |
|
|||
1658 | @current_journal.details << JournalDetail.new(:property => 'cf', |
|
|||
1659 | :prop_key => c.custom_field_id, |
|
|||
1660 | :old_value => before, |
|
|||
1661 | :value => after) |
|
|||
1662 | end |
|
|||
1663 | } |
|
|||
1664 | end |
|
|||
1665 | @current_journal.save |
|
|||
1666 | # reset current journal |
|
|||
1667 | init_journal @current_journal.user, @current_journal.notes |
|
|||
1668 | end |
|
1610 | end | |
1669 | end |
|
1611 | end | |
1670 |
|
1612 |
@@ -50,7 +50,16 class Journal < ActiveRecord::Base | |||||
50 | where("(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes, *args)}))", false) |
|
50 | where("(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes, *args)}))", false) | |
51 | } |
|
51 | } | |
52 |
|
52 | |||
|
53 | def initialize(*args) | |||
|
54 | super | |||
|
55 | if journalized && journalized.new_record? | |||
|
56 | self.notify = false | |||
|
57 | end | |||
|
58 | start | |||
|
59 | end | |||
|
60 | ||||
53 | def save(*args) |
|
61 | def save(*args) | |
|
62 | journalize_changes | |||
54 | # Do not save an empty journal |
|
63 | # Do not save an empty journal | |
55 | (details.empty? && notes.blank?) ? false : super |
|
64 | (details.empty? && notes.blank?) ? false : super | |
56 | end |
|
65 | end | |
@@ -166,8 +175,101 class Journal < ActiveRecord::Base | |||||
166 | journals |
|
175 | journals | |
167 | end |
|
176 | end | |
168 |
|
177 | |||
|
178 | # Stores the values of the attributes and custom fields of the journalized object | |||
|
179 | def start | |||
|
180 | if journalized | |||
|
181 | @attributes_before_change = journalized.journalized_attribute_names.inject({}) do |h, attribute| | |||
|
182 | h[attribute] = journalized.send(attribute) | |||
|
183 | h | |||
|
184 | end | |||
|
185 | @custom_values_before_change = journalized.custom_field_values.inject({}) do |h, c| | |||
|
186 | h[c.custom_field_id] = c.value | |||
|
187 | h | |||
|
188 | end | |||
|
189 | end | |||
|
190 | self | |||
|
191 | end | |||
|
192 | ||||
|
193 | # Adds a journal detail for an attachment that was added or removed | |||
|
194 | def journalize_attachment(attachment, added_or_removed) | |||
|
195 | key = (added_or_removed == :removed ? :old_value : :value) | |||
|
196 | details << JournalDetail.new( | |||
|
197 | :property => 'attachment', | |||
|
198 | :prop_key => attachment.id, | |||
|
199 | key => attachment.filename | |||
|
200 | ) | |||
|
201 | end | |||
|
202 | ||||
|
203 | # Adds a journal detail for an issue relation that was added or removed | |||
|
204 | def journalize_relation(relation, added_or_removed) | |||
|
205 | key = (added_or_removed == :removed ? :old_value : :value) | |||
|
206 | details << JournalDetail.new( | |||
|
207 | :property => 'relation', | |||
|
208 | :prop_key => relation.relation_type_for(journalized), | |||
|
209 | key => relation.other_issue(journalized).try(:id) | |||
|
210 | ) | |||
|
211 | end | |||
|
212 | ||||
169 | private |
|
213 | private | |
170 |
|
214 | |||
|
215 | # Generates journal details for attribute and custom field changes | |||
|
216 | def journalize_changes | |||
|
217 | # attributes changes | |||
|
218 | if @attributes_before_change | |||
|
219 | journalized.journalized_attribute_names.each {|attribute| | |||
|
220 | before = @attributes_before_change[attribute] | |||
|
221 | after = journalized.send(attribute) | |||
|
222 | next if before == after || (before.blank? && after.blank?) | |||
|
223 | add_attribute_detail(attribute, before, after) | |||
|
224 | } | |||
|
225 | end | |||
|
226 | if @custom_values_before_change | |||
|
227 | # custom fields changes | |||
|
228 | journalized.custom_field_values.each {|c| | |||
|
229 | before = @custom_values_before_change[c.custom_field_id] | |||
|
230 | after = c.value | |||
|
231 | next if before == after || (before.blank? && after.blank?) | |||
|
232 | ||||
|
233 | if before.is_a?(Array) || after.is_a?(Array) | |||
|
234 | before = [before] unless before.is_a?(Array) | |||
|
235 | after = [after] unless after.is_a?(Array) | |||
|
236 | ||||
|
237 | # values removed | |||
|
238 | (before - after).reject(&:blank?).each do |value| | |||
|
239 | add_custom_value_detail(c, value, nil) | |||
|
240 | end | |||
|
241 | # values added | |||
|
242 | (after - before).reject(&:blank?).each do |value| | |||
|
243 | add_custom_value_detail(c, nil, value) | |||
|
244 | end | |||
|
245 | else | |||
|
246 | add_custom_value_detail(c, before, after) | |||
|
247 | end | |||
|
248 | } | |||
|
249 | end | |||
|
250 | start | |||
|
251 | end | |||
|
252 | ||||
|
253 | # Adds a journal detail for an attribute change | |||
|
254 | def add_attribute_detail(attribute, old_value, value) | |||
|
255 | add_detail('attr', attribute, old_value, value) | |||
|
256 | end | |||
|
257 | ||||
|
258 | # Adds a journal detail for a custom field value change | |||
|
259 | def add_custom_value_detail(custom_value, old_value, value) | |||
|
260 | add_detail('cf', custom_value.custom_field_id, old_value, value) | |||
|
261 | end | |||
|
262 | ||||
|
263 | # Adds a journal detail | |||
|
264 | def add_detail(property, prop_key, old_value, value) | |||
|
265 | details << JournalDetail.new( | |||
|
266 | :property => property, | |||
|
267 | :prop_key => prop_key, | |||
|
268 | :old_value => old_value, | |||
|
269 | :value => value | |||
|
270 | ) | |||
|
271 | end | |||
|
272 | ||||
171 | def split_private_notes |
|
273 | def split_private_notes | |
172 | if private_notes? |
|
274 | if private_notes? | |
173 | if notes.present? |
|
275 | if notes.present? |
General Comments 0
You need to be logged in to leave comments.
Login now