discourse/spec/models/user_search_spec.rb
Sam Saffron f780920759 FEATURE: mention in secure category to prioritize groups
This feature allows @ mentions to prioritize showing members of a group who
have explicit permission to a category.

This makes it far easier to @ mention group member when composing topics in
categories where only the group has access.

For example:

If Sam, Jane an Joan have access to bugs category.

Then `@` will auto complete to (jane,joan,sam) ordered on last seen at

This feature works on new topics and existing topics. There is an explicit
exclusion of trust level 0,1,2 groups cause they get too big.
2019-08-06 17:57:56 +10:00

202 lines
6.4 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
describe UserSearch do
let(:topic) { Fabricate :topic }
let(:topic2) { Fabricate :topic }
let(:topic3) { Fabricate :topic }
let(:topic4) { Fabricate :topic }
let(:user1) { Fabricate :user, username: "mrb", name: "Michael Madsen", last_seen_at: 10.days.ago }
let(:user2) { Fabricate :user, username: "mrblue", name: "Eddie Code", last_seen_at: 9.days.ago }
let(:user3) { Fabricate :user, username: "mrorange", name: "Tim Roth", last_seen_at: 8.days.ago }
let(:user4) { Fabricate :user, username: "mrpink", name: "Steve Buscemi", last_seen_at: 7.days.ago }
let(:user5) { Fabricate :user, username: "mrbrown", name: "Quentin Tarantino", last_seen_at: 6.days.ago }
let(:user6) { Fabricate :user, username: "mrwhite", name: "Harvey Keitel", last_seen_at: 5.days.ago }
let!(:inactive) { Fabricate :user, username: "Ghost", active: false }
let(:admin) { Fabricate :admin, username: "theadmin" }
let(:moderator) { Fabricate :moderator, username: "themod" }
let(:staged) { Fabricate :staged }
before do
SearchIndexer.enable
end
def search_for(*args)
UserSearch.new(*args).search
end
it 'finds users in secure category' do
group = Fabricate(:group)
user = Fabricate(:user)
group.add(user)
group.save
category = Fabricate.build(
:category,
read_restricted: true,
user: user
)
# TODO: maybe we amend all category fabrication to skip this?
# test is half a second faster
category.skip_category_definition = true
category.save!
Fabricate(:category_group, category: category, group: group)
results = search_for("", category_id: category.id)
expect(user.username).to eq(results[0].username)
expect(results.length).to eq(1)
topic = Fabricate(:topic, category: category)
_post = Fabricate(:post, user: topic.user, topic: topic)
results = search_for("", topic_id: topic.id)
expect(results.length).to eq(2)
expect(results.map(&:username)).to contain_exactly(
user.username, topic.user.username
)
end
it 'allows for correct underscore searching' do
Fabricate(:user, username: 'Under_Score')
Fabricate(:user, username: 'undertaker')
expect(search_for("under_sc").length).to eq(1)
expect(search_for("under_").length).to eq(1)
end
it 'allows filtering by group' do
group = Fabricate(:group)
sam = Fabricate(:user, username: 'sam')
_samantha = Fabricate(:user, username: 'samantha')
group.add(sam)
results = search_for("sam", groups: [group])
expect(results.count).to eq(1)
end
it 'allows filtering by multiple groups' do
group_1 = Fabricate(:group)
sam = Fabricate(:user, username: 'sam')
group_2 = Fabricate(:group)
samantha = Fabricate(:user, username: 'samantha')
group_1.add(sam)
group_2.add(samantha)
results = search_for("sam", groups: [group_1, group_2])
expect(results.count).to eq(2)
end
context "with seed data" do
before do
Fabricate :post, user: user1, topic: topic
Fabricate :post, user: user2, topic: topic2
Fabricate :post, user: user3, topic: topic
Fabricate :post, user: user4, topic: topic
Fabricate :post, user: user5, topic: topic3
Fabricate :post, user: user6, topic: topic
Fabricate :post, user: staged, topic: topic4
user6.update(suspended_at: 1.day.ago, suspended_till: 1.year.from_now)
end
# this is a seriously expensive integration test,
# re-creating this entire test db is too expensive reuse
it "operates correctly" do
# normal search
results = search_for(user1.name.split(" ").first)
expect(results.size).to eq(1)
expect(results.first.username).to eq(user1.username)
# lower case
results = search_for(user1.name.split(" ").first.downcase)
expect(results.size).to eq(1)
expect(results.first).to eq(user1)
# username
results = search_for(user4.username)
expect(results.size).to eq(1)
expect(results.first).to eq(user4)
# case insensitive
results = search_for(user4.username.upcase)
expect(results.size).to eq(1)
expect(results.first).to eq(user4)
# substrings
# only staff members see suspended users in results
results = search_for("mr")
expect(results.size).to eq(5)
expect(results).not_to include(user6)
expect(search_for("mr", searching_user: user1).size).to eq(5)
results = search_for("mr", searching_user: admin)
expect(results.size).to eq(6)
expect(results).to include(user6)
expect(search_for("mr", searching_user: moderator).size).to eq(6)
results = search_for(user1.username, searching_user: admin)
expect(results.size).to eq(3)
results = search_for("MR", searching_user: admin)
expect(results.size).to eq(6)
results = search_for("MRB", searching_user: admin, limit: 2)
expect(results.size).to eq(2)
# topic priority
results = search_for(user1.username, topic_id: topic.id)
expect(results.first).to eq(user1)
results = search_for(user1.username, topic_id: topic2.id)
expect(results[1]).to eq(user2)
results = search_for(user1.username, topic_id: topic3.id)
expect(results[1]).to eq(user5)
# When searching by name is enabled, it returns the record
SiteSetting.enable_names = true
results = search_for("Tarantino")
expect(results.size).to eq(1)
results = search_for("coding")
expect(results.size).to eq(0)
results = search_for("z")
expect(results.size).to eq(0)
# When searching by name is disabled, it will not return the record
SiteSetting.enable_names = false
results = search_for("Tarantino")
expect(results.size).to eq(0)
# find an exact match first
results = search_for("mrB")
expect(results.first.username).to eq(user1.username)
# don't return inactive users
results = search_for(inactive.username)
expect(results).to be_blank
# don't return staged users
results = search_for(staged.username)
expect(results).to be_blank
results = search_for(staged.username, include_staged_users: true)
expect(results.first.username).to eq(staged.username)
results = search_for("", topic_id: topic.id, searching_user: user1)
# mrb is omitted, mrb is current user
expect(results.map(&:username)).to eq(["mrpink", "mrorange"])
end
end
end