Refactor and clean up New-Topic via Email

With the new email_in admin configuration setting, emails to the email_in_address fetched via POP will now be processed and posted as new topics to the forum.

With the email_in_min_trust you can control the trust level the user needs to have at least to be able to post an email as a new topic.

Also contains tests for the email-in feature and minor clean ups
This commit is contained in:
Benjamin Kampmann 2014-02-24 17:36:53 +01:00
parent dad43b9853
commit 4af2cf3f23
7 changed files with 164 additions and 42 deletions

View file

@ -90,11 +90,3 @@ cors_origin = '*'
# enable if you really need to serve assets in prd
serve_static_assets = false
# Enable new topic creation via email by setting this value to "true"
allow_new_topics_from_email =
# Set the default category for new threads by entering the category number here
default_categories_id =

View file

@ -791,6 +791,10 @@ en:
pop3s_polling_host: "The host to poll for email via POP3S"
pop3s_polling_username: "The username for the POP3S account to poll for email"
pop3s_polling_password: "The password for the POP3S account to poll for email"
email_in: "Allow users to post new topics via email"
email_in_address: "The email address the users can post new topics to. None means users can't post globally."
email_in_min_trust: "The minimum trust level an users needs to have to be allowed to post new topics via email"
email_in_category: "The category new emails are posted into"
enable_mailing_list_mode: "Allow users to (optionally) opt-in to mailing list mode via a user preference"
minimum_topics_similar: "How many topics need to exist in the database before similar topics are presented."

View file

@ -235,6 +235,12 @@ email:
pop3s_polling_port: 995
pop3s_polling_username: ''
pop3s_polling_password: ''
email_in: false
email_in_address: ''
email_in_min_trust:
default: 3
enum: 'MinTrustToCreateTopicSetting'
email_in_category: -1
enable_mailing_list_mode:
default: false
client: true

View file

@ -1,12 +1,4 @@
## App Setup
> TODO build an admin UI for this, get it out of discourse_defaults.conf
Enable new topic creation via email by setting this value to "true"
`allow_new_topics_from_email = `
Set the default category for new threads by entering the category number here
`default_categories_id = `
## Admin UI Setup

View file

@ -31,6 +31,15 @@ module Email
discourse_email_parser
return Email::Receiver.results[:unprocessable] if @body.blank?
if SiteSetting.email_in and @message.to.first == SiteSetting.email_in_address
@user = User.find_by_email(@message.from.first)
return Email::Receiver.results[:unprocessable] if @user.blank? or not @user.has_trust_level?(TrustLevel.levels[SiteSetting.email_in_min_trust.to_i])
create_new_topic
return Email::Receiver.results[:processed]
end
@reply_key = @message.to.first
# Extract the `reply_key` from the format the site has specified
@ -39,19 +48,12 @@ module Email
@reply_key.gsub!(t, "") if t.present?
end
# Look up the email log for the reply key, or create a new post if there is none
# Enabled when config/discourse.conf contains "allow_new_topics_from_email = true"
# Look up the email log for the reply key
@email_log = EmailLog.for(reply_key)
if @email_log.blank?
return Email::Receiver.results[:unprocessable] if GlobalSetting.allow_new_topics_from_email == false
@subject = @message.subject
@user_info = User.find_by_email(@message.from.first)
return Email::Receiver.results[:unprocessable] if @user_info.blank?
Rails.logger.debug "Creating post from #{@message.from.first} with subject #{@subject}"
create_new
else
create_reply
end
return Email::Receiver.results[:missing] if @email_log.blank?
create_reply
Email::Receiver.results[:processed]
rescue
Email::Receiver.results[:error]
@ -137,20 +139,25 @@ module Email
creator.create
end
def create_new
# Try to create a new topic with the body and subject
# looking to config/discourse.conf to set category
if defined? GlobalSetting.default_categories_id
@categoryID = 1
else
@categoryID = GlobalSetting.default_categories_id
end
creator = PostCreator.new(@user_info,
title: @subject,
raw: @body,
category: @categoryID,
cooking_options: {traditional_markdown_linebreaks: true})
creator.create
def create_new_topic
# Try to post the body as a reply
topic_creator = TopicCreator.new(@user,
Guardian.new(@user),
category: SiteSetting.email_in_category.to_i,
title: @message.subject)
topic = topic_creator.create
post_creator = PostCreator.new(@user,
raw: @body,
topic_id: topic.id,
cooking_options: {traditional_markdown_linebreaks: true})
post_creator.create
EmailLog.create(email_type: "topic_via_incoming_email",
to_address: SiteSetting.email_in_address,
topic_id: topic.id, user_id: @user.id)
topic
end
end

