easy unsubscribe baked into emails

This commit is contained in:
Kyle Drake 2015-01-07 15:24:15 -08:00
parent 39ce179d16
commit be0267956b
6 changed files with 91 additions and 3 deletions

View file

@ -15,7 +15,10 @@ def require_ownership_for_settings
end
end
get '/settings/:username/?' do
get '/settings/:username/?' do |username|
# This is for the email_unsubscribe below
pass if Site.select(:id).where(username: username).first.nil?
require_login
require_ownership_for_settings
erb :'settings/site'
@ -282,3 +285,19 @@ post '/settings/create_child' do
redirect '/settings#sites'
end
end
get '/settings/unsubscribe_email/?' do
redirect "/settings/#email" if signed_in?
if params[:email] && params[:token] && params[:email] != '' && Site.valid_email_unsubscribe_token?(params[:email], params[:token])
Site.where(email: params[:email]).all.each do |site|
site.send_emails = false
site.save_changes validate: false
end
@message = "You have been successfully unsubscribed from future emails to #{params[:email]}. Our apologies for the inconvenience."
else
@message = 'There was an error unsubscribing your email address. Please contact support.'
end
erb :'settings/account/unsubscribe'
end

View file

@ -206,6 +206,14 @@ class Site < Sequel::Model
end
class << self
def valid_email_unsubscribe_token?(email, token)
email_unsubscribe_token(email) == token
end
def email_unsubscribe_token(email)
Digest::SHA2.hexdigest email+$config['email_unsubscribe_token']
end
def valid_login?(username_or_email, plaintext)
site = get_with_identifier username_or_email

View file

@ -66,6 +66,49 @@ describe 'site/settings' do
end
end
describe 'unsubscribe email' do
include Capybara::DSL
before do
@email = "#{SecureRandom.uuid.gsub('-', '')}@example.com"
@site = Fabricate :site, email: @email
EmailWorker.jobs.clear
Mail::TestMailer.deliveries.clear
@params = {
email: @site.email,
token: Site.email_unsubscribe_token(@site.email)
}
@params_query = Rack::Utils.build_query(@params)
@email_unsubscribe_url = "https://neocities.org/settings/unsubscribe_email?"+@params_query
page.set_rack_session id: nil
end
it 'should redirect to settings page if logged in' do
page.set_rack_session id: @site.id
end
it 'should unsubscribe for valid token' do
@site.send_email subject: 'Hello', body: 'Okay'
EmailWorker.drain
email = Mail::TestMailer.deliveries.first
email.body.to_s.must_match @email_unsubscribe_url
@site.send_emails.must_equal true
visit '/settings/unsubscribe_email?'+@params_query
page.body.must_match /You have been successfully unsubscribed.+#{@site.email}/i
@site.reload.send_emails.must_equal false
end
it 'should fail to subscribe for bad token' do
end
end
describe 'change password' do
include Capybara::DSL

View file

@ -18,6 +18,9 @@ describe EmailWorker do
mail.from.first.must_equal 'from@example.com'
mail.to.first.must_equal 'to@example.com'
mail.subject.must_equal 'Hello World'
mail.body.to_s.must_equal 'testing'
body = mail.body.to_s
puts body
body.must_match /testing/
body.must_match /unsubscribe/
end
end

View file

@ -0,0 +1,11 @@
<div class="header-Outro">
<div class="row content single-Col">
<h1>Email Unsubscribe</h1>
</div>
</div>
<div class="content single-Col misc-page">
<article>
<%= @message %>
</article>
</div>

View file

@ -3,13 +3,17 @@ class EmailWorker
sidekiq_options queue: :emails, retry: 10, backtrace: true
def perform(args={})
unsubscribe_token = Site.email_unsubscribe_token args['to']
footer = "\n\n---\nYou are receiving this email because you have a Neocities site. If you would like to subscribe from Neocities emails, just visit this url:\nhttps://neocities.org/settings/unsubscribe_email?email=#{Rack::Utils.escape args['to']}&token=#{unsubscribe_token}"
Mail.deliver do
# TODO this is not doing UTF-8 properly.
from args['from']
reply_to args['reply_to']
to args['to']
subject args['subject']
body args['body']
body args['body']+footer
end
end
end