Skip to content

Commit

Permalink
feat: Add projects to solr search [PT-188115817]
Browse files Browse the repository at this point in the history
This adds projects to the solr search endpoint.
  • Loading branch information
dougmartin committed Aug 28, 2024
1 parent 1f65572 commit 41ae9c5
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 2 deletions.
45 changes: 44 additions & 1 deletion rails/app/controllers/api/v1/search_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ def search_results_data
results = []
@search.results.each do |type, values|
next if type == :all
results.push group_data(type.downcase, values)
if type == :project
results.push project_data(values)
else
results.push group_data(type.downcase, values)
end
end
results
end
Expand All @@ -63,6 +67,45 @@ def group_data(type, collection)
}
end

def project_data(collection)
projects = []
collection.each do |project|
tags = {}
tags['subject_areas'] = []
tags['grade_levels'] = []

tags.each do |key, value|
list = project.send(key)
list.each do |o|
tags[key].push o.name
end
end

project_data = {
id: project.id,
name: project.name,
subject_areas: tags['subject_areas'],
grade_levels: tags['grade_levels'],
}

projects.push project_data
end

{
type: "projects",
header: view_context.t("HomePage.SearchResults.Projects"),
projects: projects,
pagination: {
current_page: collection.current_page,
total_pages: collection.total_pages,
start_item: collection.offset + 1,
end_item: collection.offset + collection.length,
total_items: collection.total_entries,
per_page: collection.per_page
}
}
end

def search_filters_data
filters = {}
filters[:number_authored_resources] = @search.number_authored_resources
Expand Down
23 changes: 23 additions & 0 deletions rails/app/models/admin/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,29 @@ def project_researchers
project_users.where(is_researcher:true).map { |ru| ru.user }
end

# this has to be set AFTER SearchableModel is included so that sunspot doesn't alias #solr_search to #search
searchable do
text :name
string :name

text :landing_page_content
text :project_card_description
text :landing_page_slug

boolean :public

time :updated_at
time :created_at

string :grade_levels, :multiple => true do
grade_level_list
end

string :subject_areas, :multiple => true do
subject_area_list
end
end

has_many :project_materials, dependent: :destroy
has_many :external_activities, through: :project_materials, source: :material, source_type: 'ExternalActivity'
has_many :interactives, through: :project_materials, source: :material, source_type: 'Interactive'
Expand Down
25 changes: 24 additions & 1 deletion rails/app/models/search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ class Search
attr_accessor :no_sensors
attr_accessor :sensors
attr_accessor :project_ids
attr_accessor :search_projects

attr_accessor :available_subject_areas
attr_accessor :available_grade_level_groups
Expand Down Expand Up @@ -144,7 +145,8 @@ def initialize(opts={})
self.include_mine = opts[:include_mine] || false
self.include_official = opts[:include_official] || false
self.include_templates = opts[:include_templates] || false
self.show_archived = opts[:show_archived] || false
self.show_archived = opts[:show_archived] || false
self.search_projects = opts[:search_projects] || false

self.fetch_available_filter_options()

Expand Down Expand Up @@ -206,6 +208,27 @@ def search
self.hits[:all] = []
self.total_entries[:all] = 0

if self.search_projects
# need to use #solr_search instead of #search as the project model already has a non-solr search method
_results = Admin::Project.solr_search do |s|
s.fulltext(self.text)
s.with(:public, true)
search_by_grade_levels(s)
search_by_subject_areas(s)

s.order_by(:name)

# no pagination on project searches, all results are shown on the first page load
end

self.results[:all] += _results.results
self.hits[:all] += _results.hits
self.total_entries[:all] += _results.results.total_entries
self.results[:project] = _results.results
self.hits[:project] = _results.hits
self.total_entries[:project] = _results.results.total_entries
end

self.clean_material_types.each do |type|

_results = self.engine.search(self.searchable_models) do |s|
Expand Down
2 changes: 2 additions & 0 deletions rails/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ en:
in the upper left to search all resources or view curated Collections of
resources by clicking the Collections link above.
</p>
SearchResults:
Projects: Collections

search:
only_mine: Resources I authored
Expand Down
102 changes: 102 additions & 0 deletions rails/spec/models/search_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -648,5 +648,107 @@ def collection(factory, count=3, opts={})
end
end

context "for projects" do
# create projects
let(:foo_project) {
FactoryBot.create(:project, name: "Foo", landing_page_slug: "first-project", public: true,
landing_page_content: "The foo project has content about cats",
project_card_description: "This is the description about felines",
grade_level_list: ["1", "2"], subject_area_list: ["Math"]
)
}
let(:bar_project) {
FactoryBot.create(:project, name: "Bar", landing_page_slug: "second-project", public: true,
landing_page_content: "The bar project also has content about cats",
project_card_description: "This is also the description about felines",
grade_level_list: ["1", "3"], subject_area_list: ["Math", "Chemistry"]
)
}
let(:baz_project) {
FactoryBot.create(:project, name: "Baz", landing_page_slug: "third-project", public: false,
landing_page_content: "The baz project is private and should not show in search results",
project_card_description: "This is the description about private projects",
grade_level_list: ["1", "2"], subject_area_list: ["Math"]
)
}
let(:search_opts) { { :search_projects => true } }

before(:each) do
foo_project
bar_project
baz_project
Admin::Project.reindex
Sunspot.commit
end

describe "with no options" do
it "returns in alphabetical name order filtering out private projects" do
expect(subject.results[:project].length).to eq(2)
expect(subject.results[:project][0].public).to be(true)
expect(subject.results[:project][1].public).to be(true)

expect(subject.results[:project][0].id).to be(bar_project.id)
expect(subject.results[:project][1].id).to be(foo_project.id)
end
end

describe "by name" do
let(:search_opts) { {:search_projects => true, :search_term => "foo"} }

it "results in 1 result" do
expect(subject.results[:project].length).to eq(1)
expect(subject.results[:project][0].id).to be(foo_project.id)
end
end

describe "by landing page content" do
let(:search_opts) { {:search_projects => true, :search_term => "cats"} }

it "results in 2 results" do
expect(subject.results[:project].length).to eq(2)

expect(subject.results[:project][0].id).to be(bar_project.id)
expect(subject.results[:project][1].id).to be(foo_project.id)
end
end

describe "by project card description" do
let(:search_opts) { {:search_projects => true, :search_term => "felines"} }

it "results in 2 results" do
expect(subject.results[:project].length).to eq(2)

expect(subject.results[:project][0].id).to be(bar_project.id)
expect(subject.results[:project][1].id).to be(foo_project.id)
end
end

describe "by landing page slug" do
let(:search_opts) { {:search_projects => true, :search_term => "second"} }

it "results in 1 result" do
expect(subject.results[:project].length).to eq(1)
expect(subject.results[:project][0].id).to be(bar_project.id)
end
end

describe "by grade levels" do
let(:search_opts) { {:search_projects => true, :grade_level_groups => ["3-4"]} }

it "results in 1 results" do
expect(subject.results[:project].length).to eq(1)
expect(subject.results[:project][0].id).to be(bar_project.id)
end
end

describe "by subject areas" do
let(:search_opts) { {:search_projects => true, :subject_areas => ["Chemistry"]} }

it "results in 1 results" do
expect(subject.results[:project].length).to eq(1)
expect(subject.results[:project][0].id).to be(bar_project.id)
end
end
end
end
end

0 comments on commit 41ae9c5

Please sign in to comment.