diff --git a/config/discourse_defaults.conf b/config/discourse_defaults.conf index 5fa0b3c9f8a..f4ede17d424 100644 --- a/config/discourse_defaults.conf +++ b/config/discourse_defaults.conf @@ -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 = - - diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index a5b70719ef3..2361259da21 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -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." diff --git a/config/site_settings.yml b/config/site_settings.yml index ef00962fb4a..b02d9c77666 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -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 diff --git a/docs/MAILING-LIST-SETUP.MD b/docs/MAILING-LIST-SETUP.MD index f400f2453b0..ed5aded1064 100644 --- a/docs/MAILING-LIST-SETUP.MD +++ b/docs/MAILING-LIST-SETUP.MD @@ -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 diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index 4c161f04646..da8d1602795 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -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 diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index ad3dcb7b5f3..2e6235101f3 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -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 diff --git a/spec/fixtures/emails/valid_incoming.eml b/spec/fixtures/emails/valid_incoming.eml new file mode 100644 index 00000000000..329e6cc6486 --- /dev/null +++ b/spec/fixtures/emails/valid_incoming.eml @@ -0,0 +1,25 @@ +Return-Path: +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 ; Thu, 13 Jun 2013 17:03:50 -0400 +Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for ; 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 +To: discourse-in@appmail.adventuretime.ooo +Message-ID: +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 +