Skip to content

Commit 4d4c6ad

Browse files
Hackathon Digest Mailer (#76)
Co-authored-by: Matt Almeida <matt7@hey.com>
1 parent f4f622b commit 4d4c6ad

File tree

34 files changed

+488
-99
lines changed

34 files changed

+488
-99
lines changed

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ gem "sprockets-rails"
1919
gem "importmap-rails"
2020
gem "turbo-rails"
2121
gem "stimulus-rails"
22+
gem "premailer-rails" # Inline CSS for emails
2223

2324
# Active Storage
2425
gem "aws-sdk-s3", require: false

Gemfile.lock

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ GEM
112112
countries (5.6.0)
113113
unaccent (~> 0.3)
114114
crass (1.0.6)
115+
css_parser (1.14.0)
116+
addressable
115117
date (3.3.3)
116118
debug (1.8.0)
117119
irb (>= 1.5.0)
@@ -136,6 +138,7 @@ GEM
136138
activerecord (>= 4.0)
137139
hashids (~> 1.0)
138140
hashids (1.0.6)
141+
htmlentities (4.3.4)
139142
i18n (1.14.1)
140143
concurrent-ruby (~> 1.0)
141144
image_processing (1.12.2)
@@ -202,6 +205,14 @@ GEM
202205
ast (~> 2.4.1)
203206
racc
204207
pg (1.5.3)
208+
premailer (1.21.0)
209+
addressable
210+
css_parser (>= 1.12.0)
211+
htmlentities (>= 4.0.0)
212+
premailer-rails (1.12.0)
213+
actionmailer (>= 3)
214+
net-smtp
215+
premailer (~> 1.7, >= 1.7.9)
205216
public_suffix (5.0.1)
206217
puma (6.3.0)
207218
nio4r (~> 2.0)
@@ -350,6 +361,7 @@ DEPENDENCIES
350361
letter_opener_web
351362
pagy
352363
pg
364+
premailer-rails
353365
puma
354366
rack-mini-profiler
355367
rails (~> 7.0.6)
8.29 KB
Loading

app/helpers/application_helper.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,37 @@
11
module ApplicationHelper
2+
# This method makes it easier to yield content with a default value.
3+
#
4+
# USAGE:
5+
# ```
6+
# <% yield_with_default_for :signature do %>
7+
# Default signature here
8+
# <% end %>
9+
# ```
10+
#
11+
# The same functionality can be achieved with the following code:
12+
# ```
13+
# <% if content_for?(:signature) %>
14+
# <%= yield :signature %>
15+
# <% else %>
16+
# Default signature here
17+
# <% end %>
18+
# ```
19+
#
20+
# In helpers, `content_for` is used instead of `yield`.
21+
#
22+
# For more information regarding `yield` and `content_for`, see:
23+
# - https://guides.rubyonrails.org/layouts_and_rendering.html#understanding-yield
24+
# - https://apidock.com/rails/ActionView/Helpers/CaptureHelper/content_for
25+
# - https://apidock.com/rails/v5.2.3/ActionView/Helpers/CaptureHelper/content_for%3F
26+
def yield_with_default_for(key, &block)
27+
default_key = :"default_#{key}"
28+
before_key = :"before_#{key}"
29+
after_key = :"after_#{key}"
30+
31+
content_for(default_key, &block)
32+
33+
concat content_for(before_key) if content_for?(before_key)
34+
concat content_for?(key) ? content_for(key) : content_for(default_key)
35+
concat content_for(after_key) if content_for?(after_key)
36+
end
237
end

app/helpers/mailer_helper.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module MailerHelper
2+
def recipient_name
3+
return unless @_message&.to&.one? # Abort if there are multiple recipients
4+
5+
recipient = @recipient || @user || User.find_by_email_address(@_message&.to&.first)
6+
recipient&.first_name
7+
end
8+
end

app/mailers/application_mailer.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,20 @@
11
class ApplicationMailer < ActionMailer::Base
22
default from: "hackathons@hackclub.com"
33
layout "mailer"
4+
5+
helper :mailer, :application
6+
7+
before_action :set_default_unsubscribe_urls
8+
after_action :set_unsubscribe_header
9+
10+
private
11+
12+
def set_default_unsubscribe_urls
13+
@unsubscribe_url = root_url
14+
@email_preferences_url = root_url
15+
end
16+
17+
def set_unsubscribe_header
18+
headers["List-Unsubscribe"] = "<#{@unsubscribe_url}>" if @unsubscribe_url
19+
end
420
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
class Hackathon::DigestMailer < ApplicationMailer
2+
def digest
3+
@digest = params[:digest]
4+
@recipient = @digest.recipient
5+
6+
@listings_by_subscription = @digest.listings
7+
.includes(:subscription, hackathon: {logo_attachment: :blob})
8+
.group_by(&:subscription)
9+
10+
mail to: @recipient.email_address, subject: "Hackathons near you"
11+
end
12+
end

app/models/hackathon/digest.rb

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,6 @@ class Hackathon::Digest < ApplicationRecord
1010
private
1111

1212
def delivery
13-
# TODO: Implement
14-
Class.new do
15-
def method_missing(_)
16-
# noop
17-
end
18-
19-
def respond_to_missing?
20-
true
21-
end
22-
end.new
13+
Hackathon::DigestMailer.with(digest: self).digest
2314
end
2415
end

app/models/hackathon/digest/listings.rb

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
module Hackathon::Digest::Listings
22
extend ActiveSupport::Concern
33

4-
include ByLocation
5-
64
included do
75
has_many :listings, dependent: :destroy
86
has_many :listed_hackathons, through: :listings, source: :hackathon
97
has_many :listed_subscriptions, through: :listings, source: :subscription
108

11-
before_create :build_list_of_relevant_hackathons
9+
before_validation :build_candidate_listings, on: :create
10+
validates_length_of :listings, minimum: 1, on: :create, message: "must not be empty"
1211
end
1312

1413
private
1514

16-
MAX_LISTINGS = 5
15+
LISTING_CRITERIA = [Criterion::Location]
16+
MAX_LISTINGS = 8
17+
18+
def applicable_listings(listing_criteria: LISTING_CRITERIA, max_listings: MAX_LISTINGS)
19+
listing_criteria
20+
.flat_map { |criterion| criterion.new(recipient:).candidate_listings }
21+
.sort_by { |candidate| candidate[:hackathon].starts_at }
22+
.first(max_listings)
23+
end
1724

18-
def build_list_of_relevant_hackathons(max_listings: MAX_LISTINGS)
19-
nearby_upcoming_hackathons.first(max_listings).each do |result|
25+
def build_candidate_listings
26+
applicable_listings.each do |result|
2027
listings.build hackathon: result[:hackathon], subscription: result[:subscription]
2128
end
2229
end

app/models/hackathon/digest/listings/by_location.rb

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)