diff --git a/app/controllers/user_actions_controller.rb b/app/controllers/user_actions_controller.rb index 8ada7a8d4b4..a6183bdd602 100644 --- a/app/controllers/user_actions_controller.rb +++ b/app/controllers/user_actions_controller.rb @@ -2,14 +2,22 @@ class UserActionsController < ApplicationController def index requires_parameters(:user_id) per_chunk = 60 - render json: UserAction.stream( + + opts = { user_id: params[:user_id].to_i, offset: params[:offset], limit: per_chunk, - action_types: (params[:filter] || "").split(","), + action_types: (params[:filter] || "").split(",").map(&:to_i), guardian: guardian, ignore_private_messages: params[:filter] ? false : true - ) + } + + if opts[:action_types] == [UserAction::GOT_PRIVATE_MESSAGE] || + opts[:action_types] == [UserAction::NEW_PRIVATE_MESSAGE] + render json: UserAction.private_message_stream(opts[:action_types][0], opts) + else + render json: UserAction.stream(opts) + end end def show diff --git a/app/models/user_action.rb b/app/models/user_action.rb index 416c6a08aec..1232bc0f84a 100644 --- a/app/models/user_action.rb +++ b/app/models/user_action.rb @@ -131,6 +131,56 @@ LEFT JOIN categories c on c.id = t.category_id data end + # slightly different to standard stream, it collapses replies + def self.private_message_stream(action_type, opts) + + user_id = opts[:user_id] + return [] unless opts[:guardian].can_see_private_messages?(user_id) + + builder = SqlBuilder.new(" +SELECT + t.title, :action_type action_type, p.created_at, t.id topic_id, + :user_id AS target_user_id, au.name AS target_name, au.username AS target_username, + coalesce(p.post_number, 1) post_number, + p.reply_to_post_number, + pu.email ,pu.username, pu.name, pu.id user_id, + pu.email acting_email, pu.username acting_username, pu.name acting_name, pu.id acting_user_id, + p.cooked + +FROM topics t +JOIN posts p ON p.topic_id = t.id and p.post_number = t.highest_post_number +JOIN users pu ON pu.id = p.user_id +JOIN users au ON au.id = :user_id +WHERE archetype = 'private_message' and EXISTS ( + select 1 from user_actions a where a.user_id = :user_id and a.target_topic_id = t.id and action_type = :action_type) +ORDER BY p.created_at desc + +/*offset*/ +/*limit*/ +") + + builder.offset((opts[:offset] || 0).to_i) + builder.limit((opts[:limit] || 60).to_i) + + data = builder.exec(user_id: user_id, action_type: action_type).to_a + + data.each do |row| + row["action_type"] = row["action_type"].to_i + row["created_at"] = DateTime.parse(row["created_at"]) + # we should probably cache the excerpts in the db at some point + row["excerpt"] = PrettyText.excerpt(row["cooked"],300) if row["cooked"] + row["cooked"] = nil + row["avatar_template"] = User.avatar_template(row["email"]) + row["acting_avatar_template"] = User.avatar_template(row["acting_email"]) + row.delete("email") + row.delete("acting_email") + row["slug"] = Slug.for(row["title"]) + end + + data + + end + def self.log_action!(hash) require_parameters(hash, :action_type, :user_id, :acting_user_id, :target_topic_id, :target_post_id) transaction(requires_new: true) do diff --git a/config/environments/profile.rb b/config/environments/profile.rb index e261db93b6b..b250224c85b 100644 --- a/config/environments/profile.rb +++ b/config/environments/profile.rb @@ -37,7 +37,7 @@ Discourse::Application.configure do config.handlebars.precompile = true # this setting enable rack_cache so it caches various requests in redis - config.enable_rack_cache = true + # config.enable_rack_cache = true # allows users to use mini profiler config.enable_mini_profiler = false diff --git a/lib/post_creator.rb b/lib/post_creator.rb index 90402693845..7541a90b24e 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -6,6 +6,10 @@ class PostCreator attr_reader :errors, :opts + def self.create(user,opts) + self.new(user,opts).create + end + # Acceptable options: # # raw - raw text of post @@ -14,6 +18,7 @@ class PostCreator # acting_user - The user performing the action might be different than the user # who is the post "author." For example when copying posts to a new # topic. + # created_at - Post creation time (optional) # # When replying to a topic: # topic_id - topic we're replying to diff --git a/spec/models/user_action_spec.rb b/spec/models/user_action_spec.rb index 802f2b11102..1b9c26d7700 100644 --- a/spec/models/user_action_spec.rb +++ b/spec/models/user_action_spec.rb @@ -206,4 +206,55 @@ describe UserAction do @user.user_actions.where(action_type: UserAction::BOOKMARK).first.should be_nil end end + + + describe 'private messages' do + + let(:user) do + Fabricate(:user) + end + + let(:target_user) do + Fabricate(:user) + end + + let(:private_message) do + PostCreator.create( user, + raw: 'this is a private message', + title: 'this is the pm title', + target_usernames: target_user.username, + archetype: Archetype::private_message + ) + end + + let!(:response) do + PostCreator.create(user, raw: 'oops I forgot to mention this', topic_id: private_message.topic_id) + end + + let!(:private_message2) do + PostCreator.create( target_user, + raw: 'this is a private message', + title: 'this is the pm title', + target_usernames: user.username, + archetype: Archetype::private_message + ) + end + + it 'should collapse the inbox correctly' do + + stream = UserAction.private_message_stream(UserAction::GOT_PRIVATE_MESSAGE, user_id: target_user.id, guardian: Guardian.new(target_user)) + # inbox should collapse this initial and reply message into one item + stream.count.should == 1 + + + # outbox should also collapse + stream = UserAction.private_message_stream(UserAction::NEW_PRIVATE_MESSAGE, user_id: user.id, guardian: Guardian.new(user)) + stream.count.should == 1 + + # anon should see nothing + stream = UserAction.private_message_stream(UserAction::NEW_PRIVATE_MESSAGE, user_id: user.id, guardian: Guardian.new(nil)) + stream.count.should == 0 + + end + end end