From 3cec3882ee925460c3afebe1eaca0b39cd6719c9 Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Sat, 19 Oct 2024 01:49:19 +0100
Subject: [PATCH 1/8] AO3-6810 Add work.hidden_for_spam virtual attribute

---
 app/models/moderated_work.rb            |  1 +
 app/models/work.rb                      |  7 ++++++-
 features/admins/admin_works.feature     | 25 +++++++++++++++++++++++++
 features/step_definitions/work_steps.rb |  5 +++++
 4 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/app/models/moderated_work.rb b/app/models/moderated_work.rb
index e6124be2471..67d1b4962b2 100644
--- a/app/models/moderated_work.rb
+++ b/app/models/moderated_work.rb
@@ -41,6 +41,7 @@ def self.bulk_review(ids)
     where(id: ids).update_all(reviewed: true, approved: false)
     # Ensure works are hidden and spam if they weren't already
     Work.joins(:moderated_work).where("moderated_works.id IN (?)", ids).each do |work|
+      work.hidden_for_spam = true
       work.update(hidden_by_admin: true, spam: true)
     end
   end
diff --git a/app/models/work.rb b/app/models/work.rb
index 0881823f956..5f784d7462f 100755
--- a/app/models/work.rb
+++ b/app/models/work.rb
@@ -75,6 +75,9 @@ def create_stat_counter
   attr_accessor :new_gifts
   attr_accessor :preview_mode
 
+  # Virtual attribute for when a work is to be hidden, whether if it's for spam or other reasons, so different emails can be sent
+  attr_accessor :hidden_for_spam
+
   # return title.html_safe to overcome escaping done by sanitiser
   def title
     read_attribute(:title).try(:html_safe)
@@ -1121,6 +1124,7 @@ def hide_spam
     return unless spam?
     admin_settings = AdminSetting.current
     if admin_settings.hide_spam?
+      self.hidden_for_spam = true
       self.hidden_by_admin = true
     end
   end
@@ -1132,6 +1136,7 @@ def moderate_spam
   def mark_as_spam!
     update_attribute(:spam, true)
     ModeratedWork.mark_reviewed(self)
+    self.hidden_for_spam = true
     # don't submit spam reports unless in production mode
     Rails.env.production? && Akismetor.submit_spam(akismet_attributes)
   end
@@ -1146,7 +1151,7 @@ def mark_as_ham!
   def notify_of_hiding
     return unless hidden_by_admin? && saved_change_to_hidden_by_admin?
     users.each do |user|
-      if spam?
+      if spam? && hidden_for_spam
         UserMailer.admin_spam_work_notification(id, user.id).deliver_after_commit
       else
         UserMailer.admin_hidden_work_notification(id, user.id).deliver_after_commit
diff --git a/features/admins/admin_works.feature b/features/admins/admin_works.feature
index 39807cbd650..ec3f6315486 100644
--- a/features/admins/admin_works.feature
+++ b/features/admins/admin_works.feature
@@ -32,6 +32,27 @@ Feature: Admin Actions for Works, Comments, Series, Bookmarks
       | superadmin       |
       | legal            |
       | policy_and_abuse |
+  
+    Scenario Outline: Can hide works already marked as spam
+    Given I am logged in as "regular_user"
+      And I post the work "ToS Violation + Spam"
+      And the work "ToS Violation + Spam" is marked as spam
+    When I am logged in as a "<role>" admin
+      And all emails have been delivered
+      And I view the work "ToS Violation + Spam"
+      And I follow "Hide Work"
+    Then I should see "Item has been hidden."
+      And logged out users should not see the hidden work "ToS Violation + Spam" by "regular_user"
+      And logged in users should not see the hidden work "ToS Violation + Spam" by "regular_user"
+      And "regular_user" should see their work "ToS Violation + Spam" is hidden
+      And 1 email should be delivered
+      And the email should contain "you will be required to take action to correct the violation"
+    
+    Examples:
+      | role             |
+      | superadmin       |
+      | legal            |
+      | policy_and_abuse |
 
   Scenario Outline: Can unhide works
     Given I am logged in as "regular_user"
@@ -361,12 +382,16 @@ Feature: Admin Actions for Works, Comments, Series, Bookmarks
   Given the work "Spammity Spam"
     And I am logged in as a "policy_and_abuse" admin
     And I view the work "Spammity Spam"
