mirror of
https://github.com/codeninjasllc/discourse.git
synced 2025-02-17 04:01:29 -05:00
Work in progress, full page search
This commit is contained in:
parent
b3e583faf3
commit
41e427bd2e
15 changed files with 108 additions and 18 deletions
|
@ -7,7 +7,8 @@ export var queryParams = {
|
||||||
status: { replace: true },
|
status: { replace: true },
|
||||||
state: { replace: true },
|
state: { replace: true },
|
||||||
search: { replace: true },
|
search: { replace: true },
|
||||||
max_posts: { replace: true }
|
max_posts: { replace: true },
|
||||||
|
q: { replace: true }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Basic controller options
|
// Basic controller options
|
||||||
|
|
|
@ -16,6 +16,8 @@ var controllerOpts = {
|
||||||
expandGloballyPinned: false,
|
expandGloballyPinned: false,
|
||||||
expandAllPinned: false,
|
expandAllPinned: false,
|
||||||
|
|
||||||
|
isSearch: Em.computed.equal('model.filter', 'search'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
|
|
||||||
changeSort: function(sortBy) {
|
changeSort: function(sortBy) {
|
||||||
|
|
|
@ -13,13 +13,13 @@ export default DiscourseController.extend({
|
||||||
|
|
||||||
isSearch: Em.computed.equal('filterMode', 'search'),
|
isSearch: Em.computed.equal('filterMode', 'search'),
|
||||||
|
|
||||||
searchTerm: Em.computed.alias('controllers.discovery/topics.model.params.search'),
|
searchTerm: Em.computed.alias('controllers.discovery/topics.model.params.q'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
search: function(){
|
search: function(){
|
||||||
var discovery = this.get('controllers.discovery/topics');
|
var discovery = this.get('controllers.discovery/topics');
|
||||||
var model = discovery.get('model');
|
var model = discovery.get('model');
|
||||||
discovery.set('search', this.get("searchTerm"));
|
discovery.set('q', this.get("searchTerm"));
|
||||||
model.refreshSort();
|
model.refreshSort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,5 +2,6 @@ import registerUnbound from 'discourse/helpers/register-unbound';
|
||||||
|
|
||||||
registerUnbound('topic-link', function(topic) {
|
registerUnbound('topic-link', function(topic) {
|
||||||
var title = topic.get('fancyTitle');
|
var title = topic.get('fancyTitle');
|
||||||
return new Handlebars.SafeString("<a href='" + topic.get('lastUnreadUrl') + "' class='title'>" + title + "</a>");
|
var url = topic.linked_post_number ? topic.urlForPostNumber(topic.linked_post_number) : topic.get('lastUnreadUrl');
|
||||||
|
return new Handlebars.SafeString("<a href='" + url + "' class='title'>" + title + "</a>");
|
||||||
});
|
});
|
||||||
|
|
|
@ -40,8 +40,8 @@ const TopicList = RestModel.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshSort: function(order, ascending) {
|
refreshSort: function(order, ascending) {
|
||||||
const self = this,
|
const self = this;
|
||||||
params = this.get('params') || {};
|
var params = this.get('params') || {};
|
||||||
|
|
||||||
params.order = order || params.order;
|
params.order = order || params.order;
|
||||||
|
|
||||||
|
@ -51,6 +51,11 @@ const TopicList = RestModel.extend({
|
||||||
params.ascending = ascending;
|
params.ascending = ascending;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.q) {
|
||||||
|
// search is unique, nothing else allowed with it
|
||||||
|
params = {q: params.q};
|
||||||
|
}
|
||||||
|
|
||||||
this.set('loaded', false);
|
this.set('loaded', false);
|
||||||
const store = this.store;
|
const store = this.store;
|
||||||
store.findFiltered('topicList', {filter: this.get('filter'), params}).then(function(tl) {
|
store.findFiltered('topicList', {filter: this.get('filter'), params}).then(function(tl) {
|
||||||
|
|
|
@ -363,8 +363,7 @@ const Topic = RestModel.extend({
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
excerptNotEmpty: Em.computed.notEmpty('excerpt'),
|
hasExcerpt: Em.computed.notEmpty('excerpt'),
|
||||||
hasExcerpt: Em.computed.and('pinned', 'excerptNotEmpty'),
|
|
||||||
|
|
||||||
excerptTruncated: function() {
|
excerptTruncated: function() {
|
||||||
const e = this.get('excerpt');
|
const e = this.get('excerpt');
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
{{topic-list
|
{{topic-list
|
||||||
showParticipants=showParticipants
|
showParticipants=showParticipants
|
||||||
hideCategory=hideCategory
|
hideCategory=hideCategory
|
||||||
topics=topics}}
|
topics=topics
|
||||||
|
expandExcerpts=expandExcerpts
|
||||||
|
}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class='alert alert-info'>
|
<div class='alert alert-info'>
|
||||||
{{i18n 'choose_topic.none_found'}}
|
{{i18n 'choose_topic.none_found'}}
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
selected=selected
|
selected=selected
|
||||||
expandGloballyPinned=expandGloballyPinned
|
expandGloballyPinned=expandGloballyPinned
|
||||||
expandAllPinned=expandAllPinned
|
expandAllPinned=expandAllPinned
|
||||||
|
expandExcerpts=isSearch
|
||||||
topics=model.topics}}
|
topics=model.topics}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -65,6 +65,10 @@ export default Discourse.View.extend(StringBuffer, {
|
||||||
},
|
},
|
||||||
|
|
||||||
expandPinned: function() {
|
expandPinned: function() {
|
||||||
|
if (this.get('controller.expandExcerpts')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const pinned = this.get('topic.pinned');
|
const pinned = this.get('topic.pinned');
|
||||||
if (!pinned) {
|
if (!pinned) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -248,7 +248,8 @@ class ListController < ApplicationController
|
||||||
status: params[:status],
|
status: params[:status],
|
||||||
filter: params[:filter],
|
filter: params[:filter],
|
||||||
state: params[:state],
|
state: params[:state],
|
||||||
search: params[:search]
|
search: params[:search],
|
||||||
|
q: params[:q]
|
||||||
}
|
}
|
||||||
options[:no_subcategories] = true if params[:no_subcategories] == 'true'
|
options[:no_subcategories] = true if params[:no_subcategories] == 'true'
|
||||||
options[:slow_platform] = true if slow_platform?
|
options[:slow_platform] = true if slow_platform?
|
||||||
|
|
|
@ -106,7 +106,9 @@ class Topic < ActiveRecord::Base
|
||||||
has_one :first_post, -> {where post_number: 1}, class_name: Post
|
has_one :first_post, -> {where post_number: 1}, class_name: Post
|
||||||
|
|
||||||
# When we want to temporarily attach some data to a forum topic (usually before serialization)
|
# When we want to temporarily attach some data to a forum topic (usually before serialization)
|
||||||
|
attr_accessor :search_data
|
||||||
attr_accessor :user_data
|
attr_accessor :user_data
|
||||||
|
|
||||||
attr_accessor :posters # TODO: can replace with posters_summary once we remove old list code
|
attr_accessor :posters # TODO: can replace with posters_summary once we remove old list code
|
||||||
attr_accessor :participants
|
attr_accessor :participants
|
||||||
attr_accessor :topic_list
|
attr_accessor :topic_list
|
||||||
|
|
|
@ -11,6 +11,7 @@ class ListableTopicSerializer < BasicTopicSerializer
|
||||||
:bumped_at,
|
:bumped_at,
|
||||||
:unseen,
|
:unseen,
|
||||||
:last_read_post_number,
|
:last_read_post_number,
|
||||||
|
:linked_post_number,
|
||||||
:unread,
|
:unread,
|
||||||
:new_posts,
|
:new_posts,
|
||||||
:pinned,
|
:pinned,
|
||||||
|
@ -77,6 +78,22 @@ class ListableTopicSerializer < BasicTopicSerializer
|
||||||
!!object.user_data
|
!!object.user_data
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def excerpt
|
||||||
|
if object.search_data
|
||||||
|
object.search_data[:excerpt]
|
||||||
|
else
|
||||||
|
object.excerpt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def include_linked_post_number?
|
||||||
|
object.search_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def linked_post_number
|
||||||
|
object.search_data[:post_number]
|
||||||
|
end
|
||||||
|
|
||||||
alias :include_last_read_post_number? :has_user_data
|
alias :include_last_read_post_number? :has_user_data
|
||||||
|
|
||||||
def unread
|
def unread
|
||||||
|
@ -90,7 +107,7 @@ class ListableTopicSerializer < BasicTopicSerializer
|
||||||
alias :include_new_posts? :has_user_data
|
alias :include_new_posts? :has_user_data
|
||||||
|
|
||||||
def include_excerpt?
|
def include_excerpt?
|
||||||
pinned
|
pinned || object.search_data
|
||||||
end
|
end
|
||||||
|
|
||||||
def pinned
|
def pinned
|
||||||
|
|
|
@ -452,10 +452,6 @@ class Search
|
||||||
# double wrapping so we get correct row numbers
|
# double wrapping so we get correct row numbers
|
||||||
post_sql = "SELECT *, row_number() over() row_number FROM (#{post_sql}) xxx"
|
post_sql = "SELECT *, row_number() over() row_number FROM (#{post_sql}) xxx"
|
||||||
|
|
||||||
# p Topic.exec_sql(post_sql).to_a
|
|
||||||
# puts post_sql
|
|
||||||
# p Topic.exec_sql("SELECT topic_id FROM topic_allowed_users WHERE user_id = 2").to_a
|
|
||||||
|
|
||||||
posts = Post.includes(:topic => :category)
|
posts = Post.includes(:topic => :category)
|
||||||
.joins("JOIN (#{post_sql}) x ON x.id = posts.topic_id AND x.post_number = posts.post_number")
|
.joins("JOIN (#{post_sql}) x ON x.id = posts.topic_id AND x.post_number = posts.post_number")
|
||||||
.order('row_number')
|
.order('row_number')
|
||||||
|
|
|
@ -27,6 +27,7 @@ class TopicQuery
|
||||||
search
|
search
|
||||||
slow_platform
|
slow_platform
|
||||||
filter
|
filter
|
||||||
|
q
|
||||||
).map(&:to_sym)
|
).map(&:to_sym)
|
||||||
|
|
||||||
# Maps `order` to a columns in `topics`
|
# Maps `order` to a columns in `topics`
|
||||||
|
@ -71,7 +72,47 @@ class TopicQuery
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_search
|
def list_search
|
||||||
create_list(:latest, {}, latest_results)
|
|
||||||
|
results = nil
|
||||||
|
|
||||||
|
if @options[:q].present?
|
||||||
|
search = Search.execute(@options[:q],
|
||||||
|
type_filter: 'topic',
|
||||||
|
guardian: Guardian.new(@user))
|
||||||
|
|
||||||
|
topic_ids = search.posts.map(&:topic_id)
|
||||||
|
|
||||||
|
if topic_ids.present?
|
||||||
|
sql = topic_ids.each_with_index.map do |id, idx|
|
||||||
|
"SELECT #{idx} pos, #{id} id"
|
||||||
|
end.join(" UNION ALL ")
|
||||||
|
|
||||||
|
results = Topic
|
||||||
|
.unscoped
|
||||||
|
.joins("JOIN (#{sql}) X on X.id = topics.id")
|
||||||
|
.order("X.pos")
|
||||||
|
|
||||||
|
posts_map = Hash[*search.posts.map{|p| [p.topic_id, p]}.flatten]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
results ||= Topic.where("1=0")
|
||||||
|
|
||||||
|
if @user
|
||||||
|
results = results.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{@user.id.to_i})")
|
||||||
|
.references('tu')
|
||||||
|
end
|
||||||
|
|
||||||
|
list = create_list(:latest, {unordered: true}, results)
|
||||||
|
|
||||||
|
|
||||||
|
list.topics.each do |topic|
|
||||||
|
if post = posts_map[topic.id]
|
||||||
|
topic.search_data = {excerpt: search.blurb(post), post_number: post.post_number}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
list
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_read
|
def list_read
|
||||||
|
|
|
@ -43,15 +43,33 @@ describe TopicQuery do
|
||||||
context "list_topics_by" do
|
context "list_topics_by" do
|
||||||
|
|
||||||
it "allows users to view their own invisible topics" do
|
it "allows users to view their own invisible topics" do
|
||||||
topic = Fabricate(:topic, user: user)
|
_topic = Fabricate(:topic, user: user)
|
||||||
invisible_topic = Fabricate(:topic, user: user, visible: false)
|
_invisible_topic = Fabricate(:topic, user: user, visible: false)
|
||||||
|
|
||||||
expect(TopicQuery.new(nil).list_topics_by(user).topics.count).to eq(1)
|
expect(TopicQuery.new(nil).list_topics_by(user).topics.count).to eq(1)
|
||||||
expect(TopicQuery.new(user).list_topics_by(user).topics.count).to eq(2)
|
expect(TopicQuery.new(user).list_topics_by(user).topics.count).to eq(2)
|
||||||
|
|
||||||
|
# search should return nothing normally
|
||||||
|
expect(TopicQuery.new(nil).list_search.topics.count).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'search' do
|
||||||
|
it 'can correctly search' do
|
||||||
|
# got to enable indexing
|
||||||
|
ActiveRecord::Base.observers.enable :all
|
||||||
|
|
||||||
|
p = create_post(raw: "I am super awesome and search will find me")
|
||||||
|
create_post(topic_id: p.topic_id, raw: "I am super spectacular post of doom")
|
||||||
|
|
||||||
|
results = TopicQuery.new(nil, q: "doom").list_search
|
||||||
|
|
||||||
|
expect(results.topics.count).to eq(1)
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'bookmarks' do
|
context 'bookmarks' do
|
||||||
it "filters and returns bookmarks correctly" do
|
it "filters and returns bookmarks correctly" do
|
||||||
post = Fabricate(:post)
|
post = Fabricate(:post)
|
||||||
|
|
Loading…
Reference in a new issue