Skip to content

Commit

Permalink
Merge pull request #2313 from alphagov/add-bulk-unsubscribe-from-subs…
Browse files Browse the repository at this point in the history
…criber-list

Add rake task to bulk unsubscribe active subscribers from a subscription list
  • Loading branch information
deborahchua authored Jan 27, 2025
2 parents 91194ff + 72b818a commit 87689fa
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 6 deletions.
7 changes: 7 additions & 0 deletions docs/support-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ You can find out the slug of the subscriber list by running the `view_subscripti
$ kubectl -n apps exec -it deploy/email-alert-api -- bundle exec rake support:unsubscribe_single_subscription[<email_address>,<subscriber_list_slug>]
```

## Unsubscribe all subscribers from a specific subscription

This task unsubscribes all active subscribers from a subscription, given a subscriber list slug.

```bash
$ kubectl -n apps exec -it deploy/email-alert-api -- bundle exec rake support:unsubscribe_all_subscribers_from_subscription[<subscriber_list_slug>]

## Unsubscribe a subscriber from all emails

This task unsubscribes one subscriber from everything they have subscribed to.
Expand Down
23 changes: 22 additions & 1 deletion lib/tasks/support.rake
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,34 @@ namespace :support do
active_subscription = Subscription.active.find_by(subscriber_list:, subscriber:)
if active_subscription
active_subscription.end(reason: :unsubscribed)
puts "Unsubscribing from #{email_address} from #{subscriber_list_slug}"
puts "Unsubscribing #{email_address} from #{subscriber_list_slug}"
else
puts "Subscriber #{email_address} already unsubscribed from #{subscriber_list_slug}"
end
end
end

desc "Unsubscribe all active subscribers from a single subscription list"
task :unsubscribe_all_subscribers_from_subscription, [:subscriber_list_slug] => :environment do |_t, args|
subscriber_list_slug = args[:subscriber_list_slug]
subscriber_list = SubscriberList.find_by(slug: subscriber_list_slug)

abort("Cannot find subscriber list #{subscriber_list_slug}") if subscriber_list.nil?

subscribers = subscriber_list.subscribers

subscribers.each do |subscriber|
active_subscription = Subscription.active.find_by(subscriber_list:, subscriber:)

if active_subscription
active_subscription.end(reason: :unsubscribed)
puts "Unsubscribing #{subscriber.address} from #{subscriber_list_slug}"
else
puts "Subscriber #{subscriber.address} already unsubscribed from #{subscriber_list_slug}"
end
end
end

desc "Unsubscribe a subscriber from all subscriptions"
task :unsubscribe_all_subscriptions, [:email_address] => :environment do |_t, args|
email_address = args[:email_address]
Expand Down
182 changes: 177 additions & 5 deletions spec/lib/tasks/support_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
RSpec.describe "support" do
after(:each) do
Rake::Task["support:emails:stats_for_content_id"].reenable
end

describe "stats_for_content_id" do
after(:each) do
Rake::Task["support:emails:stats_for_content_id"].reenable
end

context "with invalid dates" do
it "outputs all subscriptions for a subscriber" do
expect { Rake::Task["support:emails:stats_for_content_id"].invoke(SecureRandom.uuid, "bad_date", "bad_date") }
Expand Down Expand Up @@ -47,8 +47,17 @@
end

describe "view_emails" do
after(:each) do
Rake::Task["support:view_emails"].reenable
end

it "displays error message if email is not provided" do
expect { Rake::Task["support:view_emails"].invoke }
.to raise_error(ArgumentError, /Provide an email!/)
end

it "outputs the latest emails sent to an email address" do
expect { Rake::Task["support:view_emails"].invoke("[email protected]") }
expect { Rake::Task["support:view_emails"].invoke("[email protected]", 1) }
.to output.to_stdout
end
end
Expand Down Expand Up @@ -109,4 +118,167 @@
end
end
end

describe "#unsubscribe_all_subscribers_from_subscription" do
after(:each) do
Rake::Task["support:unsubscribe_all_subscribers_from_subscription"].reenable
end

it "outputs an error message to the user if subscription list is not found" do
expect { Rake::Task["support:unsubscribe_all_subscribers_from_subscription"].invoke("invalid-subscription-list") }
.to raise_error(SystemExit, /Cannot find subscriber list invalid-subscription-list/)
end

it "successfully unsubscribes active subscribers from valid subscription list" do
subscriber = create(:subscriber, address: "[email protected]")
subscriber_list = create(:subscriber_list, slug: "my-list", title: "My List")
active_subscription = create(:subscription, subscriber_list:, subscriber:)

expect { Rake::Task["support:unsubscribe_all_subscribers_from_subscription"].invoke("my-list") }
.to output("Unsubscribing [email protected] from my-list\n").to_stdout
.and change { active_subscription.reload.ended_reason }
.from(nil)
.to("unsubscribed")
end

it "displays message if subscriber has already been unsubscribed from valid subscription list" do
subscriber = create(:subscriber, address: "[email protected]")
subscriber_list = create(:subscriber_list, slug: "another-list", title: "Another List")
create(:subscription, :ended, subscriber_list:, subscriber:)

expect { Rake::Task["support:unsubscribe_all_subscribers_from_subscription"].invoke("another-list") }
.to output(/Subscriber [email protected] already unsubscribed from another-list/).to_stdout
end
end

describe "unsubscribe_single_subscription" do
before do
@subscriber_list = create(:subscriber_list, slug: "my-list", title: "My List")
end

after(:each) do
Rake::Task["support:unsubscribe_single_subscription"].reenable
end

it "displays error message if subscriber is not found" do
expect { Rake::Task["support:unsubscribe_single_subscription"].invoke("[email protected]", "my-list") }
.to output(/Subscriber [email protected] not found/).to_stdout
end

it "displays error message if subscriber list is not found but subscriber exists" do
create(:subscriber, address: "[email protected]")

expect { Rake::Task["support:unsubscribe_single_subscription"].invoke("[email protected]", "invalid-subscription-list") }
.to output(/Subscriber list invalid-subscription-list not found/).to_stdout
end

it "displays error message if subscriber is not subscribed to subscriber list" do
create(:subscriber, address: "[email protected]")

expect { Rake::Task["support:unsubscribe_single_subscription"].invoke("[email protected]", "my-list") }
.to output(/Subscriber [email protected] does not appear to be signed up for my-list/).to_stdout
end

it "successfully unsubscribes an active subscriber" do
subscriber = create(:subscriber, address: "[email protected]")
active_subscription = create(:subscription, subscriber_list: @subscriber_list, subscriber:)

expect { Rake::Task["support:unsubscribe_single_subscription"].invoke("[email protected]", "my-list") }
.to output(/Unsubscribing [email protected] from my-list/).to_stdout
.and change { active_subscription.reload.ended_reason }
.from(nil)
.to("unsubscribed")
end

it "displays message if subscriber has already been unsubscribed" do
subscriber = create(:subscriber, address: "[email protected]")
create(:subscription, :ended, subscriber_list: @subscriber_list, subscriber:)

expect { Rake::Task["support:unsubscribe_single_subscription"].invoke("[email protected]", "my-list") }
.to output(/Subscriber [email protected] already unsubscribed from my-list/).to_stdout
end
end

describe "unsubscribe_all_subscriptions" do
after(:each) do
Rake::Task["support:unsubscribe_all_subscriptions"].reenable
end

it "displays error essage if the subscriber is not found" do
expect { Rake::Task["support:unsubscribe_all_subscriptions"].invoke("[email protected]") }
.to output(/Subscriber [email protected] not found/).to_stdout
end

it "displays message if user has been unsubscribed" do
subscriber_list1 = create(:subscriber_list, slug: "my-list", title: "My List")
subscriber_list2 = create(:subscriber_list, slug: "another-list", title: "another List")
subscriber = create(:subscriber, address: "[email protected]")
active_subscription1 = create(:subscription, subscriber_list: subscriber_list1, subscriber:)
active_subscription2 = create(:subscription, subscriber_list: subscriber_list2, subscriber:)

expect { Rake::Task["support:unsubscribe_all_subscriptions"].invoke("[email protected]") }
.to output(/Unsubscribing [email protected]/).to_stdout
.and change { active_subscription1.reload.ended_reason }
.from(nil)
.to("unsubscribed")
.and change { active_subscription2.reload.ended_reason }
.from(nil)
.to("unsubscribed")
end
end

describe "change_email_address" do
after(:each) do
Rake::Task["support:change_email_address"].reenable
end

it "displays error message and aborts if email address is not found" do
expect { Rake::Task["support:change_email_address"].invoke("[email protected]", "[email protected]") }
.to raise_error(SystemExit, /Cannot find any subscriber with email address [email protected]/)
end

it "displays message when email address for subsciber has been changed" do
subscriber = create(:subscriber, address: "[email protected]")

expect { Rake::Task["support:change_email_address"].invoke("[email protected]", "[email protected]") }
.to output(/Changed email address for [email protected] to [email protected]/).to_stdout
.and change { subscriber.reload.address }
.from("[email protected]")
.to("[email protected]")
end
end

describe "view_subscriptions" do
after(:each) do
Rake::Task["support:view_subscriptions"].reenable
end

it "displays error message and aborts if email address is not found" do
expect { Rake::Task["support:view_subscriptions"].invoke("[email protected]") }
.to raise_error(SystemExit, /Cannot find any subscriber with email address [email protected]/)
end

it "displays all subscriptions for a subscriber" do
subscriber = create(:subscriber, address: "[email protected]")
subscriber_list1 = create(:subscriber_list, slug: "my-list", title: "My List")
subscriber_list2 = create(:subscriber_list, slug: "another-list", title: "Another List")
subscription1 = create(:subscription, subscriber_list: subscriber_list1, subscriber:)
subscription2 = create(:subscription, :ended, subscriber_list: subscriber_list2, subscriber:)

report = <<~TEXT
[{:status=>"Active",
:subscriber_list=>"#{subscriber_list1.title} (slug: #{subscriber_list1.slug})",
:frequency=>"#{subscription1.frequency}",
:timeline=>"Subscribed #{subscription1.created_at}"},
{:status=>"Inactive (#{subscription2.ended_reason})",
:subscriber_list=>"#{subscriber_list2.title} (slug: #{subscriber_list2.slug})",
:frequency=>"#{subscription2.frequency}",
:timeline=>
"Subscribed #{subscription2.created_at}, Ended #{subscription2.ended_at}"}]
TEXT

expect { Rake::Task["support:view_subscriptions"].invoke("[email protected]") }
.to output(report).to_stdout
end
end
end

0 comments on commit 87689fa

Please sign in to comment.