+    And all emails have been delivered 
   Then I should see "Mark As Spam"
   When I follow "Mark As Spam"
   Then I should see "marked as spam and hidden"
     And I should see "Mark Not Spam"
     And the work "Spammity Spam" should be marked as spam
     And the work "Spammity Spam" should be hidden
+    And 1 email should be delivered
+    And the email should contain "has been flagged by our automated system as spam"
+
 
   Scenario: can mark a spam work as not-spam
   Given the spam work "Spammity Spam"
diff --git a/features/step_definitions/work_steps.rb b/features/step_definitions/work_steps.rb
index 0086cbfe51f..40e227ff574 100644
--- a/features/step_definitions/work_steps.rb
+++ b/features/step_definitions/work_steps.rb
@@ -264,6 +264,11 @@
   w.update_attribute(:hidden_by_admin, true)
 end
 
+Given /^the work "([^\"]*)" is marked as spam$/ do |work|
+  w = Work.find_by_title(work)
+  w.update_attribute(:spam, true)
+end
+
 Given "the user-defined tag limit is {int}" do |count|
   allow(ArchiveConfig).to receive(:USER_DEFINED_TAGS_MAX).and_return(count)
 end

From d9d90068dc51b79dd2b6fc0c63b70edc1609f868 Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Wed, 20 Nov 2024 22:51:38 +0000
Subject: [PATCH 2/8] AO3-6810 Remove virtual attribute and add tests for bulk
 hiding

---
 .../admin/user_creations_controller.rb        |  5 ++-
 app/models/moderated_work.rb                  |  4 ++-
 app/models/work.rb                            | 20 +++++------
 features/admins/admin_spam.feature            | 35 +++++++++++++++++--
 features/admins/admin_works.feature           |  2 +-
 features/step_definitions/work_steps.rb       |  4 ++-
 6 files changed, 54 insertions(+), 16 deletions(-)

diff --git a/app/controllers/admin/user_creations_controller.rb b/app/controllers/admin/user_creations_controller.rb
index 6e5d0300a33..c088d6d509c 100644
--- a/app/controllers/admin/user_creations_controller.rb
+++ b/app/controllers/admin/user_creations_controller.rb
@@ -38,7 +38,10 @@ def set_spam
     AdminActivity.log_action(current_admin, @creation, action: action, summary: @creation.inspect)    
     if params[:spam] == "true"
       @creation.mark_as_spam!
-      @creation.update_attribute(:hidden_by_admin, true)
+      if not @creation.hidden_by_admin
+        @creation.notify_of_hiding_for_spam() if @creation_class == Work
+        @creation.update_attribute(:hidden_by_admin, true)
+      end
       flash[:notice] = ts("Work was marked as spam and hidden.")
     else
       @creation.mark_as_ham!
diff --git a/app/models/moderated_work.rb b/app/models/moderated_work.rb
index 67d1b4962b2..2a8d15cb50b 100644
--- a/app/models/moderated_work.rb
+++ b/app/models/moderated_work.rb
@@ -41,7 +41,9 @@ def self.bulk_review(ids)
     where(id: ids).update_all(reviewed: true, approved: false)
     # Ensure works are hidden and spam if they weren't already
     Work.joins(:moderated_work).where("moderated_works.id IN (?)", ids).each do |work|
-      work.hidden_for_spam = true
+      if not work.hidden_by_admin?
+        work.notify_of_hiding_for_spam()
+      end
       work.update(hidden_by_admin: true, spam: true)
     end
   end
diff --git a/app/models/work.rb b/app/models/work.rb
index 5f784d7462f..ea9ff6671c3 100755
--- a/app/models/work.rb
+++ b/app/models/work.rb
@@ -75,9 +75,6 @@ def create_stat_counter
   attr_accessor :new_gifts
   attr_accessor :preview_mode
 
-  # Virtual attribute for when a work is to be hidden, whether if it's for spam or other reasons, so different emails can be sent
-  attr_accessor :hidden_for_spam
-
   # return title.html_safe to overcome escaping done by sanitiser
   def title
     read_attribute(:title).try(:html_safe)
@@ -1124,8 +1121,9 @@ def hide_spam
     return unless spam?
     admin_settings = AdminSetting.current
     if admin_settings.hide_spam?
-      self.hidden_for_spam = true
+      return if self.hidden_by_admin
       self.hidden_by_admin = true
+      notify_of_hiding_for_spam()
     end
   end
 
@@ -1136,7 +1134,6 @@ def moderate_spam
   def mark_as_spam!
     update_attribute(:spam, true)
     ModeratedWork.mark_reviewed(self)
