Commit bc6805a6 authored by Holger Just's avatar Holger Just

Initial version of acts_as_journalized

parent 28519714
# 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 Journal < ActiveRecord::Base
belongs_to :journalized, :polymorphic => true
# added as a quick fix to allow eager loading of the polymorphic association
# since always associated to an issue, for now
belongs_to :issue, :foreign_key => :journalized_id
self.abstract_class = true
belongs_to :user
has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
serialize :details
attr_accessor :indice
acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" },
:description => :notes,
:author => :user,
:type => Proc.new {|o| (s = o.new_status) ? (s.is_closed? ? 'issue-closed' : 'issue-edit') : 'issue-note' },
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}}
before_save :check_for_empty_journal
acts_as_activity_provider :type => 'issues',
:permission => :view_issues,
:author_key => :user_id,
:find_options => {:include => [{:issue => :project}, :details, :user],
:conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" +
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"}
def save(*args)
def check_for_empty_journal
# Do not save an empty journal
(details.empty? && notes.blank?) ? false : super
end
# Returns the new status if the journal contains a status change, otherwise nil
def new_status
c = details.detect {|detail| detail.prop_key == 'status_id'}
(c && c.value) ? IssueStatus.find_by_id(c.value.to_i) : nil
end
def new_value_for(prop)
c = details.detect {|detail| detail.prop_key == prop}
c ? c.value : nil
end
def editable_by?(usr)
usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project)))
end
def project
journalized.respond_to?(:project) ? journalized.project : nil
end
def attachments
journalized.respond_to?(:attachments) ? journalized.attachments : nil
!(details.empty? && notes.blank?)
end
end
require File.dirname(__FILE__) + '/lib/acts_as_journalized'
ActiveRecord::Base.send(:include, Redmine::Acts::Journalized)
module Redmine
module Acts
module Journalized
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def acts_as_journalized(options = {})
return if self.included_modules.include?(Redmine::Acts::Journalized::InstanceMethods)
self.include Redmine::Acts::Journalized::InstanceMethods
plural_name = self.name.underscore.pluralize
journal_name = "#{self.name}Journal"
extra_module = options.delete(:extra_module)
event_hash = {
:description => :notes,
:author => Proc.new {|o| User.find_by_id(o.journal.user_id)},
:url => Proc.new do |o|
{
:controller => self.name.underscore.pluralize,
:action => 'show',
:id => o.id,
:anchor => "change-#{o.id}"
}
end
}
activity_hash = {
:type => plural_name,
:permission => "view_#{plural_name}".to_sym,
:author_key => :user_id,
}
options.each_pair do |k, v|
case
when key = k.to_s.slice(/event_(.+)/, 1)
event_hash[key.to_sym] = v
when key = k.to_s.slice(/activity_(.+)/, 1)
activity_hash[key.to_sym] = v
end
end
# create the new model class
journal = Class.new(Journal)
journal.belongs_to self.name.underscore
journal.acts_as_event event_hash
journal.acts_as_activity_provider activity_hash
journal.send(:include, extra_module)
Object.const_set("#{self.name}Journal", journal)
unless Redmine::Activity.providers[plural_name].include? self.name
Redmine::Activity.register plural_name.to_sym
end
end
end
module InstanceMethods
def self.included(base)
base.extend ClassMethods
base.class_eval do
after_save :create_journal
has_many :journals, :class_name => "#{self.name}Journal", :dependent => :destroy
end
end
def journal_class
"#{self.class.name}Journal".constantize
end
def init_journal(user, notes = "")
@notes ||= ""
@current_journal ||= journal_class.new(:journalized => self, :user => user, :notes => notes)
@object_before_change = self.clone
@object_before_change.status = self.status
if self.respond_to? :custom_values
@custom_values_before_change = {}
self.custom_values.each {|c| @custom_values_before_change[c.custom_field_id] = c.value }
end
# Make sure updated_on is updated when adding a note.
updated_on_will_change!
@current_journal
end
# Saves the changes in a Journal
# Called after_save
def create_journal
if @current_journal
details = {:attr => {}}
if self.respond_to? :custom_values
details[:cf] = {}
end
# attributes changes
self.class.journalized_columns.each do |c|
unless send(c) == @object_before_change.send(c)
details[:attr][c] = {
:old => @object_before_change.send(c),
:new => send(c)
}
end
end
if self.respond_to? :custom_values
# custom fields changes
custom_values.each do |c|
unless ( @custom_values_before_change[c.custom_field_id]==c.value ||
(@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?))
details[:cf][c.custom_field_id] = {
:old => @custom_values_before_change[c.custom_field_id],
:new => c.value
}
end
end
end
@current_journal.details = details
@current_journal.save
end
end
module ClassMethods
def journalized_columns=(columns = [])
@journalized_columns = columns
end
def journalized_columns
@journalized_columns ||= begin
(self.column_names - %w(id description lock_version created_on updated_on))
end
end
end
end
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment