Skip to content

Commit

Permalink
Send email notifications for replies (#62)
Browse files Browse the repository at this point in the history
  • Loading branch information
cbothner authored Jul 6, 2017
2 parents 416da74 + 18ba4e3 commit 02f9f15
Show file tree
Hide file tree
Showing 23 changed files with 501 additions and 396 deletions.
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
AllCops:
TargetRubyVersion: 2.3
Style/AsciiComments:
Enabled: false
Security/YAMLLoad:
Enabled: false
4 changes: 2 additions & 2 deletions app/assets/stylesheets/forms.sass
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ select, input, textarea, button
font-family: $sansFont

.edit_reader, .new_reader
label
label:not(.notification)
font: 600 80% $sansFont
text-transform: uppercase
letter-spacing: 0.05em
Expand All @@ -34,7 +34,7 @@ select, input, textarea, button
.pt-checkbox
margin: 5px 0 0 0

.pt-control
.pt-control:not(.notification)
text-transform: uppercase

.actions
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/readers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def reader_params
@reader_can_set_password = @reader && !@reader.created_password
end

permitted = %i[name initials email locale]
permitted = %i[name initials email locale send_reply_notifications]
permitted << :password if @reader_can_set_password

params.require(:reader).permit(*permitted)
Expand Down
9 changes: 9 additions & 0 deletions app/helpers/comment_threads_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module CommentThreadsHelper
def comment_thread_url(locale, comment_thread)
"#{case_url(locale, comment_thread.card.case.slug)}" \
"/#{comment_thread.card.element.case_element.position}" \
"/cards/#{comment_thread.card_id}/comments"
end
end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class NotificationBroadcastJob < ActiveJob::Base
class ReplyNotificationBroadcastJob < ActiveJob::Base
queue_as :default

def perform(notification)
Expand All @@ -12,7 +12,6 @@ def perform(notification)
private

def render_notification(notification)
ApplicationController.renderer.render partial: 'notifications/notification',
locals: { notification: notification }
ApplicationController.renderer.render notification
end
end
4 changes: 3 additions & 1 deletion app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

class ApplicationMailer < ActionMailer::Base
helper :application
default from: 'Michigan Sustainability Cases <hello@learnmsc.org>'

FROM_ADDRESS = 'hello@learnmsc.org'
default from: "Michigan Sustainability Cases <#{FROM_ADDRESS}>"

layout 'mailer'
end
40 changes: 40 additions & 0 deletions app/mailers/reply_notification_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# frozen_string_literal: true

class ReplyNotificationMailer < ApplicationMailer
helper :cases
helper :comment_threads

def notify(notification)
@notification = notification
reader = @notification.reader
return unless reader.send_reply_notifications

mail(to: reader.name_and_email,
from: from_header,
subject: subject_header) do |format|
format.text
format.html
end
end

private

# Build the from header. We’re setting the from name to the name of the
# reader whose comment triggered the notification, but the from address
# remains our notification address so as not to trip spam filters
def from_header
"#{@notification.notifier.name} <#{ApplicationMailer::FROM_ADDRESS}>"
end

# Build the email subject as follows
# RE: [National Adaptation] “I understand that Ethiopia would be a...” (# 46)
#
# Every notification of a reply to the same original comment will have the
# same subject so that they can be threaded
def subject_header
comment_thread = @notification.comment_thread
"RE: [#{@notification.case.kicker}] " \
"“#{comment_thread.comments.first.content.truncate(40)}” " \
"(##{comment_thread.id})"
end
end
23 changes: 11 additions & 12 deletions app/models/comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Comment < ApplicationRecord

translates :content

acts_as_list scope: :comment_thread
default_scope { order :created_at }

validates :content, presence: :true

Expand All @@ -20,18 +20,17 @@ def timestamp

private

def notification_data
{ notifier_id: reader.id,
comment_thread_id: comment_thread.id,
card_id: comment_thread.card.id,
case_id: comment_thread.card.case.id,
page_id: comment_thread.card.element.id }
end

def send_notifications_of_reply
(comment_thread.collocutors - [reader]).each do |r|
Notification.create reader: r, category: :reply_to_thread,
data: notification_data
card = comment_thread.card
comment_thread.collocutors.each do |other_reader|
next if other_reader == reader
ReplyNotification.create reader: other_reader,
notifier: reader,
comment: self,
comment_thread: comment_thread,
card: card,
case: card.case,
page: card.element
end
end
end
1 change: 0 additions & 1 deletion app/models/comment_thread.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ class CommentThread < ApplicationRecord
belongs_to :reader
belongs_to :group
belongs_to :card
belongs_to :case
has_many :comments, dependent: :restrict_with_error

def collocutors
Expand Down
46 changes: 0 additions & 46 deletions app/models/notification.rb

This file was deleted.

20 changes: 20 additions & 0 deletions app/models/reply_notification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

class ReplyNotification < ApplicationRecord
belongs_to :reader
belongs_to :notifier, class_name: 'Reader'
belongs_to :comment
belongs_to :comment_thread
belongs_to :case
belongs_to :page
belongs_to :card

after_create_commit { ReplyNotificationBroadcastJob.perform_now self }
after_create_commit { ReplyNotificationMailer.notify(self).deliver }

def message
I18n.t 'notifications.replied_to_your_comment',
notifier: notifier.name,
case_kicker: self.case.kicker
end
end
3 changes: 2 additions & 1 deletion app/views/layouts/mailer.text.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<%= sanitize yield, tags: [] %>
<% if content_for? :headline %># <%= content_for :headline %>
<% end %><%= sanitize yield, tags: [] %>

--
<% if content_for? :email_footer %>
Expand Down
16 changes: 0 additions & 16 deletions app/views/notifications/_notification.json.jbuilder

This file was deleted.

8 changes: 8 additions & 0 deletions app/views/readers/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
= t 'activerecord.attributes.user.email'
= f.email_field :email, class: "pt-input pt-fill", tabindex: 3

%h2= t '.notification_settings'
%div{ style: 'padding-bottom: 1em'}

= f.label :send_reply_notifications, class: 'notification pt-control pt-checkbox' do
= t 'activerecord.attributes.reader.send_reply_notifications'
= f.check_box :send_reply_notifications
%span.pt-control-indicator

.actions
= f.submit t('.save'), class: "o-button pt-button pt-intent-primary"

Expand Down
16 changes: 16 additions & 0 deletions app/views/reply_notification_mailer/notify.markerb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<% headline one_liner "#{@notification.notifier.name} replied to your comment" %>
<% background_image_url ix_cover_image @notification.case, :email %>

<%= @notification.comment.content %>

<%= md_button_to "Reply online",
comment_thread_url(I18n.locale, @notification.comment_thread) %>

<% email_footer <<-FOOTER
You are receiving this email because someone replied to a comment you made on a
Michigan Sustainability Case you’re studying. If you do not want to receive
emails like this, you can [change your notification settings](#{
edit_reader_url @notification.reader.locale, @notification.reader
}).
FOOTER
%>
14 changes: 14 additions & 0 deletions app/views/reply_notifications/_reply_notification.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