-    self.hidden_for_spam = true
     # don't submit spam reports unless in production mode
     Rails.env.production? && Akismetor.submit_spam(akismet_attributes)
   end
@@ -1150,12 +1147,15 @@ def mark_as_ham!
 
   def notify_of_hiding
     return unless hidden_by_admin? && saved_change_to_hidden_by_admin?
+    return if spam?
     users.each do |user|
-      if spam? && hidden_for_spam
-        UserMailer.admin_spam_work_notification(id, user.id).deliver_after_commit
-      else
-        UserMailer.admin_hidden_work_notification(id, user.id).deliver_after_commit
-      end
+      UserMailer.admin_hidden_work_notification(id, user.id).deliver_after_commit
+    end
+  end
+
+  def notify_of_hiding_for_spam
+    users.each do |user|
+      UserMailer.admin_spam_work_notification(id, user.id).deliver_after_commit
     end
   end
 
diff --git a/features/admins/admin_spam.feature b/features/admins/admin_spam.feature
index ded7525a80c..cca10b26247 100644
--- a/features/admins/admin_spam.feature
+++ b/features/admins/admin_spam.feature
@@ -4,10 +4,39 @@ Feature: Admin spam management
   As an an admin
   I want to be able to view and update works marked as spam
 
-Scenario: Review spam
-  Given the spam work "Spammity Spam"
+Scenario: Review spam when spam works are already hidden
+  Given the following admin settings are configured:
+    | hide_spam | 1 |
+    And the spam work "Spammity Spam"
     And the spam work "Totally Legit"
+    And the work "Spammity Spam" should be hidden
+    And the work "Totally Legit" should be hidden
+    And I am logged in as a "superadmin" admin
+    And all emails have been delivered
+  Then I should see "Spam"
+  When I follow "Spam"
+  Then I should see "Works Marked as Spam"
+    And I should see "Spammity"
+    And I should see "Totally Legit"
+  When I check "spam_1"
+    And I check "ham_2"
+    And I press "Update Works"
+  Then I should not see "Spammity"
+    And I should not see "Totally Legit"
+    And the work "Spammity Spam" should be hidden
+    And the work "Totally Legit" should not be hidden
+    And 0 email should be delivered
+
+
+Scenario: Review spam when spam works are not already hidden
+  Given the following admin settings are configured:
+    | hide_spam | 0 |
+    And the spam work "Spammity Spam"
+    And the spam work "Totally Legit"
+    And the work "Spammity Spam" should not be hidden
+    And the work "Totally Legit" should not be hidden
     And I am logged in as a "superadmin" admin
+    And all emails have been delivered
   Then I should see "Spam"
   When I follow "Spam"
   Then I should see "Works Marked as Spam"
@@ -20,3 +49,5 @@ Scenario: Review spam
     And I should not see "Totally Legit"
     And the work "Spammity Spam" should be hidden
     And the work "Totally Legit" should not be hidden
+    And 1 email should be delivered
+    And the email should contain "has been flagged by our automated system as spam"
diff --git a/features/admins/admin_works.feature b/features/admins/admin_works.feature
index ec3f6315486..4478dc0d9fc 100644
--- a/features/admins/admin_works.feature
+++ b/features/admins/admin_works.feature
@@ -382,7 +382,7 @@ Feature: Admin Actions for Works, Comments, Series, Bookmarks
   Given the work "Spammity Spam"
     And I am logged in as a "policy_and_abuse" admin
     And I view the work "Spammity Spam"
-    And all emails have been delivered 
+    And all emails have been delivered
   Then I should see "Mark As Spam"
   When I follow "Mark As Spam"
   Then I should see "marked as spam and hidden"
diff --git a/features/step_definitions/work_steps.rb b/features/step_definitions/work_steps.rb
index 40e227ff574..8b0ade36078 100644
--- a/features/step_definitions/work_steps.rb
+++ b/features/step_definitions/work_steps.rb
@@ -261,7 +261,9 @@
   step %{I log out}
   w = Work.find_by_title(work)
   w.update_attribute(:spam, true)
-  w.update_attribute(:hidden_by_admin, true)
+
+  admin_settings = AdminSetting.current
+  w.update_attribute(:hidden_by_admin, true) if admin_settings.hide_spam?
 end
 
 Given /^the work "([^\"]*)" is marked as spam$/ do |work|