View file

@ -7,6 +7,7 @@ describe Email::Receiver do
before do
SiteSetting.stubs(:reply_by_email_address).returns("reply+%{reply_key}@appmail.adventuretime.ooo")
SiteSetting.stubs(:email_in).returns(false)
end
describe "exception raised" do
@ -204,5 +205,100 @@ greatest show ever created. Everyone should watch it.
end
describe "processes a valid incoming email" do
before do
SiteSetting.stubs(:email_in_address).returns("discourse-in@appmail.adventuretime.ooo")
SiteSetting.stubs(:email_in_category).returns("42")
SiteSetting.stubs(:email_in).returns(true)
end
let(:incoming_email) { File.read("#{Rails.root}/spec/fixtures/emails/valid_incoming.eml") }
let(:receiver) { Email::Receiver.new(incoming_email) }
let(:user) { Fabricate.build(:user, id: 3456) }
let(:subject) { "We should have a post-by-email-feature." }
let(:email_body) {
"Hey folks,
I was thinking. Wouldn't it be great if we could post topics via email? Yes it would!
Jakie" }
describe "email from non user" do
before do
User.expects(:find_by_email).returns(nil)
end
let!(:result) { receiver.process }
it "returns unprocessable" do
expect(result).to eq(Email::Receiver.results[:unprocessable])
end
end
describe "email from untrusted user" do
before do
User.expects(:find_by_email).with(
"jake@adventuretime.ooo").returns(user)
SiteSetting.stubs(:email_in_min_trust).returns(TrustLevel.levels[:elder].to_s)
end
let!(:result) { receiver.process }
it "returns unprocessable" do
expect(result).to eq(Email::Receiver.results[:unprocessable])
end
end
describe "with proper user" do
before do
SiteSetting.stubs(:email_in_min_trust).returns(TrustLevel.levels[:newuser].to_s)
User.expects(:find_by_email).with(
"jake@adventuretime.ooo").returns(user)
topic_creator = mock()
TopicCreator.expects(:new).with(instance_of(User),
instance_of(Guardian),
has_entries(title: subject,
category: 42))
.returns(topic_creator)
topic_creator.expects(:create).returns(topic_creator)
topic_creator.expects(:id).twice.returns(12345)
post_creator = mock
PostCreator.expects(:new).with(instance_of(User),
has_entries(raw: email_body,
topic_id: 12345,
cooking_options: {traditional_markdown_linebreaks: true}))
.returns(post_creator)
post_creator.expects(:create)
EmailLog.expects(:create).with(has_entries(
email_type: 'topic_via_incoming_email',
to_address: "discourse-in@appmail.adventuretime.ooo",
user_id: 3456,
topic_id: 12345
))
end
let!(:result) { receiver.process }
it "returns a processed result" do
expect(result).to eq(Email::Receiver.results[:processed])
end
it "extracts the body" do
expect(receiver.body).to eq(email_body)
end
end
end
end

25
spec/fixtures/emails/valid_incoming.eml vendored Normal file
View file

@ -0,0 +1,25 @@
Return-Path: <jake@adventuretime.ooo>
Received: from iceking.adventuretime.ooo ([unix socket]) by iceking (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA; Thu, 13 Jun 2013 17:03:50 -0400
Received: from mail-ie0-x234.google.com (mail-ie0-x234.google.com [IPv6:2607:f8b0:4001:c03::234]) by iceking.adventuretime.ooo (8.14.3/8.14.3/Debian-9.4) with ESMTP id r5DL3nFJ016967 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for <discourse-in@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400
Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <discourse-in@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 14:03:48 -0700
Received: by 10.0.0.1 with HTTP; Thu, 13 Jun 2013 14:03:48 -0700
Date: Thu, 13 Jun 2013 17:03:48 -0400
From: Jake the Dog <jake@adventuretime.ooo>
To: discourse-in@appmail.adventuretime.ooo
Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com>
Subject: We should have a post-by-email-feature.
Mime-Version: 1.0
Content-Type: text/plain;
charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
X-Sieve: CMU Sieve 2.2
X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu,
13 Jun 2013 14:03:48 -0700 (PDT)
X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1
Hey folks,
I was thinking. Wouldn't it be great if we could post topics via email? Yes it would!
Jakie