json.key_format! camelize: :lower

json.extract! reply_notification, :id, :message, :card_id, :comment_thread_id
json.notifier do
json.extract! reply_notification.notifier, :id, :name, :initials
end
json.case do
json.extract! reply_notification.case, :slug, :kicker
end
json.element do
json.extract! reply_notification.page.case_element, :position
end
3 changes: 0 additions & 3 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ dependencies:
override:
- yarn
- bundle install
compile:
override:
- RAILS_ENV=test rails webpacker:compile
test:
override:
- bundle exec rspec -r rspec_junit_formatter --format progress --format RspecJunitFormatter -o $CIRCLE_TEST_REPORTS/rspec/junit.xml:
Expand Down
1 change: 1 addition & 0 deletions config/locales/translations/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ en:
reset_password_token: Reset password token #g
uid: UID #g
initials: Initials
send_reply_notifications: Notify me when someone replies to a comment I wrote

question:
content: Content
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class AddReplyNotificationFlagToReader < ActiveRecord::Migration[5.0]
def change
add_column :readers, :send_reply_notifications, :boolean, default: true
end
end
16 changes: 16 additions & 0 deletions db/migrate/20170705164751_create_reply_notifications.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class CreateReplyNotifications < ActiveRecord::Migration[5.0]
def change
create_table :reply_notifications do |t|
t.references :reader

t.integer :notifier_id
t.integer :comment_id
t.integer :comment_thread_id
t.integer :case_id
t.integer :page_id
t.integer :card_id
end
end
end
15 changes: 15 additions & 0 deletions db/migrate/20170705165135_drop_notifications.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class DropNotifications < ActiveRecord::Migration[5.0]
def change
drop_table :notifications do |t|
t.boolean :email_sent
t.boolean :read
t.references :reader, foreign_key: true
t.integer :category
t.jsonb :data

t.timestamps
end
end
end
Loading

0 comments on commit 02f9f15

Please sign in to comment.