From 94718747392603b25e52a27ba927ad4036da0a7f Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Wed, 20 Nov 2024 22:56:40 +0000
Subject: [PATCH 3/8] AO3-6810 Rubocop code style

---
 app/controllers/admin/user_creations_controller.rb | 4 ++--
 app/models/moderated_work.rb                       | 4 ++--
 app/models/work.rb                                 | 4 +++-
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/app/controllers/admin/user_creations_controller.rb b/app/controllers/admin/user_creations_controller.rb
index c088d6d509c..69272e2b800 100644
--- a/app/controllers/admin/user_creations_controller.rb
+++ b/app/controllers/admin/user_creations_controller.rb
@@ -38,8 +38,8 @@ def set_spam
     AdminActivity.log_action(current_admin, @creation, action: action, summary: @creation.inspect)    
     if params[:spam] == "true"
       @creation.mark_as_spam!
-      if not @creation.hidden_by_admin
-        @creation.notify_of_hiding_for_spam() if @creation_class == Work
+      unless @creation.hidden_by_admin
+        @creation.notify_of_hiding_for_spam if @creation_class == Work
         @creation.update_attribute(:hidden_by_admin, true)
       end
       flash[:notice] = ts("Work was marked as spam and hidden.")
diff --git a/app/models/moderated_work.rb b/app/models/moderated_work.rb
index 2a8d15cb50b..56607530b0e 100644
--- a/app/models/moderated_work.rb
+++ b/app/models/moderated_work.rb
@@ -41,8 +41,8 @@ def self.bulk_review(ids)
     where(id: ids).update_all(reviewed: true, approved: false)
     # Ensure works are hidden and spam if they weren't already
     Work.joins(:moderated_work).where("moderated_works.id IN (?)", ids).each do |work|
-      if not work.hidden_by_admin?
-        work.notify_of_hiding_for_spam()
+      unless work.hidden_by_admin?
+        work.notify_of_hiding_for_spam
       end
       work.update(hidden_by_admin: true, spam: true)
     end
diff --git a/app/models/work.rb b/app/models/work.rb
index ea9ff6671c3..ef528cb6f29 100755
--- a/app/models/work.rb
+++ b/app/models/work.rb
@@ -1122,8 +1122,9 @@ def hide_spam
     admin_settings = AdminSetting.current
     if admin_settings.hide_spam?
       return if self.hidden_by_admin
+
       self.hidden_by_admin = true
-      notify_of_hiding_for_spam()
+      notify_of_hiding_for_spam
     end
   end
 
@@ -1148,6 +1149,7 @@ def mark_as_ham!
   def notify_of_hiding
     return unless hidden_by_admin? && saved_change_to_hidden_by_admin?
     return if spam?
+    
     users.each do |user|
       UserMailer.admin_hidden_work_notification(id, user.id).deliver_after_commit
     end

From 481989b15bcf4ee6984acff345d41c4f2d801009 Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Thu, 21 Nov 2024 00:04:18 +0000
Subject: [PATCH 4/8] AO3-6810 Fix test

---
 app/controllers/admin/user_creations_controller.rb | 4 ++--
 app/models/work.rb                                 | 4 ++--
 features/admins/admin_spam.feature                 | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/app/controllers/admin/user_creations_controller.rb b/app/controllers/admin/user_creations_controller.rb
index 69272e2b800..9bffc42a017 100644
--- a/app/controllers/admin/user_creations_controller.rb
+++ b/app/controllers/admin/user_creations_controller.rb
@@ -37,11 +37,11 @@ def set_spam
     action = "mark as " + (params[:spam] == "true" ? "spam" : "not spam")
     AdminActivity.log_action(current_admin, @creation, action: action, summary: @creation.inspect)    
     if params[:spam] == "true"
-      @creation.mark_as_spam!
       unless @creation.hidden_by_admin
         @creation.notify_of_hiding_for_spam if @creation_class == Work
-        @creation.update_attribute(:hidden_by_admin, true)
+        @creation.hidden_by_admin = true
       end
+      @creation.mark_as_spam!
       flash[:notice] = ts("Work was marked as spam and hidden.")
     else
       @creation.mark_as_ham!
diff --git a/app/models/work.rb b/app/models/work.rb
index ef528cb6f29..cd1ec0a7a7c 100755
--- a/app/models/work.rb
+++ b/app/models/work.rb
@@ -1148,8 +1148,8 @@ def mark_as_ham!
 
   def notify_of_hiding
     return unless hidden_by_admin? && saved_change_to_hidden_by_admin?
