diff --git a/app/controllers/list_controller.rb b/app/controllers/list_controller.rb index 890e2871d5e..10e14423c81 100644 --- a/app/controllers/list_controller.rb +++ b/app/controllers/list_controller.rb @@ -260,7 +260,7 @@ class ListController < ApplicationController min_posts: params[:min_posts], max_posts: params[:max_posts], status: params[:status], - bookmarked: params[:bookmarked].present?, + filter: params[:filter], state: params[:state], search: params[:search] } diff --git a/app/models/post_action.rb b/app/models/post_action.rb index 4314da7e0e0..1ec92a8c1e1 100644 --- a/app/models/post_action.rb +++ b/app/models/post_action.rb @@ -80,6 +80,23 @@ class PostAction < ActiveRecord::Base user_actions end + def self.lookup_for(user, topics, post_action_type_id) + return if topics.blank? + + map = {} + PostAction.where(user_id: user.id, post_action_type_id: post_action_type_id, deleted_at: nil) + .references(:post) + .includes(:post) + .where('posts.topic_id in (?)', topics.map(&:id)) + .order('posts.topic_id, posts.post_number') + .pluck('posts.topic_id, posts.post_number') + .each do |topic_id, post_number| + (map[topic_id] ||= []) << post_number + end + + map + end + def self.active_flags_counts_for(collection) return {} if collection.blank? diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb index 20d438fc4bf..5fb0206a4e5 100644 --- a/app/models/topic_list.rb +++ b/app/models/topic_list.rb @@ -46,6 +46,20 @@ class TopicList # Attach some data for serialization to each topic @topic_lookup = TopicUser.lookup_for(@current_user, @topics) if @current_user.present? + post_action_type = + if @current_user.present? + if @opts[:filter].present? + if @opts[:filter] == "bookmarked" + PostActionType.types[:bookmark] + elsif @opts[:filter] == "liked" + PostActionType.types[:like] + end + end + end + + # Data for bookmarks or likes + post_action_lookup = PostAction.lookup_for(@current_user, @topics, post_action_type) if post_action_type + # Create a lookup for all the user ids we need user_ids = [] @topics.each do |ft| @@ -56,6 +70,11 @@ class TopicList @topics.each do |ft| ft.user_data = @topic_lookup[ft.id] if @topic_lookup.present? + + if ft.user_data && post_action_lookup && actions = post_action_lookup[ft.id] + ft.user_data.post_action_data = {post_action_type => actions} + end + ft.posters = ft.posters_summary(avatar_lookup: avatar_lookup) ft.participants = ft.participants_summary(avatar_lookup: avatar_lookup, user: @current_user) ft.topic_list = self diff --git a/app/models/topic_user.rb b/app/models/topic_user.rb index 7996f1f0f38..80174ac6309 100644 --- a/app/models/topic_user.rb +++ b/app/models/topic_user.rb @@ -2,6 +2,9 @@ class TopicUser < ActiveRecord::Base belongs_to :user belongs_to :topic + # used for serialization + attr_accessor :post_action_data + scope :tracking, lambda { |topic_id| where(topic_id: topic_id) .where("COALESCE(topic_users.notification_level, :regular) >= :tracking", diff --git a/app/serializers/topic_list_item_serializer.rb b/app/serializers/topic_list_item_serializer.rb index c22560d8b09..dd0f66be00c 100644 --- a/app/serializers/topic_list_item_serializer.rb +++ b/app/serializers/topic_list_item_serializer.rb @@ -7,7 +7,8 @@ class TopicListItemSerializer < ListableTopicSerializer :last_poster_username, :category_id, :op_like_count, - :pinned_globally + :pinned_globally, + :bookmarked_post_numbers has_many :posters, serializer: TopicPosterSerializer, embed: :objects has_many :participants, serializer: TopicPosterSerializer, embed: :objects @@ -28,6 +29,16 @@ class TopicListItemSerializer < ListableTopicSerializer object.participants_summary || [] end + def include_bookmarked_post_numbers? + object.user_data && + object.user_data.post_action_data && + object.user_data.post_action_data.key?(PostActionType.types[:bookmark]) + end + + def bookmarked_post_numbers + object.user_data.post_action_data[PostActionType.types[:bookmark]] + end + def include_participants? object.private_message? end diff --git a/lib/topic_query.rb b/lib/topic_query.rb index ccb87692739..fa8f89ce042 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -26,7 +26,7 @@ class TopicQuery state search slow_platform - bookmarked + filter ).map(&:to_sym) # Maps `order` to a columns in `topics` @@ -311,16 +311,24 @@ class TopicQuery end end - if options[:bookmarked] && @user - result = result.where('topics.id IN (SELECT pp.topic_id + if (filter=options[:filter]) && @user + action = + if filter == "bookmarked" + PostActionType.types[:bookmark] + elsif filter == "liked" + PostActionType.types[:like] + end + if action + result = result.where('topics.id IN (SELECT pp.topic_id FROM post_actions pa JOIN posts pp ON pp.id = pa.post_id WHERE pa.user_id = :user_id AND - pa.post_action_type_id = :bookmarked AND + pa.post_action_type_id = :action AND pa.deleted_at IS NULL )', user_id: @user.id, - bookmarked: PostActionType.types[:bookmark] + action: action ) + end end result = result.where('topics.deleted_at IS NULL') if require_deleted_clause diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index 55070d6d33e..74215acf3a5 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -40,9 +40,28 @@ describe TopicQuery do end + context 'bookmarks' do + it "filters and returns bookmarks correctly" do + post = Fabricate(:post) + reply = Fabricate(:post, topic_id: post.topic_id) + + post2 = Fabricate(:post) + + PostAction.act(user, post, PostActionType.types[:bookmark]) + PostAction.act(user, reply, PostActionType.types[:bookmark]) + TopicUser.change(user, post.topic, notification_level: 1) + TopicUser.change(user, post2.topic, notification_level: 1) + + query = TopicQuery.new(user, filter: 'bookmarked').list_latest + + query.topics.length.should == 1 + query.topics.first.user_data.post_action_data.should == {PostActionType.types[:bookmark] => [1,2]} + end + end + context 'deleted filter' do it "filters deleted topics correctly" do - topic = Fabricate(:topic, deleted_at: 1.year.ago) + _topic = Fabricate(:topic, deleted_at: 1.year.ago) TopicQuery.new(admin, status: 'deleted').list_latest.topics.size.should == 1 TopicQuery.new(moderator, status: 'deleted').list_latest.topics.size.should == 1