Merge pull request #11602 from opf/implementation/43678-support-date-alerts-in-email-digest

[#43678] Support date alerts in email digest
pull/11596/head
Dombi Attila 2 years ago committed by GitHub
commit 56b04e0524
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      app/helpers/mail_digest_helper.rb
  2. 8
      app/mailers/digest_mailer.rb
  3. 4
      app/models/notification.rb
  4. 8
      app/views/digest_mailer/work_packages.html.erb
  5. 6
      app/views/digest_mailer/work_packages.text.erb
  6. 2
      config/locales/en.yml
  7. 177
      spec/mailers/digest_mailer_spec.rb

@ -42,6 +42,16 @@ module MailDigestHelper
summary
end
def date_alerts_text(notification, html: true)
date_value = date_value(notification)
is_past, is_overdue, days_diff = text_modifiers_for(notification, date_value)
alert_text = build_alert_text(date_value, is_past, is_overdue, days_diff)
property_text = build_property_text(notification, is_overdue, days_diff)
highlight_overdue("#{property_text} #{alert_text}", is_overdue, html)
end
def digest_notification_timestamp_text(notification, html: true)
journal = notification.journal
user = html ? link_to_user(journal.user, only_path: false) : journal.user.name
@ -74,4 +84,43 @@ module MailDigestHelper
def number_of_authors(notifications)
notifications.group_by { |n| n[:actor_id] }.count
end
def date_value(notification)
work_package = notification.resource
notification.reason == "date_alert_start_date" ? work_package.start_date : work_package.due_date
end
def text_modifiers_for(notification, value)
return unless value
is_past = value.before?(Time.zone.today)
is_overdue = is_past && notification.reason == "date_alert_due_date"
difference_in_days = (value - Time.zone.today).to_i.abs
[is_past, is_overdue, difference_in_days]
end
def build_property_text(notification, is_overdue, days_diff)
return I18n.t('js.notifications.date_alerts.overdue') if is_overdue && days_diff > 0
return I18n.t('js.notifications.date_alerts.milestone_date') if notification.resource.milestone?
return I18n.t('js.work_packages.properties.startDate') if notification.reason == "date_alert_start_date"
I18n.t('js.work_packages.properties.dueDate')
end
def build_alert_text(date_value, is_past, is_overdue, days_diff)
return I18n.t('js.notifications.date_alerts.property_is_deleted') unless date_value
return I18n.t('js.notifications.date_alerts.property_today') if days_diff == 0
days_text = I18n.t('js.units.day', count: days_diff)
return I18n.t('js.notifications.date_alerts.overdue_since', difference_in_days: days_text) if is_overdue
return I18n.t('js.notifications.date_alerts.property_was', difference_in_days: days_text) if is_past
I18n.t('js.notifications.date_alerts.property_is', difference_in_days: days_text)
end
def highlight_overdue(text, is_overdue, html)
return text unless html && is_overdue
content_tag :span, text, style: 'color: #C92A2A'
end
end

@ -86,7 +86,11 @@ class DigestMailer < ApplicationMailer
def load_notifications(notification_ids)
Notification
.where(id: notification_ids)
.includes(:project, :resource, journal: %i[data attachable_journals customizable_journals])
.reject { |notification| notification.resource.nil? || notification.project.nil? || notification.journal.nil? }
.includes(:project, :resource)
.reject do |notification|
notification.resource.nil? ||
notification.project.nil? ||
(notification.journal.nil? && !notification.date_alert?)
end
end
end

@ -29,4 +29,8 @@ class Notification < ApplicationRecord
:mail_alert_unsent,
:recipient,
:visible
def date_alert?
reason.in?(["date_alert_start_date", "date_alert_due_date"])
end
end

@ -17,7 +17,7 @@
salutation: I18n.t(:'mail.salutation', user: @user.firstname)
} %>
<% @aggregated_notifications.first(DigestMailer::MAX_SHOWN_WORK_PACKAGES).each do | work_package, notifications_by_work_package| %>
<% @aggregated_notifications.first(DigestMailer::MAX_SHOWN_WORK_PACKAGES).each do |work_package, notifications_by_work_package| %>
<%= render layout: 'mailer/notification_row',
locals: {
work_package: work_package,
@ -29,7 +29,11 @@
<table <%= placeholder_table_styles %>>
<tr>
<td style="color: #878787; line-height: 24px; font-size: 14px; white-space: normal;">
<%= digest_notification_timestamp_text(notifications_by_work_package.first) %>
<% if notifications_by_work_package.first.date_alert? %>
<%= date_alerts_text(notifications_by_work_package.first) %>
<% else %>
<%= digest_notification_timestamp_text(notifications_by_work_package.first) %>
<% end %>
<%= digest_additional_author_text(notifications_by_work_package) %>
</td>
</tr>

@ -9,7 +9,11 @@
<%= "=" * (('# ' + work_package.id.to_s + work_package.subject).length + 4) %>
<% unique_reasons = unique_reasons_of_notifications(notifications_by_work_package) %>
<% unique_reasons.each_with_index do |reason, index| %><%= I18n.t(:"mail.work_packages.reason.#{reason || :unknown}", default: '-') %><%= ', ' unless unique_reasons.size-1 == index %><% end %>: <%= digest_notification_timestamp_text(notifications_by_work_package.first, html: false) %>
<% unique_reasons.each_with_index do |reason, index| %><%= I18n.t(:"mail.work_packages.reason.#{reason || :unknown}", default: '-') %><%= ', ' unless unique_reasons.size-1 == index %><% end %>: <% if notifications_by_work_package.first.date_alert? %>
<%= date_alerts_text(notifications_by_work_package.first, html: false) %>
<% else %>
<%= digest_notification_timestamp_text(notifications_by_work_package.first, html: false) %>
<% end %>
<%= digest_additional_author_text(notifications_by_work_package) %>
<% end %>

@ -2109,6 +2109,8 @@ en:
mentioned: 'Mentioned'
subscribed: 'all'
prefix: 'Received because of the notification setting: %{reason}'
date_alert_start_date: 'Date alert'
date_alert_due_date: 'Date alert'
see_all: 'See all'
updated_at: 'Updated at %{timestamp} by %{user}'

@ -28,7 +28,7 @@
require 'spec_helper'
describe DigestMailer, type: :mailer do
describe DigestMailer do
include OpenProject::ObjectLinking
include ActionView::Helpers::UrlHelper
include OpenProject::StaticRouting::UrlHelpers
@ -130,5 +130,180 @@ describe DigestMailer, type: :mailer do
.to eql({})
end
end
describe "#date_alerts_text" do
let!(:project1) { create(:project) }
let!(:recipient) { create(:user) }
let(:notifications) { [notification] }
context 'when notification_wp_start_past' do
let(:work_package) do
create(:work_package, subject: 'WP start past', project: project1, start_date: 1.day.ago, type: Type.first)
end
let(:notification) do
create(:notification,
reason: :date_alert_start_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Start date was 1 day ago')
end
end
context 'when notification_wp_start_future' do
let(:work_package) do
create(:work_package, subject: 'WP start future', project: project1, start_date: 2.days.from_now, type: Type.first)
end
let(:notification) do
create(:notification,
reason: :date_alert_start_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Start date is in 2 days')
end
end
context 'when notification_wp_due_past' do
let(:work_package) do
create(:work_package, subject: 'WP due past', project: project1, due_date: 3.days.ago, type: Type.first)
end
let(:notification) do
create(:notification,
reason: :date_alert_due_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Overdue since 3 days')
end
end
context 'when notification_wp_due_future' do
let(:work_package) do
create(:work_package, subject: 'WP due future', project: project1, due_date: 3.days.from_now, type: Type.first)
end
let(:notification) do
create(:notification,
reason: :date_alert_due_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Finish date is in 3 days')
end
end
context 'when notification_milestone_past' do
let(:milestone_type) { create(:type_milestone) }
let(:work_package) do
create(:work_package, subject: 'Milestone WP past', project: project1, type: milestone_type, due_date: 2.days.ago)
end
let(:notification) do
create(:notification,
reason: :date_alert_due_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to include('<span style="color: #C92A2A">Overdue since 2 days</span>')
end
end
context 'when notification_milestone_future' do
let(:milestone_type) { create(:type_milestone) }
let(:work_package) do
create(:work_package, subject: 'Milestone WP future', project: project1, type: milestone_type, due_date: 1.day.from_now)
end
let(:notification) do
create(:notification,
reason: :date_alert_due_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Milestone date is in 1 day')
end
end
context 'when notification_wp_unset_date' do
let(:work_package) { create(:work_package, subject: 'Unset date', project: project1, due_date: nil, type: Type.first) }
let(:notification) do
create(:notification,
reason: :date_alert_due_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Finish date is deleted')
end
end
context 'when notification_wp_due_today' do
let(:work_package) do
create(:work_package, subject: 'Due today', project: project1, due_date: Time.zone.today, type: Type.first)
end
let(:notification) do
create(:notification,
reason: :date_alert_due_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Finish date is today')
end
end
context 'when notification_wp_double_date_alert' do
let(:work_package) do
create(:work_package, subject: 'Alert + Mention', project: project1, due_date: 1.day.from_now, type: Type.first)
end
let(:notification) do
create(:notification,
reason: :date_alert_due_date,
recipient:,
resource: work_package,
project: project1)
end
it 'matches generated text' do
expect(mail_body).to have_text('Finish date is in 1 day')
end
end
context 'when notification is mentioned and no journal' do
let(:work_package) { create(:work_package, subject: 'Unset date', project: project1, due_date: nil, type: Type.first) }
let(:notification) do
create(:notification,
reason: :mentioned,
recipient:,
resource: work_package,
project: project1,
journal: nil)
end
it 'does not send the email' do
expect(mail.body).to eq("")
end
end
end
end
end

Loading…
Cancel
Save