-    return if spam?
-    
+    return if spam? && saved_change_to_spam?
+
     users.each do |user|
       UserMailer.admin_hidden_work_notification(id, user.id).deliver_after_commit
     end
diff --git a/features/admins/admin_spam.feature b/features/admins/admin_spam.feature
index cca10b26247..868f3c6e816 100644
--- a/features/admins/admin_spam.feature
+++ b/features/admins/admin_spam.feature
@@ -42,8 +42,8 @@ Scenario: Review spam when spam works are not already hidden
   Then I should see "Works Marked as Spam"
     And I should see "Spammity"
     And I should see "Totally Legit"
-  When I check "spam_1"
-    And I check "ham_2"
+  When I check "spam_3"
+    And I check "ham_4"
     And I press "Update Works"
   Then I should not see "Spammity"
     And I should not see "Totally Legit"

From 716ae7ea7872b06b6619540e823c5e5b78ba1c9f Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Thu, 21 Nov 2024 00:41:21 +0000
Subject: [PATCH 5/8] AO3-6810 Replace the 'spam?' rising edge detector with an
 internal virtual attribute

---
 app/models/work.rb | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/app/models/work.rb b/app/models/work.rb
index cd1ec0a7a7c..e87fe4332b1 100755
--- a/app/models/work.rb
+++ b/app/models/work.rb
@@ -75,6 +75,9 @@ def create_stat_counter
   attr_accessor :new_gifts
   attr_accessor :preview_mode
 
+  # Internal virtual attribute for whether if the hidden-for-spam email has been sent, so the normal work-hidden email should not be sent
+  attr_accessor :notified_of_hiding_for_spam
+
   # return title.html_safe to overcome escaping done by sanitiser
   def title
     read_attribute(:title).try(:html_safe)
@@ -1148,7 +1151,7 @@ def mark_as_ham!
 
   def notify_of_hiding
     return unless hidden_by_admin? && saved_change_to_hidden_by_admin?
-    return if spam? && saved_change_to_spam?
+    return if notified_of_hiding_for_spam
 
     users.each do |user|
       UserMailer.admin_hidden_work_notification(id, user.id).deliver_after_commit
@@ -1159,6 +1162,7 @@ def notify_of_hiding_for_spam
     users.each do |user|
       UserMailer.admin_spam_work_notification(id, user.id).deliver_after_commit
     end
+    self.notified_of_hiding_for_spam = true
   end
 
   #############################################################################

From b34897ac50fd34b7dfd8782b8128bab07c85169c Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Tue, 26 Nov 2024 01:51:32 +0000
Subject: [PATCH 6/8] AO3-6810 Fix test

---
 features/other_a/hit_counts.feature     | 2 +-
 features/step_definitions/work_steps.rb | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/features/other_a/hit_counts.feature b/features/other_a/hit_counts.feature
index 187f94380d4..be99a5e2f7b 100644
--- a/features/other_a/hit_counts.feature
+++ b/features/other_a/hit_counts.feature
@@ -41,7 +41,7 @@ Feature: Hit Counts
     Then I should see "Hits: 0"
 
   Scenario: Viewing a work hidden by an admin doesn't increment the hit count
-    Given the spam work "Hit Count Test"
+    Given the hidden work "Hit Count Test"
       And I am logged in as an admin
       And all hit count information is reset
     When I go to the work "Hit Count Test"
diff --git a/features/step_definitions/work_steps.rb b/features/step_definitions/work_steps.rb
index 8b0ade36078..f519769ace6 100644
--- a/features/step_definitions/work_steps.rb
+++ b/features/step_definitions/work_steps.rb
@@ -266,6 +266,13 @@
   w.update_attribute(:hidden_by_admin, true) if admin_settings.hide_spam?
 end
 
+Given /^the hidden work "([^\"]*)"$/ do |work|
+  step %{I have a work "#{work}"}
+  step %{I log out}
+  w = Work.find_by_title(work)
+  w.update_attribute(:hidden_by_admin, true)
+end
+
 Given /^the work "([^\"]*)" is marked as spam$/ do |work|
   w = Work.find_by_title(work)
   w.update_attribute(:spam, true)

From e97973f3954e7072fe4a7751b9c3ad4f8d34d50a Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Sun, 8 Dec 2024 15:53:25 +0000
Subject: [PATCH 7/8] AO3-6810 Revert test step changes

