Skip to content

Commit

Permalink
Merge pull request #2200 from samvera/i1019-batch-email-notifications
Browse files Browse the repository at this point in the history
🎁 1019 batch email notifications
  • Loading branch information
kirkkwang authored May 7, 2024
2 parents 26c993c + f3740c6 commit 57108c2
Show file tree
Hide file tree
Showing 38 changed files with 787 additions and 36 deletions.
25 changes: 25 additions & 0 deletions app/controllers/hyrax/dashboard/profiles_controller_decorator.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# frozen_string_literal: true

# OVERRIDE FILE from Hyrax v5.0.0
# - Modify params to allow editing of additional User columns
# - Ensure the current user matches the requested URL.
module Hyrax
module Dashboard
module ProfilesControllerDecorator
EMAIL_OPTIONS = ['never', 'daily', 'weekly', 'monthly'].freeze

def frequency_options
EMAIL_OPTIONS.map do |item|
[I18n.t("hyrax.user_profile.email_frequency.#{item}"), item]
end
end

private

def user_params
params.require(:user).permit(:batch_email_frequency, :avatar, :facebook_handle, :twitter_handle,
:googleplus_handle, :linkedin_handle, :remove_avatar, :orcid)
end
end
end
end

Hyrax::Dashboard::ProfilesController.prepend(Hyrax::Dashboard::ProfilesControllerDecorator)

##
# Ensure the current user matches the requested URL.
Expand Down
74 changes: 74 additions & 0 deletions app/jobs/batch_email_notification_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# frozen_string_literal: true

class BatchEmailNotificationJob < ApplicationJob
non_tenant_job
after_perform do |job|
reenqueue(job.arguments.first)
end

def perform(account)
Apartment::Tenant.switch(account.tenant) do
# Query for all users that have email_frequency turned off
users = User.where.not(batch_email_frequency: "never")
users.each do |user|
next unless send_email_today?(user)
# Find all undelivered messages within the frequency range of a user and any emails that haven't been sent
undelivered_messages =
Mailboxer::Message.joins(:receipts)
.where(mailboxer_receipts: { receiver_id: user.id, receiver_type: 'User', is_delivered: false })
.where('mailboxer_notifications.created_at >= ?', frequency_date(user.batch_email_frequency))
.select('mailboxer_notifications.*')
.distinct
.to_a

next if undelivered_messages.blank?
send_email(user, undelivered_messages, account)

# Mark the as read
undelivered_messages.each do |message|
message.receipts.each do |receipt|
receipt.update(is_delivered: true)
end
end

user.update(last_emailed_at: Time.current)
end
end
end

private

def reenqueue(account)
BatchEmailNotificationJob.set(wait_until: Date.tomorrow.midnight).perform_later(account)
end

def send_email_today?(user)
return true if user.last_emailed_at.nil?

next_email_date = case user.batch_email_frequency
when "daily"
user.last_emailed_at + 1.day
when "weekly"
user.last_emailed_at + 1.week
when "monthly"
user.last_emailed_at + 1.month
end

Time.current >= next_email_date
end

def frequency_date(frequency)
case frequency
when "daily"
1.day.ago
when "weekly"
1.week.ago
when "monthly"
1.month.ago
end
end

def send_email(user, undelivered_messages, account)
HykuMailer.summary_email(user, undelivered_messages, account).deliver_now
end
end
18 changes: 18 additions & 0 deletions app/mailers/hyku_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,27 @@ def default_url_options
{ host: host_for_tenant }
end

def summary_email(user, messages, account)
@user = user
@messages = messages || []
@account = account
@url = notifications_url_for(@account)
@application_name = account.sites.application_name

mail(to: @user.email,
subject: "You have #{@messages.count} new message(s) on #{@application_name}",
from: @account.contact_email,
template_path: 'hyku_mailer',
template_name: 'summary_email')
end

private

def host_for_tenant
Account.find_by(tenant: Apartment::Tenant.current)&.cname || Account.admin_host
end

def notifications_url_for(account)
"https://#{account.cname}/notifications"
end
end
23 changes: 23 additions & 0 deletions app/models/mailboxer/receipt_decorator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

# OVERRIDE: Mailboxer v0.15.1 to mark receipts as delivered for users that
# set their `batch_email_frequency` to 'never'

module Mailboxer
module ReceiptDecorator
extend ActiveSupport::Concern

prepended do
after_create :mark_as_delivered
end

