FEATURE: allow users to easily track/watch/mute topics via email

FEATURE: allow users to easily track/watch/mute topics via email

If you reply to an email with the word “mute” a topic will be muted If you reply to an email with the word “track” a topic will be tracked If you reply to an email with the word “watch” a topic will be watched

These ninja command can help advanced mailing list ex-users, saves a trip to the website

diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb
index 7366261..c7f706d 100644
--- a/lib/email/receiver.rb
+++ b/lib/email/receiver.rb
@@ -899,6 +899,22 @@ module Email
       create_post_with_attachments(options)
     end
 
+    def notification_level_for(body)
+      # since we are stripping save all this work on long replies
+      return nil if body.length > 40
+
+      body = body.strip.downcase
+      case body
+      when "mute"
+        NotificationLevels.topic_levels[:muted]
+      when "track"
+        NotificationLevels.topic_levels[:tracking]
+      when "watch"
+        NotificationLevels.topic_levels[:watching]
+      else nil
+      end
+    end
+
     def create_reply(options = {})
       raise TopicNotFoundError if options[:topic].nil? || options[:topic].trashed?
       raise BouncedEmailError if options[:bounce] && options[:topic].archetype != Archetype.private_message
@@ -908,6 +924,8 @@ module Email
 
       if post_action_type = post_action_for(options[:raw])
         create_post_action(options[:user], options[:post], post_action_type)
+      elsif notification_level = notification_level_for(options[:raw])
+        TopicUser.change(options[:user].id, options[:post].topic_id, notification_level: notification_level)
       else
         raise TopicClosedError if options[:topic].closed?
         options[:topic_id] = options[:topic].id
diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb
index f243065..a87629e 100644
--- a/spec/components/email/receiver_spec.rb
+++ b/spec/components/email/receiver_spec.rb
@@ -251,6 +251,10 @@ describe Email::Receiver do
       )
     end
 
+    let :topic_user do
+      TopicUser.find_by(topic_id: topic.id, user_id: user.id)
+    end
+
     it "uses MD5 of 'mail_string' there is no message_id" do
       mail_string = email(:missing_message_id)
       expect { Email::Receiver.new(mail_string).process! }.to change { IncomingEmail.count }
@@ -285,14 +289,34 @@ describe Email::Receiver do
       expect { process(:reply_user_matching) }.to raise_error(Email::Receiver::TopicNotFoundError)
     end
 
-    it "raises a TopicClosedError when the topic was closed" do
-      topic.update_columns(closed: true)
-      expect { process(:reply_user_matching) }.to raise_error(Email::Receiver::TopicClosedError)
-    end
+    context "a closed topic" do
 
-    it "does not raise TopicClosedError when performing a like action" do
-      topic.update_columns(closed: true)
-      expect { process(:like) }.to change(PostAction, :count)
+      before do
+        topic.update_columns(closed: true)
+      end
+
+      it "raises a TopicClosedError when the topic was closed" do
+        expect { process(:reply_user_matching) }.to raise_error(Email::Receiver::TopicClosedError)
+      end
+
+      it "Can watch topics via the watch command" do
+        # TODO support other locales as well, the tricky thing is that these string live in
+        # client.yml not on server yml so it is a bit tricky to find
+
+        topic.update_columns(closed: true)
+        process(:watch)
+        expect(topic_user.notification_level).to eq(NotificationLevels.topic_levels[:watching])
+      end
+
+      it "Can mute topics via the mute command" do
+        process(:mute)
+        expect(topic_user.notification_level).to eq(NotificationLevels.topic_levels[:muted])
+      end
+
+      it "can track a topic via the track command" do
+        process(:track)
+        expect(topic_user.notification_level).to eq(NotificationLevels.topic_levels[:tracking])
+      end
     end
 
     it "raises an InvalidPost when there was an error while creating the post" do
diff --git a/spec/fixtures/emails/mute.eml b/spec/fixtures/emails/mute.eml
new file mode 100644
index 0000000..62dea40
Binary files /dev/null and b/spec/fixtures/emails/mute.eml differ
diff --git a/spec/fixtures/emails/track.eml b/spec/fixtures/emails/track.eml
new file mode 100644
index 0000000..a7d7ad1
Binary files /dev/null and b/spec/fixtures/emails/track.eml differ
diff --git a/spec/fixtures/emails/watch.eml b/spec/fixtures/emails/watch.eml
new file mode 100644
index 0000000..446ff77
Binary files /dev/null and b/spec/fixtures/emails/watch.eml differ

GitHub sha: b2187301

1 Like

This commit has been mentioned on Discourse Meta. There might be relevant details there: