Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Research Classes page: filter all the options by project_id #1280

Merged
merged 1 commit into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 27 additions & 12 deletions rails/app/controllers/api/v1/research_classes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,31 +48,37 @@ def query(options, user)
# Load results just for one field and no totals
case options[:load_only]
when "teachers"
results[:hits] = {teachers: teacher_query(options, user, teachers, classes_ids_subquery)}
results[:hits] = {teachers: teacher_query(options, user, teachers, classes_ids_subquery, ids[:project_id])}
when "cohorts"
results[:hits] = {cohorts: cohorts_query(options, user, cohorts, classes_ids_subquery)}
results[:hits] = {cohorts: cohorts_query(options, user, cohorts, classes_ids_subquery, ids[:project_id])}
when "runnables"
results[:hits] = {runnables: runnables_query(options, user, runnables, classes_ids_subquery)}
results[:hits] = {runnables: runnables_query(options, user, runnables, classes_ids_subquery, ids[:project_id])}
end
else
results[:hits] = {
classes: classes_mapping(classes_subquery)
}
results[:totals] = {
teachers: teacher_query(options, user, teachers, classes_ids_subquery, true),
cohorts: cohorts_query(options, user, cohorts, classes_ids_subquery, true),
runnables: runnables_query(options, user, runnables, classes_ids_subquery, true),
teachers: teacher_query(options, user, teachers, classes_ids_subquery, ids[:project_id], true),
cohorts: cohorts_query(options, user, cohorts, classes_ids_subquery, ids[:project_id], true),
runnables: runnables_query(options, user, runnables, classes_ids_subquery, ids[:project_id], true),
classes: results[:hits][:classes].count
}
end

return results
end

def teacher_query(options, user, scope, clazz_ids_subquery, count_only = false)
def teacher_query(options, user, scope, clazz_ids_subquery, project_id, count_only = false)
scope = scope
.joins("INNER JOIN portal_teacher_clazzes ON portal_teacher_clazzes.teacher_id = portal_teachers.id")
.where(portal_teacher_clazzes: { clazz_id: clazz_ids_subquery })
# Note that we still need to filter by project_id, as one class might belong to two projects if
# it has two teachers, each belonging to a different project.
.joins("INNER JOIN admin_cohort_items ON admin_cohort_items.item_id = portal_teachers.id AND admin_cohort_items.item_type = 'Portal::Teacher'")
.joins("INNER JOIN admin_cohorts ON admin_cohorts.id = admin_cohort_items.admin_cohort_id")
.joins("INNER JOIN admin_projects ON admin_projects.id = admin_cohorts.project_id")
.where(admin_projects: { id: project_id })
.distinct

if count_only
Expand All @@ -84,12 +90,15 @@ def teacher_query(options, user, scope, clazz_ids_subquery, count_only = false)
end
end

def cohorts_query(options, user, scope, clazz_ids_subquery, count_only = false)
def cohorts_query(options, user, scope, clazz_ids_subquery, project_id, count_only = false)
scope = scope
.joins("INNER JOIN admin_cohort_items ON admin_cohort_items.item_type = 'Portal::Teacher' AND admin_cohort_items.admin_cohort_id = admin_cohorts.id")
.joins("INNER JOIN portal_teacher_clazzes ON admin_cohort_items.item_id = portal_teacher_clazzes.teacher_id")
.where(portal_teacher_clazzes: { clazz_id: clazz_ids_subquery })
.joins("LEFT OUTER JOIN admin_projects ON admin_projects.id = admin_cohorts.project_id")
# Note that we still need to filter by project_id, as one class might belong to two projects if
# it has two teachers, each belonging to a different project.
.joins("INNER JOIN admin_projects ON admin_projects.id = admin_cohorts.project_id")
.where(admin_projects: { id: project_id })
.distinct

if count_only
Expand All @@ -101,10 +110,16 @@ def cohorts_query(options, user, scope, clazz_ids_subquery, count_only = false)
end
end

def runnables_query(options, user, scope, clazz_ids_subquery, count_only = false)
def runnables_query(options, user, scope, clazz_ids_subquery, project_id, count_only = false)
scope = scope
.joins("INNER JOIN portal_teacher_clazzes ptc2 ON portal_offerings.clazz_id = ptc2.clazz_id")
.where("ptc2.clazz_id": clazz_ids_subquery)
.where(clazz_id: clazz_ids_subquery)
# Note that we still need to filter by project_id, as one class might belong to two projects if
# it has two teachers, each belonging to a different project.
.joins("INNER JOIN portal_teacher_clazzes ON portal_teacher_clazzes.clazz_id = portal_offerings.clazz_id")
.joins("INNER JOIN admin_cohort_items ON admin_cohort_items.item_id = portal_teacher_clazzes.teacher_id AND admin_cohort_items.item_type = 'Portal::Teacher'")
.joins("INNER JOIN admin_cohorts ON admin_cohorts.id = admin_cohort_items.admin_cohort_id")
.joins("INNER JOIN admin_projects ON admin_projects.id = admin_cohorts.project_id")
.where(admin_projects: { id: project_id })
.distinct

if count_only
Expand Down
71 changes: 49 additions & 22 deletions rails/spec/controllers/api/v1/research_classes_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
@cc_school = FactoryBot.create(:portal_school, {name: 'concord consortium'})

@teacher1 = FactoryBot.create(:portal_teacher, schools: [@cc_school])

@teacher2 = FactoryBot.create(:portal_teacher)
@teacher2 = FactoryBot.create(:portal_teacher, schools: [@cc_school])

@project1 = FactoryBot.create(:project, name: 'Project 1')
@project2 = FactoryBot.create(:project, name: 'Project 2')
Expand All @@ -23,19 +22,28 @@
@teacher1.cohorts << @cohort1
@teacher2.cohorts << @cohort2

# test different tools
@clazz1 = @teacher1.clazzes[0]
@clazz2 = @teacher2.clazzes[0]

@runnable1 = FactoryBot.create(:external_activity)
@runnable2 = FactoryBot.create(:external_activity)

@offering1 = FactoryBot.create(:portal_offering, {clazz: @teacher1.clazzes[0], runnable: @runnable1})
@offering2 = FactoryBot.create(:portal_offering, {clazz: @teacher2.clazzes[0], runnable: @runnable2})
@offering1 = FactoryBot.create(:portal_offering, {clazz: @clazz1, runnable: @runnable1})
@offering2 = FactoryBot.create(:portal_offering, {clazz: @clazz2, runnable: @runnable2})

# This line is very important because it protects against regressions related to the following issue:
# https://www.pivotaltracker.com/story/show/187422622
# @clazz1 is now considered valid for both @project1 and @project2 (via @teacher2 and @cohort2).
# This will test explicit filtering of filter options (cohorts, teachers, runnables) by project_id.
@clazz1.teachers << @teacher2

sign_in researcher
end

let(:researcher) do
user = FactoryBot.create(:confirmed_user)
user.add_role_for_project('researcher', @project1)
user.add_role_for_project('researcher', @project2)
user
end

Expand Down Expand Up @@ -95,71 +103,90 @@

describe "basic query" do
describe "GET index" do
let (:params) do
{
project_id: "#{@project1.id}",
cohorts: "#{@cohort1.id}",
teachers: "#{@teacher1.id}",
runnables: "#{@runnable1.id}"
}
end
it "allows index" do
params = {
project_id: @project1.id
}
get :index, params: params
expect(response.status).to eql(200)
end
it "gets class info" do
params = {
project_id: @project1.id
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
clazz = @teacher1.clazzes[0]
expect(json["hits"]).to eql({"classes"=>[{"class_url"=>materials_portal_clazz_url(clazz.id, researcher: true), "cohort_names"=>@cohort1.name, "id"=>clazz.id, "name"=>clazz.name, "school_name"=>@teacher1.school.name, "teacher_names"=>@teacher1.name}]})
clazz = @clazz1
expect(json["hits"]).to eql({"classes"=>[{"class_url"=>materials_portal_clazz_url(clazz.id, researcher: true), "cohort_names"=>@cohort1.name, "id"=>clazz.id, "name"=>clazz.name, "school_name"=>@teacher1.school.name, "teacher_names"=>"#{@teacher1.name}, #{@teacher2.name}"}]})
end
it "gets totals" do
params = {
project_id: @project1.id
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
expect(json["totals"]).to eql({"classes"=>1, "cohorts"=>1, "runnables"=>1, "teachers"=>1})
end
it "gets all teachers" do
params[:load_only] = "teachers"
params = {
project_id: @project1.id,
load_only: "teachers"
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
expect(json["hits"]["teachers"].length).to eql(1)
end
it "gets all cohorts" do
params[:load_only] = "cohorts"
params = {
project_id: @project1.id,
load_only: "cohorts"
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
expect(json["hits"]["cohorts"].length).to eql(1)
expect(json["hits"]["cohorts"][0]).to eql({"id"=>@cohort1.id, "label"=>"Project 1: test cohort"})
end
it "gets all runnables" do
params[:load_only] = "runnables"
params = {
project_id: @project1.id,
load_only: "runnables"
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
expect(json["hits"]["runnables"].length).to eql(1)
end
it "filters out archived runnables" do
@runnable1.update_attribute(:is_archived, true)
params[:load_only] = "runnables"
params = {
project_id: @project1.id,
load_only: "runnables"
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
expect(json["hits"]["runnables"].length).to eql(0)
end
it "filters out CC teachers from teachers results (when requested)" do
params[:load_only] = "teachers"
params[:remove_cc_teachers] = "true"
params = {
project_id: @project1.id,
load_only: "teachers",
remove_cc_teachers: "true"
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
expect(json["hits"]["teachers"].length).to eql(0)
end
it "filters out CC teachers from classes results (when requested)" do
params[:remove_cc_teachers] = "true"
params = {
project_id: @project1.id,
remove_cc_teachers: "true"
}
get :index, params: params
json = JSON.parse(response.body)
expect(response.status).to eql(200)
Expand Down
Loading