mirror of
https://github.com/codeninjasllc/discourse.git
synced 2025-05-02 08:54:02 -04:00
FEATURE: search private messages option
This commit is contained in:
parent
174a00c985
commit
4aa0d88c6c
6 changed files with 114 additions and 13 deletions
app
assets/javascripts/discourse
controllers
config/locales
lib
spec/components
|
@ -4,13 +4,23 @@ var _dontSearch = false;
|
||||||
|
|
||||||
export default Em.Controller.extend(Discourse.Presence, {
|
export default Em.Controller.extend(Discourse.Presence, {
|
||||||
|
|
||||||
|
contextType: function(key, value){
|
||||||
|
if(arguments.length > 1) {
|
||||||
|
// a bit hacky, consider cleaning this up, need to work through all observers though
|
||||||
|
var context = $.extend({}, this.get('searchContext'));
|
||||||
|
context.type = value;
|
||||||
|
this.set('searchContext', context);
|
||||||
|
}
|
||||||
|
return this.get('searchContext.type');
|
||||||
|
}.property('searchContext'),
|
||||||
|
|
||||||
contextChanged: function(){
|
contextChanged: function(){
|
||||||
if (this.get('searchContextEnabled')) {
|
if (this.get('searchContextEnabled')) {
|
||||||
_dontSearch = true;
|
_dontSearch = true;
|
||||||
this.set('searchContextEnabled', false);
|
this.set('searchContextEnabled', false);
|
||||||
_dontSearch = false;
|
_dontSearch = false;
|
||||||
}
|
}
|
||||||
}.observes("searchContext"),
|
}.observes('searchContext'),
|
||||||
|
|
||||||
searchContextDescription: function(){
|
searchContextDescription: function(){
|
||||||
var ctx = this.get('searchContext');
|
var ctx = this.get('searchContext');
|
||||||
|
@ -22,6 +32,8 @@ export default Em.Controller.extend(Discourse.Presence, {
|
||||||
return I18n.t('search.context.user', {username: Em.get(ctx, 'user.username')});
|
return I18n.t('search.context.user', {username: Em.get(ctx, 'user.username')});
|
||||||
case 'category':
|
case 'category':
|
||||||
return I18n.t('search.context.category', {category: Em.get(ctx, 'category.name')});
|
return I18n.t('search.context.category', {category: Em.get(ctx, 'category.name')});
|
||||||
|
case 'private_messages':
|
||||||
|
return I18n.t('search.context.private_messages');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.property('searchContext'),
|
}.property('searchContext'),
|
||||||
|
|
|
@ -25,7 +25,12 @@ export default function (viewName, path) {
|
||||||
showParticipants: true
|
showParticipants: true
|
||||||
});
|
});
|
||||||
|
|
||||||
this.controllerFor('user').set("pmView", viewName);
|
this.controllerFor('user').set('pmView', viewName);
|
||||||
|
this.controllerFor('search').set('contextType', 'private_messages');
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivate: function(){
|
||||||
|
this.controllerFor('search').set('contextType', 'user');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ require_dependency 'search'
|
||||||
class SearchController < ApplicationController
|
class SearchController < ApplicationController
|
||||||
|
|
||||||
def self.valid_context_types
|
def self.valid_context_types
|
||||||
%w{user topic category}
|
%w{user topic category private_messages}
|
||||||
end
|
end
|
||||||
|
|
||||||
def query
|
def query
|
||||||
|
@ -21,16 +21,19 @@ class SearchController < ApplicationController
|
||||||
raise Discourse::InvalidParameters.new(:search_context) unless SearchController.valid_context_types.include?(search_context[:type])
|
raise Discourse::InvalidParameters.new(:search_context) unless SearchController.valid_context_types.include?(search_context[:type])
|
||||||
raise Discourse::InvalidParameters.new(:search_context) if search_context[:id].blank?
|
raise Discourse::InvalidParameters.new(:search_context) if search_context[:id].blank?
|
||||||
|
|
||||||
klass = search_context[:type].classify.constantize
|
|
||||||
|
|
||||||
# A user is found by username
|
# A user is found by username
|
||||||
context_obj = nil
|
context_obj = nil
|
||||||
if search_context[:type] == 'user'
|
if ['user','private_messages'].include? search_context[:type]
|
||||||
context_obj = klass.find_by(username_lower: params[:search_context][:id].downcase)
|
context_obj = User.find_by(username_lower: params[:search_context][:id].downcase)
|
||||||
else
|
else
|
||||||
|
klass = search_context[:type].classify.constantize
|
||||||
context_obj = klass.find_by(id: params[:search_context][:id])
|
context_obj = klass.find_by(id: params[:search_context][:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if search_context[:type] == 'private_messages'
|
||||||
|
search_args[:type_filter] = 'private_messages'
|
||||||
|
end
|
||||||
|
|
||||||
guardian.ensure_can_see!(context_obj)
|
guardian.ensure_can_see!(context_obj)
|
||||||
search_args[:search_context] = context_obj
|
search_args[:search_context] = context_obj
|
||||||
end
|
end
|
||||||
|
|
|
@ -769,6 +769,7 @@ en:
|
||||||
user: "Search posts by @{{username}}"
|
user: "Search posts by @{{username}}"
|
||||||
category: "Search the \"{{category}}\" category"
|
category: "Search the \"{{category}}\" category"
|
||||||
topic: "Search this topic"
|
topic: "Search this topic"
|
||||||
|
private_messages: "Search private messages"
|
||||||
|
|
||||||
site_map: "go to another topic list or category"
|
site_map: "go to another topic list or category"
|
||||||
go_back: 'go back'
|
go_back: 'go back'
|
||||||
|
|
|
@ -17,7 +17,7 @@ class Search
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.facets
|
def self.facets
|
||||||
%w(topic category user)
|
%w(topic category user private_messages)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.long_locale
|
def self.long_locale
|
||||||
|
@ -277,10 +277,20 @@ class Search
|
||||||
def posts_query(limit, opts=nil)
|
def posts_query(limit, opts=nil)
|
||||||
opts ||= {}
|
opts ||= {}
|
||||||
posts = Post
|
posts = Post
|
||||||
.joins(:post_search_data, {:topic => :category})
|
.joins(:post_search_data, :topic)
|
||||||
|
.joins("LEFT JOIN categories ON categories.id = topics.category_id")
|
||||||
.where("topics.deleted_at" => nil)
|
.where("topics.deleted_at" => nil)
|
||||||
.where("topics.visible")
|
.where("topics.visible")
|
||||||
.where("topics.archetype <> ?", Archetype.private_message)
|
|
||||||
|
if opts[:private_messages]
|
||||||
|
posts = posts.where("topics.archetype = ?", Archetype.private_message)
|
||||||
|
|
||||||
|
unless @guardian.is_admin?
|
||||||
|
posts = posts.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = ?)", @guardian.user.id)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
posts = posts.where("topics.archetype <> ?", Archetype.private_message)
|
||||||
|
end
|
||||||
|
|
||||||
if @search_context.present? && @search_context.is_a?(Topic)
|
if @search_context.present? && @search_context.is_a?(Topic)
|
||||||
posts = posts.joins('JOIN users u ON u.id = posts.user_id')
|
posts = posts.joins('JOIN users u ON u.id = posts.user_id')
|
||||||
|
@ -336,7 +346,13 @@ class Search
|
||||||
if @search_context.present?
|
if @search_context.present?
|
||||||
|
|
||||||
if @search_context.is_a?(User)
|
if @search_context.is_a?(User)
|
||||||
posts = posts.where("posts.user_id = #{@search_context.id}")
|
|
||||||
|
if opts[:private_messages]
|
||||||
|
posts = posts.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = ?)", @search_context.id)
|
||||||
|
else
|
||||||
|
posts = posts.where("posts.user_id = #{@search_context.id}")
|
||||||
|
end
|
||||||
|
|
||||||
elsif @search_context.is_a?(Category)
|
elsif @search_context.is_a?(Category)
|
||||||
posts = posts.where("topics.category_id = #{@search_context.id}")
|
posts = posts.where("topics.category_id = #{@search_context.id}")
|
||||||
elsif @search_context.is_a?(Topic)
|
elsif @search_context.is_a?(Topic)
|
||||||
|
@ -407,9 +423,10 @@ class Search
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def aggregate_search
|
def aggregate_search(opts = {})
|
||||||
|
|
||||||
post_sql = posts_query(@limit, aggregate_search: true)
|
post_sql = posts_query(@limit, aggregate_search: true,
|
||||||
|
private_messages: opts[:private_messages])
|
||||||
.select('topics.id', 'min(post_number) post_number')
|
.select('topics.id', 'min(post_number) post_number')
|
||||||
.group('topics.id')
|
.group('topics.id')
|
||||||
.to_sql
|
.to_sql
|
||||||
|
@ -417,6 +434,10 @@ 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')
|
||||||
|
@ -426,6 +447,12 @@ class Search
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def private_messages_search
|
||||||
|
raise Discourse::InvalidAccess.new("anonymous can not search PMs") unless @guardian.user
|
||||||
|
|
||||||
|
aggregate_search(private_messages: true)
|
||||||
|
end
|
||||||
|
|
||||||
def topic_search
|
def topic_search
|
||||||
if @search_context.is_a?(Topic)
|
if @search_context.is_a?(Topic)
|
||||||
posts = posts_query(@limit).where('posts.topic_id = ?', @search_context.id).includes(:topic => :category)
|
posts = posts_query(@limit).where('posts.topic_id = ?', @search_context.id).includes(:topic => :category)
|
||||||
|
|
|
@ -96,6 +96,59 @@ describe Search do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'private messages' do
|
||||||
|
|
||||||
|
let(:topic) {
|
||||||
|
Fabricate(:topic,
|
||||||
|
category_id: nil,
|
||||||
|
archetype: 'private_message')
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:post) { Fabricate(:post, topic: topic) }
|
||||||
|
let(:reply) { Fabricate(:post, topic: topic,
|
||||||
|
raw: 'hello from mars, we just landed') }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
it 'searches correctly' do
|
||||||
|
|
||||||
|
expect do
|
||||||
|
Search.execute('mars', type_filter: 'private_messages')
|
||||||
|
end.to raise_error(Discourse::InvalidAccess)
|
||||||
|
|
||||||
|
TopicAllowedUser.create!(user_id: reply.user_id, topic_id: topic.id)
|
||||||
|
TopicAllowedUser.create!(user_id: post.user_id, topic_id: topic.id)
|
||||||
|
|
||||||
|
|
||||||
|
results = Search.execute('mars',
|
||||||
|
type_filter: 'private_messages',
|
||||||
|
guardian: Guardian.new(reply.user))
|
||||||
|
|
||||||
|
results.posts.length.should == 1
|
||||||
|
|
||||||
|
# does not leak out
|
||||||
|
results = Search.execute('mars',
|
||||||
|
type_filter: 'private_messages',
|
||||||
|
guardian: Guardian.new(Fabricate(:user)))
|
||||||
|
|
||||||
|
results.posts.length.should == 0
|
||||||
|
|
||||||
|
Fabricate(:topic, category_id: nil, archetype: 'private_message')
|
||||||
|
Fabricate(:post, topic: topic, raw: 'another secret pm from mars, testing')
|
||||||
|
|
||||||
|
|
||||||
|
# admin can search everything with correct context
|
||||||
|
results = Search.execute('mars',
|
||||||
|
type_filter: 'private_messages',
|
||||||
|
search_context: post.user,
|
||||||
|
guardian: Guardian.new(Fabricate(:admin)))
|
||||||
|
|
||||||
|
results.posts.length.should == 1
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
context 'topics' do
|
context 'topics' do
|
||||||
let(:post) { Fabricate(:post) }
|
let(:post) { Fabricate(:post) }
|
||||||
let(:topic) { post.topic}
|
let(:topic) { post.topic}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue