diff --git a/app/assets/javascripts/discourse/controllers/raw-email.js.es6 b/app/assets/javascripts/discourse/controllers/raw-email.js.es6 new file mode 100644 index 00000000000..01f637a7bec --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/raw-email.js.es6 @@ -0,0 +1,24 @@ +import ModalFunctionality from 'discourse/mixins/modal-functionality'; + +import ObjectController from 'discourse/controllers/object'; + +/** + This controller handles displaying of raw email + + @class RawEmailController + @extends ObjectController + @namespace Discourse + @uses ModalFunctionality + @module Discourse +**/ +export default ObjectController.extend(ModalFunctionality, { + raw_email: "", + + loadRawEmail: function(postId) { + var self = this; + Discourse.Post.loadRawEmail(postId).then(function (raw_email) { + self.set("raw_email", raw_email); + }); + } + +}); diff --git a/app/assets/javascripts/discourse/models/_post.js b/app/assets/javascripts/discourse/models/_post.js index 620baf40138..118afce2997 100644 --- a/app/assets/javascripts/discourse/models/_post.js +++ b/app/assets/javascripts/discourse/models/_post.js @@ -64,6 +64,10 @@ Discourse.Post = Discourse.Model.extend({ hasHistory: Em.computed.gt('version', 1), postElementId: Discourse.computed.fmt('post_number', 'post_%@'), + canViewRawEmail: function() { + return Discourse.User.currentProp('staff'); + }.property(), + bookmarkedChanged: function() { Discourse.Post.bookmark(this.get('id'), this.get('bookmarked')) .then(null, function (error) { @@ -486,6 +490,12 @@ Discourse.Post.reopenClass({ }); }, + loadRawEmail: function(postId) { + return Discourse.ajax("/posts/" + postId + "/raw-email").then(function (result) { + return result.raw_email; + }); + }, + load: function(postId) { return Discourse.ajax("/posts/" + postId + ".json").then(function (result) { return Discourse.Post.create(result); diff --git a/app/assets/javascripts/discourse/routes/topic_route.js b/app/assets/javascripts/discourse/routes/topic_route.js index a02a635bc67..462845ef71f 100644 --- a/app/assets/javascripts/discourse/routes/topic_route.js +++ b/app/assets/javascripts/discourse/routes/topic_route.js @@ -73,6 +73,11 @@ Discourse.TopicRoute = Discourse.Route.extend({ this.controllerFor('modal').set('modalClass', 'history-modal'); }, + showRawEmail: function(post) { + Discourse.Route.showModal(this, 'raw-email', post); + this.controllerFor('raw_email').loadRawEmail(post.get("id")); + }, + mergeTopic: function() { Discourse.Route.showModal(this, 'mergeTopic', this.modelFor('topic')); }, diff --git a/app/assets/javascripts/discourse/templates/modal/raw_email.hbs b/app/assets/javascripts/discourse/templates/modal/raw_email.hbs new file mode 100644 index 00000000000..63e9256d942 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/modal/raw_email.hbs @@ -0,0 +1,7 @@ + diff --git a/app/assets/javascripts/discourse/templates/post.hbs b/app/assets/javascripts/discourse/templates/post.hbs index f9bf8059de4..90f06f2917c 100644 --- a/app/assets/javascripts/discourse/templates/post.hbs +++ b/app/assets/javascripts/discourse/templates/post.hbs @@ -53,7 +53,11 @@
{{/if}} {{#if via_email}} -
+ {{#if canViewRawEmail}} +
+ {{else}} +
+ {{/if}} {{/if}}
diff --git a/app/assets/javascripts/discourse/views/raw-email.es6 b/app/assets/javascripts/discourse/views/raw-email.es6 new file mode 100644 index 00000000000..d529b1063b7 --- /dev/null +++ b/app/assets/javascripts/discourse/views/raw-email.es6 @@ -0,0 +1,9 @@ +export default Discourse.ModalBodyView.extend({ + templateName: 'modal/raw_email', + title: I18n.t('raw_email.title'), + + resizeModal: function(){ + var viewPortHeight = $(window).height(); + this.$(".modal-body").css("max-height", Math.floor(0.8 * viewPortHeight) + "px"); + }.on("didInsertElement") +}); diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 926264e0952..0626826bf3a 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -135,6 +135,9 @@ aside.quote { &.via-email { color: scale-color($primary, $lightness: 70%); } + &.raw-email { + cursor: pointer; + } } diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index e52b5f0fd5b..14fbc4acbf6 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -30,6 +30,12 @@ class PostsController < ApplicationController render json: {cooked: post.cooked} end + def raw_email + guardian.ensure_can_view_raw_email! + post = Post.find(params[:id].to_i) + render json: {raw_email: post.raw_email} + end + def short_link post = Post.find(params[:post_id].to_i) # Stuff the user in the request object, because that's what IncomingLink wants diff --git a/app/models/post.rb b/app/models/post.rb index 0d311af67d9..91c0de77ac2 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -606,6 +606,8 @@ end # version :integer default(1), not null # cook_method :integer default(1), not null # wiki :boolean default(FALSE), not null +# via_email :boolean default(FALSE), not null +# raw_email :text # baked_at :datetime # baked_version :integer # hidden_at :datetime diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 7fb27b02a38..87fb3c8713d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1384,6 +1384,10 @@ en: history: "History" changed_by: "by {{author}}" + raw_email: + title: "Raw Email" + not_available: "Not available!" + categories_list: "Categories List" filters: diff --git a/config/routes.rb b/config/routes.rb index 1bac1c7d187..9650af142b6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -416,6 +416,7 @@ Discourse::Application.routes.draw do get "/posts/:id/cooked" => "posts#cooked" get "/posts/:id/expand-embed" => "posts#expand_embed" get "/posts/:id/raw" => "posts#markdown_id" + get "/posts/:id/raw-email" => "posts#raw_email" get "raw/:topic_id(/:post_number)" => "posts#markdown_num" resources :invites do diff --git a/db/migrate/20141015060145_add_raw_email_to_posts.rb b/db/migrate/20141015060145_add_raw_email_to_posts.rb new file mode 100644 index 00000000000..2c3b89b6d64 --- /dev/null +++ b/db/migrate/20141015060145_add_raw_email_to_posts.rb @@ -0,0 +1,5 @@ +class AddRawEmailToPosts < ActiveRecord::Migration + def change + add_column :posts, :raw_email, :text + end +end diff --git a/lib/email/receiver.rb b/lib/email/receiver.rb index a007965130a..4ca8032cf21 100644 --- a/lib/email/receiver.rb +++ b/lib/email/receiver.rb @@ -245,6 +245,7 @@ module Email def create_post(user, options) # Mark the reply as incoming via email options[:via_email] = true + options[:raw_email] = @raw creator = PostCreator.new(user, options) post = creator.create diff --git a/lib/guardian/post_guardian.rb b/lib/guardian/post_guardian.rb index 4da4acf03d8..7eae1a89f3b 100644 --- a/lib/guardian/post_guardian.rb +++ b/lib/guardian/post_guardian.rb @@ -193,6 +193,10 @@ module PostGuardian is_staff? end + def can_view_raw_email? + is_staff? + end + def can_unhide?(post) post.try(:hidden) && is_staff? end diff --git a/lib/post_creator.rb b/lib/post_creator.rb index 2eb4d6c1b5a..ae1c6fc178f 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -223,7 +223,7 @@ class PostCreator reply_to_post_number: @opts[:reply_to_post_number]) # Attributes we pass through to the post instance if present - [:post_type, :no_bump, :cooking_options, :image_sizes, :acting_user, :invalidate_oneboxes, :cook_method, :via_email].each do |a| + [:post_type, :no_bump, :cooking_options, :image_sizes, :acting_user, :invalidate_oneboxes, :cook_method, :via_email, :raw_email].each do |a| post.send("#{a}=", @opts[a]) if @opts[a].present? end diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index c5e7c9c4fa3..f5484fa0bb5 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -146,6 +146,7 @@ Pleasure to have you here! topic.posts.count.should == (start_count + 1) created_post = topic.posts.last created_post.via_email.should == true + created_post.raw_email.should == fixture_file("emails/valid_reply.eml") created_post.cooked.strip.should == fixture_file("emails/valid_reply.cooked").strip end end diff --git a/spec/controllers/posts_controller_spec.rb b/spec/controllers/posts_controller_spec.rb index 04690e02390..dd28e3af048 100644 --- a/spec/controllers/posts_controller_spec.rb +++ b/spec/controllers/posts_controller_spec.rb @@ -68,6 +68,36 @@ describe PostsController do end end + describe 'raw_email' do + include_examples "action requires login", :get, :raw_email, id: 2 + + describe "when logged in" do + let(:user) {log_in} + let(:post) {Fabricate(:post, user: user, raw_email: 'email_content')} + + it "raises an error if the user doesn't have permission to view raw email" do + Guardian.any_instance.expects(:can_view_raw_email?).returns(false) + + xhr :get, :raw_email, id: post.id + + response.should be_forbidden + end + + it "can view raw email" do + Guardian.any_instance.expects(:can_view_raw_email?).returns(true) + + xhr :get, :raw_email, id: post.id + + response.should be_success + json = ::JSON.parse(response.body) + json.should be_present + json['raw_email'].should == 'email_content' + end + + end + + end + describe 'show' do include_examples 'finding and showing post' do let(:action) { :show }