def mark_as_delivered
user = User.find_by(id: receiver_id)
return unless user&.batch_email_frequency == 'never'

update(is_delivered: true)
end
end
end

Mailboxer::Receipt.prepend(Mailboxer::ReceiptDecorator)
9 changes: 9 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class User < ApplicationRecord
devise(*Hyku::Application.user_devise_parameters)

after_create :add_default_group_membership!
after_update :mark_all_undelivered_messages_as_delivered!, if: -> { batch_email_frequency == 'never' }

# set default scope to exclude guest users
def self.default_scope
Expand Down Expand Up @@ -163,4 +164,12 @@ def add_default_group_membership!

Hyrax::Group.find_or_create_by!(name: Ability.registered_group_name).add_members_by_id(id)
end

# When the user sets their batch email frequency to 'never' then we want to mark all the messages
# (really the receipts of the messages) to is_delivered tru
def mark_all_undelivered_messages_as_delivered!
mailbox.receipts.where(is_delivered: false).find_each do |receipt|
receipt.update(is_delivered: true)
end
end
end
1 change: 1 addition & 0 deletions app/services/create_account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def schedule_recurring_jobs

EmbargoAutoExpiryJob.perform_later(account)
LeaseAutoExpiryJob.perform_later(account)
BatchEmailNotificationJob.perform_later(account)
end

private
Expand Down
42 changes: 42 additions & 0 deletions app/views/hyku_mailer/summary_email.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Notifications</title>
<style>
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
</style>
</head>
<body>
<h2>Hello, <%= @user.name %></h2>
<p>You have the following notifications:</p>
<p>Click <a href="<%= @url %>">here</a> to view them on <%= @application_name %>.</p>
<table>
<tr>
<th>Date</th>
<th>Subject</th>
<th>Message</th>
</tr>
<% @messages.each do |message| %>
<tr>
<td><%= message.created_at.to_date %></td>
<td><%= message.subject %></td>
<td><%= message.body.gsub('href="', "href=\"#{URI(@url).origin}").html_safe %></td>
</tr>
<% end %>
</table>
</body>
</html>
69 changes: 69 additions & 0 deletions app/views/hyrax/dashboard/profiles/_edit_primary.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<!-- OVERRIDE Hyrax 5.0: Add batch email frequency to User edit -->

<%= form_for @user,
url: hyrax.dashboard_profile_path(@user.to_param),
html: { multipart: true } do |f| %>
<div class="form-group row">
<%= f.label :avatar, t(".change_picture").html_safe, class: "col-4 col-form-label" %>
<div class="col-8">
<%= image_tag @user.avatar.url(:thumb) if @user.avatar? %>
<%= f.file_field :avatar %>
<%= f.hidden_field :avatar_cache %>
<span class="form-text"><%= t('.help_change_picture_type') %></span>

<div class="form-check">
<%= f.label :remove_avatar, class: 'form-check-label' do %>
<%= f.check_box :remove_avatar, class: 'form-check-input' %>
<%= t(".delete_picture") %>
<a href="#" id="delete_picture_help" data-toggle="popover" data-content="<%= t('.delete_picture_data_content') %>" data-original-title="<%= t('.delete_picture_data_original_title') %>"><i class="fa fa-question"></i></a>
<% end %>
</div>
</div>
</div><!-- .form-group -->

<% if Hyrax.config.arkivo_api? %>
<%= render partial: 'zotero', locals: { f: f, user: @user } %>
<% end %>

<div class="form-group row">
<%= f.label :orcid, class: 'col-4 col-form-label' do %>
<%= orcid_label %>
<% end %>
<div class="col-8">
<%= f.text_field :orcid, class: "form-control" %>
</div>
</div><!-- .form-group -->

<div class="form-group row">
<%= f.label :twitter_handle, t(".twitter_handle").html_safe, class: 'col-4 col-form-label' %>
<div class="col-8">
<%= f.text_field :twitter_handle, class: "form-control" %>
</div>
</div><!-- .form-group -->

<div class="form-group row">
<%= f.label :facebook_handle, t(".facebook_handle").html_safe, class: 'col-4 col-form-label' %>
<div class="col-8">
<%= f.text_field :facebook_handle, class: "form-control" %>
</div>
</div><!-- .form-group -->

<div class="form-group row">
<%= f.label :googleplus_handle, t(".google_handle").html_safe, class: 'col-4 col-form-label' %>
<div class="col-8">
<%= f.text_field :googleplus_handle, class: "form-control" %>
</div>
</div><!-- .form-group -->