---
 features/step_definitions/work_steps.rb | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/features/step_definitions/work_steps.rb b/features/step_definitions/work_steps.rb
index f519769ace6..ea54b8c3540 100644
--- a/features/step_definitions/work_steps.rb
+++ b/features/step_definitions/work_steps.rb
@@ -261,9 +261,6 @@
   step %{I log out}
   w = Work.find_by_title(work)
   w.update_attribute(:spam, true)
-
-  admin_settings = AdminSetting.current
-  w.update_attribute(:hidden_by_admin, true) if admin_settings.hide_spam?
 end
 
 Given /^the hidden work "([^\"]*)"$/ do |work|

From 012e0dd3194a7302caccb10c143d4edc62593beb Mon Sep 17 00:00:00 2001
From: EchoEkhi <echoekhi@gmail.com>
Date: Fri, 20 Dec 2024 12:19:13 +0000
Subject: [PATCH 8/8] AO3-6810 Formatting

---
 app/models/moderated_work.rb            |  4 +---
 app/models/work.rb                      |  2 +-
 features/admins/admin_spam.feature      |  2 +-
 features/step_definitions/work_steps.rb | 12 ++++++------
 4 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/app/models/moderated_work.rb b/app/models/moderated_work.rb
index 56607530b0e..75760fd6365 100644
--- a/app/models/moderated_work.rb
+++ b/app/models/moderated_work.rb
@@ -41,9 +41,7 @@ def self.bulk_review(ids)
     where(id: ids).update_all(reviewed: true, approved: false)
     # Ensure works are hidden and spam if they weren't already
     Work.joins(:moderated_work).where("moderated_works.id IN (?)", ids).each do |work|
-      unless work.hidden_by_admin?
-        work.notify_of_hiding_for_spam
-      end
+      work.notify_of_hiding_for_spam unless work.hidden_by_admin?
       work.update(hidden_by_admin: true, spam: true)
     end
   end
diff --git a/app/models/work.rb b/app/models/work.rb
index e87fe4332b1..aaf904c38af 100755
--- a/app/models/work.rb
+++ b/app/models/work.rb
@@ -75,7 +75,7 @@ def create_stat_counter
   attr_accessor :new_gifts
   attr_accessor :preview_mode
 
-  # Internal virtual attribute for whether if the hidden-for-spam email has been sent, so the normal work-hidden email should not be sent
+  # Virtual attribute for whether the hidden-for-spam email has been sent, so the normal work-hidden email should not be sent
   attr_accessor :notified_of_hiding_for_spam
 
   # return title.html_safe to overcome escaping done by sanitiser
diff --git a/features/admins/admin_spam.feature b/features/admins/admin_spam.feature
index 868f3c6e816..fb7ef69484a 100644
--- a/features/admins/admin_spam.feature
+++ b/features/admins/admin_spam.feature
@@ -25,7 +25,7 @@ Scenario: Review spam when spam works are already hidden
     And I should not see "Totally Legit"
     And the work "Spammity Spam" should be hidden
     And the work "Totally Legit" should not be hidden
-    And 0 email should be delivered
+    And 0 emails should be delivered
 
 
 Scenario: Review spam when spam works are not already hidden
diff --git a/features/step_definitions/work_steps.rb b/features/step_definitions/work_steps.rb
index ea54b8c3540..ca77e376fdf 100644
--- a/features/step_definitions/work_steps.rb
+++ b/features/step_definitions/work_steps.rb
@@ -256,22 +256,22 @@
   step %{I am logged in as "#{work.users.first.login}"}
 end
 
-Given /^the spam work "([^\"]*)"$/ do |work|
+Given "the spam work {string}" do |work|
   step %{I have a work "#{work}"}
   step %{I log out}
-  w = Work.find_by_title(work)
+  w = Work.find_by(title: work)
   w.update_attribute(:spam, true)
 end
 
-Given /^the hidden work "([^\"]*)"$/ do |work|
+Given "the hidden work {string}" do |work|
   step %{I have a work "#{work}"}
   step %{I log out}
-  w = Work.find_by_title(work)
+  w = Work.find_by(title: work)
   w.update_attribute(:hidden_by_admin, true)
 end
 
-Given /^the work "([^\"]*)" is marked as spam$/ do |work|
-  w = Work.find_by_title(work)
+Given "the work {string} is marked as spam" do |work|
+  w = Work.find_by(title: work)
   w.update_attribute(:spam, true)
 end