From 6843e2f742d9908718c60e2fc3712c730b821c86 Mon Sep 17 00:00:00 2001 From: Naman Gupta <01namangupta@gmail.com> Date: Wed, 4 Jul 2018 01:54:50 +0530 Subject: [PATCH] incoming email parsing feature for gmail and yahoo (#2933) * Added reply to content field in comment table * Added incoming email parsing feature for gmail and yahooo * Added incoming email parsing feature for gmail and yahooo * Minor changes * Removed column * Added filter in comment * Added mail filter in mails * Minor changes * Fixes codeclimate issues * Modified COMMENT_FILTER * Added test for parsing gmail and yahoo * Added detail readme for yahoo and gmail parsing --- app/helpers/application_helper.rb | 15 +++ app/mailers/comment_mailer.rb | 1 - app/models/comment.rb | 83 ++++++++++++-- app/models/concerns/comments_shared.rb | 5 + app/views/notes/_comment.html.erb | 10 +- test/fixtures/drupal_users.yml | 14 +++ test/fixtures/users.yml | 26 +++++ .../gmail/final_parsed_comment.txt | 11 ++ .../gmail/incoming_gmail_email.eml | 107 ++++++++++++++++++ .../gmail/incoming_gmail_email.html | 15 +++ test/incoming_test_emails/gmail/readme.md | 9 ++ .../yahoo/final_parsed_comment.txt | 10 ++ .../yahoo/incoming_yahoo_email.eml | 79 +++++++++++++ .../yahoo/incoming_yahoo_mail.html | 22 ++++ test/incoming_test_emails/yahoo/readme.md | 9 ++ test/unit/comment_test.rb | 25 +++- 16 files changed, 426 insertions(+), 15 deletions(-) create mode 100644 test/incoming_test_emails/gmail/final_parsed_comment.txt create mode 100644 test/incoming_test_emails/gmail/incoming_gmail_email.eml create mode 100644 test/incoming_test_emails/gmail/incoming_gmail_email.html create mode 100644 test/incoming_test_emails/gmail/readme.md create mode 100644 test/incoming_test_emails/yahoo/final_parsed_comment.txt create mode 100644 test/incoming_test_emails/yahoo/incoming_yahoo_email.eml create mode 100644 test/incoming_test_emails/yahoo/incoming_yahoo_mail.html create mode 100644 test/incoming_test_emails/yahoo/readme.md diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 8d0a6d816f4..ce044164183 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -114,4 +114,19 @@ def title_suggestion(comment) output end end + + def filtered_comment_body(comment_body) + if contain_trimmed_body?(comment_body) + return comment_body.split(Comment::COMMENT_FILTER).first + end + comment_body + end + + def contain_trimmed_body?(comment_body) + comment_body.include?(Comment::COMMENT_FILTER) + end + + def trimmed_body(comment_body) + comment_body.split(Comment::COMMENT_FILTER).second + end end diff --git a/app/mailers/comment_mailer.rb b/app/mailers/comment_mailer.rb index dacfb55fcc7..add90ab5d56 100644 --- a/app/mailers/comment_mailer.rb +++ b/app/mailers/comment_mailer.rb @@ -1,6 +1,5 @@ class CommentMailer < ActionMailer::Base helper :application - require 'byebug' include ApplicationHelper default from: "notifications@#{ActionMailer::Base.default_url_options[:host]}" diff --git a/app/models/comment.rb b/app/models/comment.rb index 565305a6eb1..9ab34c6f47c 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -13,6 +13,8 @@ class Comment < ApplicationRecord self.table_name = 'comments' self.primary_key = 'cid' + COMMENT_FILTER = "".freeze + def self.inheritance_column 'rails_type' end @@ -220,22 +222,79 @@ def user_reactions_map user_like_map end - def self.receive_mail(message) - node_id = message.subject[/#([\d]+)/, 1] #This took out the node ID from the subject line - puts node_id - unless node_id.nil? - node = Node.where(nid: node_id) - if node.any? - node = node.first - user = User.find_by(email: message.from.first) - if user.present? && node_id.present? - message_markdown = ReverseMarkdown.convert message.html_part.body.decoded - message_id = message.message_id - comment = node.add_comment(uid: user.uid, body: message_markdown, comment_via: 1, message_id: message_id) + def self.receive_mail(mail) + user = User.where(email: mail.from.first).first + if user + node_id = mail.subject[/#([\d]+)/, 1] #This took out the node ID from the subject line + unless node_id.nil? + node = Node.where(nid: node_id).first + if node + mail_doc = Nokogiri::HTML(mail.html_part.body.decoded) # To parse the mail to extract comment content and reply content + domain = get_domain mail.from.first + if domain == "gmail" + content = gmail_parsed_mail mail_doc + elsif domain == "yahoo" + content = yahoo_parsed_mail mail_doc + else + content = { + "comment_content" => mail_doc, + "extra_content" => nil + } + end + + if content["extra_content"].nil? + comment_content_markdown = ReverseMarkdown.convert content["comment_content"] + else + extra_content_markdown = ReverseMarkdown.convert content["extra_content"] + comment_content_markdown = ReverseMarkdown.convert content["comment_content"] + comment_content_markdown = comment_content_markdown + COMMENT_FILTER + extra_content_markdown + end + message_id = mail.message_id + comment = node.add_comment(uid: user.uid, body: comment_content_markdown, comment_via: 1, message_id: message_id) comment.notify user end end end end + def self.get_domain(email) + domain = email[/(?<=@)[^.]+(?=\.)/, 0] + end + + def self.yahoo_parsed_mail(mail_doc) + if mail_doc.css(".yahoo_quoted") + extra_content = mail_doc.css(".yahoo_quoted")[0] + mail_doc.css(".yahoo_quoted")[0].remove + comment_content = mail_doc + else + comment_content = mail_doc + extra_content = nil + end + + { + "comment_content" => comment_content, + "extra_content" => extra_content + } + end + + def self.gmail_parsed_mail(mail_doc) + if mail_doc.css(".gmail_quote").any? + extra_content = mail_doc.css(".gmail_quote")[0] + mail_doc.css(".gmail_quote")[0].remove + comment_content = mail_doc + else + comment_content = mail_doc + extra_content = nil + end + + { + "comment_content" => comment_content, + "extra_content" => extra_content + } + end + + def trimmed_content? + comment.include?(COMMENT_FILTER) + end + end diff --git a/app/models/concerns/comments_shared.rb b/app/models/concerns/comments_shared.rb index 422ffe05183..9147782480c 100644 --- a/app/models/concerns/comments_shared.rb +++ b/app/models/concerns/comments_shared.rb @@ -2,10 +2,15 @@ # Refer to this link: http://stackoverflow.com/questions/14541823/how-to-use-concerns-in-rails-4 module CommentsShared extend ActiveSupport::Concern + include ApplicationHelper # filtered version additionally appending http/https # protocol to protocol-relative URLslike "/foo" def body_email(host = 'publiclab.org') + if contain_trimmed_body?(body) + comment_body = filtered_comment_body(body) + return comment_body.gsub(/([\s|"|'|\[|\(])(\/\/)([\w]?\.?#{host})/, '\1https://\3') + end body.gsub(/([\s|"|'|\[|\(])(\/\/)([\w]?\.?#{host})/, '\1https://\3') end diff --git a/app/views/notes/_comment.html.erb b/app/views/notes/_comment.html.erb index 334e6d32976..c5b7e6d3b1b 100644 --- a/app/views/notes/_comment.html.erb +++ b/app/views/notes/_comment.html.erb @@ -106,7 +106,15 @@
<%= raw render_comment_body(comment) %>
+ + <% comment_body = render_comment_body(comment) %> +<%= raw filtered_comment_body(comment_body) %>
+ + <% if contain_trimmed_body?(comment_body) %> + ... +Is this a question? Click here to post it to the Questions page.
diff --git a/test/fixtures/drupal_users.yml b/test/fixtures/drupal_users.yml index 14e721ead47..20bc6f64c63 100644 --- a/test/fixtures/drupal_users.yml +++ b/test/fixtures/drupal_users.yml @@ -74,3 +74,17 @@ legacy_user: status: 1 mail: legacy@publiclab.org created: <%= Time.now.to_i %> + +gmail_test: + name: namangupta + mail: 01namangupta@gmail.com + uid: 12 + status: 1 + created: <%= Time.now.to_i %> + +naman18996: + name: naman18996 + mail: naman18996@yahoo.com + uid: 13 + status: 1 + created: <%= Time.now.to_i %> diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 9ff2a4ad5ba..74c57c27350 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -132,3 +132,29 @@ test_user: bio: '' created_at: <%= Time.now %> updated_at: <%= Time.now %> + +naman: + username: namangupta + status: 1 + email: 01namangupta@gmail.com + id: 12 + last_request_at: <%= Time.now %> + password_salt: <%= salt = Authlogic::Random.hex_token %> + crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt("secretive" + salt) %> + persistence_token: <%= Authlogic::Random.hex_token %> + bio: '' + created_at: <%= Time.now %> + updated_at: <%= Time.now %> + +naman18996: + username: naman18996 + status: 1 + email: naman18996@yahoo.com + id: 13 + last_request_at: <%= Time.now %> + password_salt: <%= salt = Authlogic::Random.hex_token %> + crypted_password: <%= Authlogic::CryptoProviders::Sha512.encrypt("secretive" + salt) %> + persistence_token: <%= Authlogic::Random.hex_token %> + bio: '' + created_at: <%= Time.now %> + updated_at: <%= Time.now %> diff --git a/test/incoming_test_emails/gmail/final_parsed_comment.txt b/test/incoming_test_emails/gmail/final_parsed_comment.txt new file mode 100644 index 00000000000..1c5f2c8eb69 --- /dev/null +++ b/test/incoming_test_emails/gmail/final_parsed_comment.txt @@ -0,0 +1,11 @@ +This is another reply by email comment + +On Tue, Jul 3, 2018 at 11:17 PM Naman Gupta \<[01namangupta@gmail.com](mailto:01namangupta@gmail.com)\> wrote: + +> This is reply by comment +> +> +> On Tue, Jul 3, 2018 at 11:13 PM Rails Projects \<[railsprojects2018@gmail.com](mailto:railsprojects2018@gmail.com)\> wrote: +> +> > This is a comment sent to the user by publiclab. + diff --git a/test/incoming_test_emails/gmail/incoming_gmail_email.eml b/test/incoming_test_emails/gmail/incoming_gmail_email.eml new file mode 100644 index 00000000000..a2e496be5be --- /dev/null +++ b/test/incoming_test_emails/gmail/incoming_gmail_email.eml @@ -0,0 +1,107 @@ +Delivered-To: railsprojects2018@gmail.com +Received: by 2002:a1c:924f:0:0:0:0:0 with SMTP id u76-v6csp1316358wmd; + Tue, 3 Jul 2018 10:48:13 -0700 (PDT) +X-Received: by 2002:a50:e615:: with SMTP id y21-v6mr29798400edm.278.1530640093065; + Tue, 03 Jul 2018 10:48:13 -0700 (PDT) +ARC-Seal: i=1; a=rsa-sha256; t=1530640093; cv=none; + d=google.com; s=arc-20160816; + b=iwlu7+0DRR8CFpRnB6GQ1MSWcjrLdSomGi3xKTijlKdmBbwQrxmMpX6SNnzskE3xVC + SiylMtj5yTcxWmWTuKuOKLbprkSobBQ1vu+xRV1J7S28a/1nYOKEipCQKh3bgLl7lIqr + vRCnNZqt+afuol0O+97HmZAp3yYBmUSL6ArW+G5mId1Zxc25uV037xJeA/mKyr7FccW9 + D6W86z9XjMzlBUWB2k3V0vbsVJhBgxXxq22VJWx2ZmK4fTiyNsBqqjfjLyGFGdMVy/e6 + 9jvl66h3XmhJp49kWbWSlFk1RKGTXvDZJ4ZhwnBZ6wqUYtrXmwg85ibmdXxDCvYANvkc + JUbw== +ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; + h=to:subject:message-id:date:from:in-reply-to:references:mime-version + :dkim-signature:arc-authentication-results; + bh=RYGhy7yx79U1IqJDo1X6kis0HCj0a5eCbuu3JzStGEU=; + b=a3X4+9aFlZEKknmilS9b18oXGSTJxvMhh/nIqhFIL1fxYIdE7XCXY+TTLwrjTkWIo5 + XaghwYmv8vCedU2v0KfojMGaN6fkZXqXr+lcsYpRJqSUALoaYhJlAOl/bL54PzXewLZ6 + 5xrraJMyDdo/xBqd6P12Cndza5il6/kpiSHPdoGb/4F/zQOQ15ta0n8veXAGFTk3k4Yk + T9MrzB0ogcaFDYlJtPFRCHz4YenzAN3JZ0hmxwLnO7f0DfGvCFi35fAOFpxCCCzd4KzG + vhMcuS/LPCQNPUbN8NGRfSHAULgGtFNGL7PmG6FKFY+iPD10AL/zIFOlHoiLsJucgNE+ + hmpw== +ARC-Authentication-Results: i=1; mx.google.com; + dkim=pass header.i=@gmail.com header.s=20161025 header.b=plagx6JT; + spf=pass (google.com: domain of 01namangupta@gmail.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=01namangupta@gmail.com; + dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com +Return-Path: <01namangupta@gmail.com> +Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) + by mx.google.com with SMTPS id k17-v6sor1127557edr.39.2018.07.03.10.48.13 + forThis i= +s reply by comment+On = +Tue, Jul 3, 2018 at 11:13 PM Rails Projects <railsprojects2018@gmail.com> w= +rote:This is a co= +mment sent to the user by publiclab.+
++This is reply by comment+
+++On Tue, Jul 3, 2018 at 11:13 PM Rails Projects <railsprojects2018@gmail.com> wrote:+++This is a comment sent to the user by publiclab.+