<!-- OVERRIDE: Add batch email frequency to edit -->
<div class="form-group row">
<%= f.label :batch_email_frequency, t("hyrax.user_profile.email_frequency.label").html_safe, class: 'col-4 col-form-label' %>
<div class="col-8">
<%= f.select :batch_email_frequency, controller.frequency_options, {}, { class: "form-control" } %>
</div>
</div><!-- .form-group -->

<%= render 'trophy_edit', trophies: @trophies %>
<%= f.button t(".save_profile").html_safe, type: 'submit', class: "btn btn-primary" %>
<% end %>
87 changes: 87 additions & 0 deletions app/views/hyrax/users/_user_info.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<!-- OVERRIDE Hyrax 5.0: Display batch email frequency -->

<dl id="user_info">

<% if user.orcid.present? %>
<dt><%= orcid_label('profile') %></dt>
<dd><%= link_to user.orcid, user.orcid, { target: '_blank' } %></dd>
<% end %>
<% if Hyrax.config.arkivo_api? && user.zotero_userid.present? %>
<dt><%= zotero_label(html_class: 'profile') %></dt>
<dd><%= link_to zotero_profile_url(user.zotero_userid), zotero_profile_url(user.zotero_userid), { target: '_blank' } %></dd>
<% end %>
<% if user.facebook_handle.present? %>
<dt><span class="fa fa-facebook" aria-hidden="true"></span> Facebook Handle</dt>
<dd><%= link_to user.facebook_handle, "http://facebook.com/#{user.facebook_handle}", {target:'_blank'} %></dd>
<% end %>
<% if user.twitter_handle.present? %>
<dt><span class="fa fa-twitter" aria-hidden="true"></span> Twitter Handle</dt>
<dd><%= link_to user.twitter_handle, "http://twitter.com/#{user.twitter_handle}", {target:'_blank'} %></dd>
<% end %>
<% if user.googleplus_handle.present? %>
<dt><span class="fa fa-google-plus" aria-hidden="true"></span> Google+ Handle</dt>
<dd><%= link_to user.googleplus_handle, "http://google.com/+#{user.googleplus_handle}", {target:'_blank'} %></dd>
<% end %>
<% if user.linkedin_handle.present? %>
<dt><span class="fa fa-linkedin" aria-hidden="true"></span> LinkedIn</dt>
<dd><%= link_to "#{@linkedInUrl}", "#{@linkedInUrl}", { target: '_blank' } %></dd>
<% end %>

<dt><span class="fa fa-envelope" aria-hidden="true"></span> Email</dt>
<dd><%= mail_to user.email %></dd>

<% if user.chat_id %>
<dt><span class="fa fa-bullhorn" aria-hidden="true"></span> Chat ID</dt>
<dd><%= user.chat_id %></dd>
<% end %>
<% if user.website %>
<dt><span class="fa fa-globe" aria-hidden="true"></span> Website(s)</dt>
<dd><%= iconify_auto_link(user.website) %></dd>
<% end %>
<% if user.title %>
<dt>Title</dt>
<dd><%= user.title %></dd>
<% end %>
<% if user.admin_area %>
<dt>Administrative Area</dt>
<dd><%= user.admin_area %></dd>
<% end %>
<% if user.department %>
<dt>Department</dt>
<dd><%= user.department %></dd>
<% end %>
<% if user.office %>
<dt>Office</dt>
<dd><%= user.office %></dd>
<% end %>
<% if user.address %>
<dt><span class="fa fa-map-marker" aria-hidden="true"></span> Address</dt>
<dd><%= user.address %></dd>
<% end %>
<% if user.affiliation %>
<dt>Affiliation</dt>
<dd><%= user.affiliation %></dd>
<% end %>
<% if user.telephone %>
<dt><span class="fa fa-phone" aria-hidden="true"></span> Telephone</dt>
<dd><%= link_to_telephone(user) %></dd>
<% end %>

<!-- OVERRIDE Hyrax 5.0: Display batch email frequency -->
<dt><%= t("hyrax.user_profile.email_frequency.label").html_safe %></dt>
<% frequency = user.batch_email_frequency || 'not_set' %>
<dd><%= t("hyrax.user_profile.email_frequency.#{frequency}") %></dd>
</dl>
Loading

0 comments on commit 57108c2

Please sign in to comment.