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
This commit is contained in:
Sam
2019-03-06 18:38:49 +11:00
parent 8d7c10f7f2
commit b2187301fd
5 changed files with 79 additions and 7 deletions

View File

@ -899,6 +899,22 @@ module Email
create_post_with_attachments(options) create_post_with_attachments(options)
end 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 = {}) def create_reply(options = {})
raise TopicNotFoundError if options[:topic].nil? || options[:topic].trashed? raise TopicNotFoundError if options[:topic].nil? || options[:topic].trashed?
raise BouncedEmailError if options[:bounce] && options[:topic].archetype != Archetype.private_message 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]) if post_action_type = post_action_for(options[:raw])
create_post_action(options[:user], options[:post], post_action_type) 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 else
raise TopicClosedError if options[:topic].closed? raise TopicClosedError if options[:topic].closed?
options[:topic_id] = options[:topic].id options[:topic_id] = options[:topic].id

View File

@ -251,6 +251,10 @@ describe Email::Receiver do
) )
end 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 it "uses MD5 of 'mail_string' there is no message_id" do
mail_string = email(:missing_message_id) mail_string = email(:missing_message_id)
expect { Email::Receiver.new(mail_string).process! }.to change { IncomingEmail.count } 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) expect { process(:reply_user_matching) }.to raise_error(Email::Receiver::TopicNotFoundError)
end end
it "raises a TopicClosedError when the topic was closed" do context "a closed topic" do
topic.update_columns(closed: true)
expect { process(:reply_user_matching) }.to raise_error(Email::Receiver::TopicClosedError)
end
it "does not raise TopicClosedError when performing a like action" do before do
topic.update_columns(closed: true) topic.update_columns(closed: true)
expect { process(:like) }.to change(PostAction, :count) 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 end
it "raises an InvalidPost when there was an error while creating the post" do it "raises an InvalidPost when there was an error while creating the post" do

10
spec/fixtures/emails/mute.eml vendored Normal file
View File

@ -0,0 +1,10 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <13@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
mute

10
spec/fixtures/emails/track.eml vendored Normal file
View File

@ -0,0 +1,10 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <13@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
track

10
spec/fixtures/emails/watch.eml vendored Normal file
View File

@ -0,0 +1,10 @@
Return-Path: <discourse@bar.com>
From: Foo Bar <discourse@bar.com>
To: reply+4f97315cc828096c9cb34c6f1a0d6fe8@bar.com
Date: Fri, 15 Jan 2016 00:12:43 +0100
Message-ID: <13@foo.bar.mail>
Mime-Version: 1.0
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
watch