lib/redmine_digest/digest.rb
module RedmineDigest
class Digest
# batch size for fetching issues
ISSUE_BATCH_SIZE = 300
attr_reader :digest_rule, :time_to
delegate :name, :user, :recurrent, :project_selector,
to: :digest_rule, allow_nil: true
def initialize(digest_rule, time_to = nil, issue_limit = nil)
@digest_rule = digest_rule
@time_to_base = time_to
@issue_limit = issue_limit
end
def issues
@issues ||= use_user_time_zone do
fetch_issues
end
end
def time_to
@time_to ||= use_user_time_zone do
get_time_to
end
end
def time_from
@time_from ||= use_user_time_zone do
digest_rule.calculate_time_from(time_to)
end
end
def sorted_digest_issues
@sorted_digest_issues ||= get_sorted_digest_issues
end
def projects_count
@projects_count ||= issues.map(&:project_id).uniq.count
end
def many_projects?
projects_count > 1
end
def project_names
@projects_names ||= issues.map(&:project_name).uniq
end
def template_path(partial = 'digest')
"digests/#{digest_rule.template}/#{partial}"
end
private
def fetch_issues
raise 'DigestRule#user must be filled' if user.nil?
d_issues = []
fetch_issue_ids.in_groups_of(ISSUE_BATCH_SIZE) do |issue_ids|
get_issues_scope(issue_ids.compact).each do |issue|
d_issue = get_digest_issue_with_events(issue)
d_issues << d_issue if wants_created? ? d_issue.any_events? : d_issue.any_changes_events?
end
end
d_issues
end
def get_digest_issue_with_events(issue)
d_issue = DigestIssue.new(
id: issue.id,
subject: issue.subject,
status_id: issue.status_id,
project_id: issue.project_id,
project_name: issue.project.name,
created_on: issue.created_on,
last_updated_on: issue.created_on,
priority: issue.priority
)
if include_issue_add_event?(issue)
event = DigestEventFactory.new_event(
DigestEvent::ISSUE_CREATED, issue.id, issue.created_on, issue.author)
d_issue.events[DigestEvent::ISSUE_CREATED] << event
end
# read all journal updates, add indice and remove private_notes
journals = issue.journals.sort_by(&:id)
journals.each_with_index { |j, i| j.indice = i + 1 }
journals.each do |journal|
next unless include_issue_edit_event?(journal)
events = digest_rule.find_events_by_journal(journal)
# get status_id from change history
status_id_change = events.detect { |e| e.event_type == DigestEvent::STATUS_CHANGED }
d_issue.status_id = status_id_change.value if status_id_change
next if journal.private_notes? &&
!user.allowed_to?(:view_private_notes, issue.project)
events.each do |event|
d_issue.last_updated_on = journal.created_on
d_issue.events[event.event_type] << event
end
end
d_issue
end
def fetch_issue_ids
all_issue_ids = get_changed_issue_ids
all_issue_ids += get_created_issue_ids if wants_created?
all_issue_ids.uniq!
all_issue_ids = all_issue_ids.take(@issue_limit) if @issue_limit
all_issue_ids
end
def include_issue_edit_event?(journal)
return false unless in_time_frame?(journal.created_on)
!(digest_rule.notify_only? && user_will_be_notified?(journal))
end
def user_will_be_notified?(journal)
journal.notify? && notified_events?(journal) && user_in_recipients?(journal)
end
def user_in_recipients?(issue_or_journal)
(issue_or_journal.watcher_recipients + issue_or_journal.recipients).include?(user.mail)
end
def notified_events?(journal)
Setting.notified_events.include?('issue_updated') ||
(Setting.notified_events.include?('issue_note_added') && journal.notes.present?) ||
(Setting.notified_events.include?('issue_status_updated') && journal.new_status.present?) ||
(Setting.notified_events.include?('issue_priority_updated') && journal.new_value_for('priority_id').present?)
end
def include_issue_add_event?(issue)
return false unless in_time_frame?(issue.created_on)
skip_digest = digest_rule.notify_only? &&
Setting.notified_events.include?('issue_added') &&
user_in_recipients?(issue)
!skip_digest
end
def in_time_frame?(datetime)
datetime >= time_from && datetime < time_to
end
def wants_created?
digest_rule.event_type_enabled?(DigestEvent::ISSUE_CREATED)
end
def get_sorted_digest_issues
result = ActiveSupport::OrderedHash.new
IssueStatus.sorted.each do |status|
result[status] = issues.
find_all { |i| i.status_id.to_i == status.id }.
sort { |a, b| b.sort_key <=> a.sort_key }
end
result
end
def get_time_to
@time_to_base ||= Date.current.midnight
end
def get_changed_issue_ids
Journal.joins(:issue).where('issues.project_id in (?)', project_ids).
where('journals.created_on >= ? and journals.created_on < ?', time_from, time_to).
uniq.pluck(:journalized_id)
end
def get_created_issue_ids
Issue.where('issues.project_id in (?)', project_ids).
where('issues.created_on >= ? and issues.created_on < ?', time_from, time_to).
uniq.pluck(:id)
end
def get_issues_scope(issue_ids)
Issue.joins(:project).includes(:author, :project, journals: [:user, :details]).
where('issues.id in (?)', issue_ids).
where(Issue.visible_condition(user))
end
def project_ids
@project_ids ||= digest_rule.affected_project_ids
end
def use_user_time_zone(&block)
Time.use_zone(user.time_zone, &block)
end
end
end