Skip to content

Commit

Permalink
feat: privacy notification email
Browse files Browse the repository at this point in the history
  • Loading branch information
moughxyz committed Nov 17, 2024
1 parent 3647586 commit 9e74ed0
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 1 deletion.
8 changes: 7 additions & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ GEM
i18n (1.8.11)
concurrent-ruby (~> 1.0)
jmespath (1.4.0)
libv8-node (16.10.0.0-aarch64-linux)
libv8-node (16.10.0.0-arm64-darwin)
libv8-node (16.10.0.0-x86_64-darwin)
libv8-node (16.10.0.0-x86_64-linux)
Expand All @@ -169,6 +170,7 @@ GEM
marcel (1.0.2)
method_source (1.0.0)
mini_mime (1.1.2)
mini_portile2 (2.6.1)
mini_racer (0.5.0)
libv8-node (~> 16.10.0.0)
minitest (5.14.4)
Expand All @@ -178,6 +180,9 @@ GEM
net-ssh (>= 2.6.5, < 7.0.0)
net-ssh (6.1.0)
nio4r (2.5.8)
nokogiri (1.12.5)
mini_portile2 (~> 2.6.1)
racc (~> 1.4)
nokogiri (1.12.5-arm64-darwin)
racc (~> 1.4)
nokogiri (1.12.5-x86_64-darwin)
Expand Down Expand Up @@ -305,6 +310,7 @@ GEM
chronic (>= 0.6.3)

PLATFORMS
aarch64-linux
arm64-darwin-21
arm64-darwin-22
x86_64-darwin-18
Expand Down Expand Up @@ -353,4 +359,4 @@ DEPENDENCIES
whenever

