app/presenters/activity_presenter.rb
class ActivityPresenter < SimpleDelegator
include Rails.application.routes.url_helpers
attr_reader :activity
IGNORED_FIELDS = %w[updated_at created_at owned_by_id owned_by_initials requested_by_id].freeze
STORY_STATES_ENUM = {
'unscheduled' => 0,
'unstarted' => 1,
'started' => 2,
'finished' => 3,
'delivered' => 4,
'accepted' => 5,
'rejected' => 6
}.freeze
def initialize(activity)
@activity = activity
super
end
def eql?(other)
other == self || activity.eql?(other)
end
def description
clause = if action == 'destroy'
"#{subject_destroyed_type} ##{subject_changes['id']}"
else
return nil if subject.nil?
"#{noun} #{predicate}".strip
end
"#{user.name} #{past_tense action} #{clause}"
end
private
delegate :helpers, to: ApplicationController
def noun
case subject_type
when 'Project'
"#{subject_type} '#{helpers.link_to subject.name, project_path(subject)}'"
when 'Story'
path = project_path(subject.try(:project_id)) + '#story-' + subject_id.to_s
"#{subject_type} ##{subject_id} - '#{helpers.link_to subject.title, path}'"
when 'Note', 'Task'
name = (subject.try(:note) || subject.try(:name)).truncate(40)
path = project_path(subject.story.project_id) + '#story-' + subject.story_id.to_s
"#{subject_type} '#{name}' for Story '#{helpers.link_to subject.story.title, path}'"
end
end
def predicate
return '' unless action == 'update'
changes = subject_changes.keys.reject { |key| IGNORED_FIELDS.include?(key) }.map do |key|
case key
when 'documents_attributes' then document_changes subject_changes[key]
when 'position' then position_changes subject_changes[key]
when 'state' then state_changes subject_changes[key]
when 'description' then description_changes subject_changes[key]
else
general_changes(key, subject_changes[key])
end
end.join(', ')
'changing ' + changes
end
def past_tense(verb)
verb + (verb.at(-1) == 'e' ? 'd' : 'ed')
end
def document_changes(changes)
old_documents = changes.first || []
new_documents = changes.last || []
added_documents = new_documents - old_documents
deleted_documents = old_documents - new_documents
tmp_changes = []
tmp_changes << "by uploading '#{added_documents.join("', '")}'" unless added_documents.empty?
tmp_changes << "by deleting '#{deleted_documents.join("', '")}'" unless deleted_documents.empty?
'documents ' + tmp_changes.join(' and ')
end
def position_changes(changes)
old_position = changes.first || Float::MAX
new_position = changes.last
if new_position > old_position
'priority decreased'
else
'priority increased'
end
end
def state_changes(changes)
old_state = STORY_STATES_ENUM[changes.first || 'unscheduled']
new_state = STORY_STATES_ENUM[changes.last]
if old_state < new_state
"state moved forward to #{changes.last}"
else
"state regressed back to #{changes.last} from #{changes.first}"
end
end
def description_changes(changes)
old_description = changes.first || ''
new_description = changes.last || ''
unless old_description.empty?
new_description = Differ.diff(new_description, old_description, ' ').format_as(:html)
end
"description to '#{new_description}'"
end
def general_changes(key, changes)
if changes.first.blank?
"#{key} to '#{changes.last}'"
else
"#{key} from '#{changes.first}' to '#{changes.last || 'empty'}'"
end
end
end