diff --git a/app/controllers/directory_items_controller.rb b/app/controllers/directory_items_controller.rb index 33bac7ec275..2fbfcf12048 100644 --- a/app/controllers/directory_items_controller.rb +++ b/app/controllers/directory_items_controller.rb @@ -2,6 +2,7 @@ class DirectoryItemsController < ApplicationController PAGE_SIZE = 50 + before_action :set_groups_exclusion, if: -> { params[:exclude_groups].present? } def index unless SiteSetting.enable_user_directory? @@ -24,6 +25,8 @@ class DirectoryItemsController < ApplicationController result = result.includes(user: :primary_group) end + result = apply_exclude_groups_filter(result) + if params[:exclude_usernames] result = result @@ -78,8 +81,11 @@ class DirectoryItemsController < ApplicationController end end + limit = [params[:limit].to_i, PAGE_SIZE].min if params[:limit].to_i > 0 + limit ||= PAGE_SIZE + result_count = result.count - result = result.limit(PAGE_SIZE).offset(PAGE_SIZE * page).to_a + result = result.limit(limit).offset(limit * page).to_a more_params = params.slice(:period, :order, :asc, :group, :user_field_ids).permit! more_params[:page] = page + 1 @@ -92,8 +98,10 @@ class DirectoryItemsController < ApplicationController # Don't show the record unless you're not in the top positions already if (position || 10) >= 10 - your_item = DirectoryItem.where(period_type: period_type, user_id: current_user.id).first - result.insert(0, your_item) if your_item + unless @users_in_exclude_groups&.include?(current_user.id) + your_item = DirectoryItem.where(period_type: period_type, user_id: current_user.id).first + result.insert(0, your_item) if your_item + end end end @@ -127,4 +135,17 @@ class DirectoryItemsController < ApplicationController }, ) end + + private + + def set_groups_exclusion + @exclude_group_names = params[:exclude_groups].split("|") + @exclude_group_ids = Group.where(name: @exclude_group_names).pluck(:id) + @users_in_exclude_groups = GroupUser.where(group_id: @exclude_group_ids).pluck(:user_id) + end + + def apply_exclude_groups_filter(result) + result = result.where.not(user_id: @users_in_exclude_groups) if params[:exclude_groups] + result + end end diff --git a/spec/requests/directory_items_controller_spec.rb b/spec/requests/directory_items_controller_spec.rb index e56ded8ae20..6576072fcc4 100644 --- a/spec/requests/directory_items_controller_spec.rb +++ b/spec/requests/directory_items_controller_spec.rb @@ -17,6 +17,75 @@ RSpec.describe DirectoryItemsController do expect(response).not_to be_successful end + context "with limit parameter" do + let!(:users) { Array.new(DirectoryItemsController::PAGE_SIZE + 10) { Fabricate(:user) } } + + before { DirectoryItem.refresh! } + + it "limits the number of returned items" do + get "/directory_items.json", params: { period: "all", limit: 2 } + expect(response.status).to eq(200) + json = response.parsed_body + + expect(json["directory_items"].length).to eq(2) + end + + it "does not exceed PAGE_SIZE if limit parameter is more than PAGE_SIZE" do + large_limit = DirectoryItemsController::PAGE_SIZE + 10 + get "/directory_items.json", params: { period: "all", limit: large_limit } + expect(response.status).to eq(200) + json = response.parsed_body + + expect(json["directory_items"].length).to eq(DirectoryItemsController::PAGE_SIZE) + end + + it "handles invalid limit parameters gracefully" do + get "/directory_items.json", params: { period: "all", limit: "invalid_limit" } + expect(response.status).to eq(200) + json = response.parsed_body + + expect(json["directory_items"]).not_to be_empty + end + end + + context "with exclude_groups parameter" do + before { DirectoryItem.refresh! } + + it "excludes users from specified groups" do + get "/directory_items.json", params: { period: "all", exclude_groups: group.name } + expect(response.status).to eq(200) + json = response.parsed_body + usernames = json["directory_items"].map { |item| item["user"]["username"] } + + expect(usernames).not_to include("eviltrout", "stage_user") + end + + it "handles non-existent group names gracefully" do + get "/directory_items.json", params: { period: "all", exclude_groups: "non_existent_group" } + expect(response.status).to eq(200) + json = response.parsed_body + + user_names = json["directory_items"].map { |item| item["user"]["username"] } + expect(user_names).to include("eviltrout") + end + end + + context "with exclude_groups parameter and current user in the top positions" do + before do + sign_in(evil_trout) + DirectoryItem.refresh! + end + + it "doesn't include current user if they are already in the top positions" do + get "/directory_items.json", params: { period: "all", exclude_groups: group.name } + expect(response.status).to eq(200) + json = response.parsed_body + usernames = json["directory_items"].map { |item| item["user"]["username"] } + + expect(usernames).not_to include("eviltrout") + end + end + context "without data" do context "with a logged in user" do before { sign_in(user) }