BUNDLED WITH
2.3.15
2.4.22
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,30 @@ docker-compose up -d
```

Now the application should be running on http://localhost:3000

### Seeding data

```
TRUNCATE TABLE subscriptions;
TRUNCATE TABLE subscribers;
TRUNCATE TABLE authors;
INSERT INTO authors (secret, email, email_verified, created_at, updated_at)
VALUES
('secret1', '[email protected]', true, NOW(), NOW()),
('secret2', '[email protected]', true, NOW(), NOW()),
('secret3', '[email protected]', true, NOW(), NOW());
INSERT INTO subscribers (email, created_at, updated_at)
VALUES
('[email protected]', NOW(), NOW()),
('[email protected]', NOW(), NOW()),
('[email protected]', NOW(), NOW());
INSERT INTO subscriptions (author_id, subscriber_id, token, verified, frequency, created_at, updated_at)
VALUES
(1, 1, 'token1', true, 'daily', NOW(), NOW()),
(2, 2, 'token2', true, 'daily', NOW(), NOW()),
(3, 3, 'token3', true, 'daily', NOW(), NOW());
```
11 changes: 11 additions & 0 deletions app/mailers/subscription_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,15 @@ def new_subscription(subscription)

mail(to: subscription.author.email, subject: "New subscriber to #{subscription.author.title}")
end

def privacy_policy_update(subscription)
@subscriber = subscription.subscriber
@author = subscription.author
@unsubscribe_url = "#{@author.get_host}/subscriptions/#{subscription.id}/unsubscribe?t=#{subscription.token}"

mail(
to: subscription.subscriber.email,
subject: 'Listed Email Privacy Policy Update'
)
end
end
10 changes: 10 additions & 0 deletions app/views/subscription_mailer/privacy_policy_update.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<%= react_component("SubscriptionMailerPrivacyUpdate", props: {
subscriber: @subscriber.as_json(
only: :email
),
author: @author.as_json(
only: [],
methods: [:title, :url]
),
unsubscribeUrl: @unsubscribe_url
}) %>
57 changes: 57 additions & 0 deletions client/app/components/subscription_mailer/PrivacyUpdate.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import PropTypes from "prop-types";
import React from "react";

const PrivacyUpdate = ({ subscriber, author, unsubscribeUrl }) => (
<div>
<p>Hello {subscriber.email},</p>

<p>
You are currently subscribed to{" "}
<strong>
<a href={author.url}>{author.title}</a>
</strong>
's blog on Listed.
</p>

<p>We're writing to inform you about an important update to Listed's privacy policy.</p>

<p>
Starting next week, blog authors will be able to see the email addresses of their subscribers. Learn more about this update at{" "}
<a href="https://listed.to/@Listed/56444/unlocking-subscriber-portability">
https://listed.to/@Listed/56444/unlocking-subscriber-portability
</a>
.
</p>

<p>What this means for you:</p>
<ul>
<li>
<a href={author.url}>{author.title}</a> will be able to see your email address ({subscriber.email})
</li>
<li>This enables direct communication between you and the author</li>
<li>Your email will only be visible to authors whose blogs you're subscribed to</li>
</ul>

<p>
If you'd prefer not to share your email address with <a href={author.url}>{author.title}</a>, you can
unsubscribe using the link below before this change takes effect.
</p>

<div className="links-footer">
<a href={unsubscribeUrl}>Unsubscribe</a>
</div>
</div>
);

PrivacyUpdate.propTypes = {
subscriber: PropTypes.shape({
email: PropTypes.string.isRequired,
}).isRequired,
author: PropTypes.shape({
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
}).isRequired,
unsubscribeUrl: PropTypes.string.isRequired,
};

export default PrivacyUpdate;
2 changes: 2 additions & 0 deletions client/app/startup/serverRegistration.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import Usage from "../components/usage/Usage";
import UsageNewAuthor from "../components/usage/NewAuthor";
import ReactionSuccess from "../components/reactions/ReactionSuccess";
import NewReaction from "../components/reactions/New";
import SubscriptionMailerPrivacyUpdate from "../components/subscription_mailer/PrivacyUpdate";

ReactOnRails.register({
AdminMailerNewDomainRequest,
Expand Down Expand Up @@ -63,4 +64,5 @@ ReactOnRails.register({
SubscriptionValidate,
Usage,
UsageNewAuthor,
SubscriptionMailerPrivacyUpdate,
});
23 changes: 23 additions & 0 deletions lib/tasks/privacy_notification.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace :privacy do
desc 'Send privacy policy update emails to all subscribers'
task notify_subscribers: :environment do
# Get all verified and non-unsubscribed subscriptions
subscriptions = Subscription.where(verified: true, unsubscribed: false)

total = subscriptions.count
current = 0

puts "Sending privacy update emails to #{total} subscriptions..."

subscriptions.find_each do |subscription|
SubscriptionMailer.privacy_policy_update(subscription).deliver_later
current += 1

puts "Processed #{current}/#{total} subscriptions..." if current % 100 == 0
rescue StandardError => e
puts "Error sending to subscription #{subscription.id}: #{e.message}"
end

puts 'Completed sending privacy update emails'
end
end
47 changes: 47 additions & 0 deletions lib/tasks/seed_authors.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace :db do
desc "Seed authors and subscriptions"
task seed_authors: :environment do
# Create 3 authors
3.times do |i|
author = Author.create!(
secret: SecureRandom.hex(10),
username: "author#{i}",
display_name: "Author #{i}",
email: "author#{i}@example.com",
email_verified: true,
bio: "This is author #{i}'s bio"
)

# Create 5 subscribers for each author
5.times do |j|
subscriber = Subscriber.create!(
email: "subscriber#{i}_#{j}@example.com"
)

# Create verified subscription
Subscription.create!(
author: author,
subscriber: subscriber,
token: SecureRandom.hex(10),
verified: true,
frequency: ['daily', 'weekly'].sample,
last_mailing: DateTime.now - rand(1..10).days
)
end

# Create some posts for each author
3.times do |k|
Post.create!(
author: author,
title: "Post #{k} by Author #{i}",
text: "This is the content of post #{k}",
token: SecureRandom.hex(10),
published: true,
author_show: true
)
end
end

puts "Created 3 authors with 5 verified subscribers each and 3 posts each"
end
end

0 comments on commit 9e74ed0

Please sign in to comment.