From 86da47880a60dbb6f2483f7080e40197cca2b1e4 Mon Sep 17 00:00:00 2001 From: James Kiesel <james.kiesel@gmail.com> Date: Wed, 30 Dec 2015 12:17:45 +0100 Subject: [PATCH 1/4] Allow +1 via email --- lib/email/receiver.rb | 19 ++++++++++++- spec/components/email/receiver_spec.rb | 39 ++++++++++++++++++++++++++ spec/fixtures/emails/like.eml | 37 ++++++++++++++++++++++++ spec/fixtures/emails/plus_one.eml | 37 ++++++++++++++++++++++++ spec/fixtures/emails/too_short.eml | 2 +- 5 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 spec/fixtures/emails/like.eml create mode 100644 spec/fixtures/emails/plus_one.eml diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index 2c0983701dd..9cf07bf908f 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -21,6 +21,7 @@ module Email class ReplyUserNotFoundError < ProcessingError; end class ReplyUserNotMatchingError < ProcessingError; end class InactiveUserError < ProcessingError; end + class InvalidPostAction < ProcessingError; end attr_reader :body, :email_log @@ -103,7 +104,11 @@ module Email raise ReplyUserNotFoundError if user.blank? raise ReplyUserNotMatchingError if @email_log.user_id != user.id - create_reply(@email_log) + if post_action_type = post_action_for(@body) + create_post_action(@email_log, post_action_type) + else + create_reply(@email_log) + end end rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError => e @@ -239,6 +244,18 @@ module Email @body = "[quote=\"#{user_email}\"]\n#{@body}\n[/quote]" end + def create_post_action(email_log, type) + PostAction.act(email_log.user, email_log.post, type) + rescue PostAction::AlreadyActed => e + raise InvalidPostAction.new(e) + end + + def post_action_for(body) + if ['+1', I18n.t('post_action_types.like.title').downcase].include? body.downcase + PostActionType.types[:like] + end + end + def create_reply(email_log) create_post_with_attachments(email_log.user, raw: @body, diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index baa3037c41c..d5c20be381f 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -340,6 +340,45 @@ This is a link http://example.com" expect(Upload.find_by(sha1: upload_sha)).not_to eq(nil) end + describe 'Liking via email' do + let!(:reply_key) { '636ca428858779856c226bb145ef4fad' } + let(:replied_user_like_params) { { user: replying_user, post: post, post_action_type_id: PostActionType.types[:like] } } + let(:replied_user_like) { PostAction.find_by(replied_user_like_params) } + + describe "plus_one.eml" do + let!(:email_raw) { + fixture_file("emails/plus_one.eml") + .gsub("TO", "reply+#{reply_key}@appmail.adventuretime.ooo") + .gsub("FROM", replying_user_email) + } + + it "adds a user like to the post" do + expect { receiver.process }.to change { PostAction.count }.by(1) + expect(replied_user_like).to be_present + end + + it "does not create a duplicate like" do + PostAction.create(replied_user_like_params) + before_count = PostAction.count + expect { receiver.process }.to raise_error(Email::Receiver::InvalidPostAction) + expect(PostAction.count).to eq before_count + expect(replied_user_like).to be_present + end + end + + describe "like.eml" do + let!(:email_raw) { + fixture_file("emails/like.eml") + .gsub("TO", "reply+#{reply_key}@appmail.adventuretime.ooo") + .gsub("FROM", replying_user_email) + } + + it 'adds a user like to the post' do + expect { receiver.process }.to change { PostAction.count }.by(1) + expect(replied_user_like).to be_present + end + end + end end # === Failure Conditions === diff --git a/spec/fixtures/emails/like.eml b/spec/fixtures/emails/like.eml new file mode 100644 index 00000000000..3bd9ae0fa7c --- /dev/null +++ b/spec/fixtures/emails/like.eml @@ -0,0 +1,37 @@ +Return-Path: <FROM> +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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400 +Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@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: FROM +To: TO +Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com> +Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux' +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 + +LIKE + + +On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta +<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote: +> +> +> +> eviltrout posted in 'Adventure Time Sux' on Discourse Meta: +> +> --- +> hey guys everyone knows adventure time sucks! +> +> --- +> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3 +> +> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences). +> diff --git a/spec/fixtures/emails/plus_one.eml b/spec/fixtures/emails/plus_one.eml new file mode 100644 index 00000000000..a3255e9699c --- /dev/null +++ b/spec/fixtures/emails/plus_one.eml @@ -0,0 +1,37 @@ +Return-Path: <FROM> +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 <reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo>; Thu, 13 Jun 2013 17:03:50 -0400 +Received: by mail-ie0-f180.google.com with SMTP id f4so21977375iea.25 for <reply+59d8df8370b7e95c5a49fbf86aeb2c93@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: FROM +To: TO +Message-ID: <CADkmRc+rNGAGGbV2iE5p918UVy4UyJqVcXRO2=otppgzduJSg@mail.gmail.com> +Subject: re: [Discourse Meta] eviltrout posted in 'Adventure Time Sux' +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 + ++1 + + +On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta +<reply+59d8df8370b7e95c5a49fbf86aeb2c93@appmail.adventuretime.ooo> wrote: +> +> +> +> eviltrout posted in 'Adventure Time Sux' on Discourse Meta: +> +> --- +> hey guys everyone knows adventure time sucks! +> +> --- +> Please visit this link to respond: http://localhost:3000/t/adventure-time-sux/1234/3 +> +> To unsubscribe from these emails, visit your [user preferences](http://localhost:3000/user_preferences). +> diff --git a/spec/fixtures/emails/too_short.eml b/spec/fixtures/emails/too_short.eml index 54fed0f98c5..69f59769787 100644 --- a/spec/fixtures/emails/too_short.eml +++ b/spec/fixtures/emails/too_short.eml @@ -18,4 +18,4 @@ X-Received: by 10.0.0.1 with SMTP id n7mr11234144ipb.85.1371157428600; Thu, X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1 -+1 \ No newline at end of file +ok From a559754db37e1255337c2aaec1404b31f044065b Mon Sep 17 00:00:00 2001 From: James Kiesel <james.kiesel@gmail.com> Date: Wed, 30 Dec 2015 20:04:05 +0100 Subject: [PATCH 2/4] Add post action creator --- lib/email/receiver.rb | 3 ++- lib/post_action_creator.rb | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 lib/post_action_creator.rb diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index 9cf07bf908f..a8881a31ec6 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -1,5 +1,6 @@ require_dependency 'new_post_manager' require_dependency 'email/html_cleaner' +require_dependency 'post_action_creator' module Email @@ -245,7 +246,7 @@ module Email end def create_post_action(email_log, type) - PostAction.act(email_log.user, email_log.post, type) + PostActionCreator.new(email_log.user, email_log.post).perform(type) rescue PostAction::AlreadyActed => e raise InvalidPostAction.new(e) end diff --git a/lib/post_action_creator.rb b/lib/post_action_creator.rb new file mode 100644 index 00000000000..3d84b44d9f1 --- /dev/null +++ b/lib/post_action_creator.rb @@ -0,0 +1,20 @@ +# creates post actions based on a post and a user +class PostActionCreator + + def initialize(user, post) + @user = user + @post = post + end + + def perform(action) + guardian.ensure_post_can_act!(@post, action, taken_actions: PostAction.counts_for([@post], @user)[@post.id]) + PostAction.act(@user, @post, action) + end + + private + + def guardian + @guardian ||= Guardian.new(@user) + end + +end From 6ceb1089468893b58497f44252e5245e7b31bfc5 Mon Sep 17 00:00:00 2001 From: James Kiesel <james.kiesel@gmail.com> Date: Wed, 30 Dec 2015 20:52:36 +0100 Subject: [PATCH 3/4] Add specs for post action guardian --- lib/email/receiver.rb | 2 +- lib/post_action_creator.rb | 2 +- spec/components/email/receiver_spec.rb | 8 ++++++++ spec/components/post_action_creator_spec.rb | 22 +++++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 spec/components/post_action_creator_spec.rb diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index a8881a31ec6..bb2ad455ac0 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -247,7 +247,7 @@ module Email def create_post_action(email_log, type) PostActionCreator.new(email_log.user, email_log.post).perform(type) - rescue PostAction::AlreadyActed => e + rescue Discourse::InvalidAccess, PostAction::AlreadyActed => e raise InvalidPostAction.new(e) end diff --git a/lib/post_action_creator.rb b/lib/post_action_creator.rb index 3d84b44d9f1..e995db1a298 100644 --- a/lib/post_action_creator.rb +++ b/lib/post_action_creator.rb @@ -7,7 +7,7 @@ class PostActionCreator end def perform(action) - guardian.ensure_post_can_act!(@post, action, taken_actions: PostAction.counts_for([@post], @user)[@post.id]) + guardian.ensure_post_can_act!(@post, action, taken_actions: PostAction.counts_for([@post].compact, @user)[@post.try(:id)]) PostAction.act(@user, @post, action) end diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index d5c20be381f..796ce440d4d 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -364,6 +364,14 @@ This is a link http://example.com" expect(PostAction.count).to eq before_count expect(replied_user_like).to be_present end + + it "does not allow unauthorized happiness" do + post.trash! + before_count = PostAction.count + expect { receiver.process }.to raise_error(Email::Receiver::InvalidPostAction) + expect(PostAction.count).to eq before_count + expect(replied_user_like).to_not be_present + end end describe "like.eml" do diff --git a/spec/components/post_action_creator_spec.rb b/spec/components/post_action_creator_spec.rb new file mode 100644 index 00000000000..0348aec6b82 --- /dev/null +++ b/spec/components/post_action_creator_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' +require 'post_action_creator' + +describe PostCreator do + let(:user) { Fabricate(:user) } + let(:post) { Fabricate(:post) } + let(:group) { Fabricate(:group) } + let(:like_type_id) { PostActionType.types[:like] } + + + describe 'perform' do + it 'creates a post action' do + expect { PostActionCreator.new(user, post).perform(like_type_id) }.to change { PostAction.count }.by(1) + expect(PostAction.find_by(user: user, post: post, post_action_type_id: like_type_id)).to be_present + end + + it 'does not create an invalid post action' do + expect { PostActionCreator.new(user, nil).perform(like_type_id) }.to raise_error(Discourse::InvalidAccess) + end + end + +end From b94c53c71cf422d32cdf8dc5166222137a15a0b7 Mon Sep 17 00:00:00 2001 From: James Kiesel <james.kiesel@gmail.com> Date: Wed, 30 Dec 2015 20:54:51 +0100 Subject: [PATCH 4/4] cleanup post action creator --- spec/components/post_action_creator_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/components/post_action_creator_spec.rb b/spec/components/post_action_creator_spec.rb index 0348aec6b82..3b577fa4043 100644 --- a/spec/components/post_action_creator_spec.rb +++ b/spec/components/post_action_creator_spec.rb @@ -1,10 +1,9 @@ require 'rails_helper' require 'post_action_creator' -describe PostCreator do +describe PostActionCreator do let(:user) { Fabricate(:user) } let(:post) { Fabricate(:post) } - let(:group) { Fabricate(:group) } let(:like_type_id) { PostActionType.types[:like] }