Skip to content

Commit 9b8cf3a

Browse files
committed
WIP: Implement ProfileApiClient.list_school_students
1 parent 8059c9c commit 9b8cf3a

File tree

4 files changed

+97
-8
lines changed

4 files changed

+97
-8
lines changed

lib/concepts/school_student/list.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ def call(school:, token:)
1616
private
1717

1818
def list_students(school, token)
19-
response = ProfileApiClient.list_school_students(token:, organisation_id: school.id)
19+
student_ids = Role.student.where(school:).map(&:user_id)
20+
response = ProfileApiClient.list_school_students(token:, school_id: school.id, student_ids:)
2021
user_ids = response.fetch(:ids)
2122

2223
User.from_userinfo(ids: user_ids)

lib/profile_api_client.rb

+11-6
Original file line numberDiff line numberDiff line change
@@ -128,15 +128,20 @@ def remove_school_teacher(token:, teacher_id:, organisation_id:)
128128
#
129129
# The API should respond:
130130
# - 422 Unprocessable if the constraints are not met
131-
def list_school_students(token:, organisation_id:)
131+
def list_school_students(token:, school_id:, student_ids:)
132132
return [] if token.blank?
133133

134-
_ = organisation_id
134+
response = connection.post("/api/v1/schools/#{school_id}/students/list") do |request|
135+
apply_default_headers(request, token)
136+
request.body = student_ids.to_json
137+
end
135138

136-
# TODO: We should make Faraday raise a Ruby error for a non-2xx status
137-
# code so that SchoolOwner::Invite propagates the error in the response.
138-
response = { 'ids' => ['99999999-9999-9999-9999-999999999999'] }
139-
response.deep_symbolize_keys
139+
return [] if response.status == 404
140+
unless response.status == 200
141+
raise "Students cannot be listed in Profile API. HTTP response code: #{response.status}"
142+
end
143+
144+
JSON.parse(response.body).map(&:deep_symbolize_keys)
140145
end
141146

142147
# The API should enforce these constraints:

spec/concepts/school_student/list_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
described_class.call(school:, token:)
2222

2323
# TODO: Replace with WebMock assertion once the profile API has been built.
24-
expect(ProfileApiClient).to have_received(:list_school_students).with(token:, organisation_id: school.id)
24+
expect(ProfileApiClient).to have_received(:list_school_students).with(token:, school_id: school.id, student_ids: [student.id])
2525
end
2626

2727
it 'returns the school students in the operation response' do

spec/lib/profile_api_client_spec.rb

+83
Original file line numberDiff line numberDiff line change
@@ -384,4 +384,87 @@ def create_school_student
384384
described_class.create_school_student(token:, username:, password:, name:, school_id: school.id)
385385
end
386386
end
387+
388+
describe '.list_school_student' do
389+
let(:school) { build(:school, id: SecureRandom.uuid) }
390+
let(:list_students_url) { "#{api_url}/api/v1/schools/#{school.id}/students/list" }
391+
let(:student_ids) { [SecureRandom.uuid] }
392+
393+
before do
394+
stub_request(:post, list_students_url).to_return(status: 200, body: '[]')
395+
end
396+
397+
it 'makes a request to the profile api host' do
398+
list_school_students
399+
expect(WebMock).to have_requested(:post, list_students_url)
400+
end
401+
402+
it 'includes token in the authorization request header' do
403+
list_school_students
404+
expect(WebMock).to have_requested(:post, list_students_url).with(headers: { authorization: "Bearer #{token}" })
405+
end
406+
407+
it 'includes the profile api key in the x-api-key request header' do
408+
list_school_students
409+
expect(WebMock).to have_requested(:post, list_students_url).with(headers: { 'x-api-key' => api_key })
410+
end
411+
412+
it 'sets content-type of request to json' do
413+
list_school_students
414+
expect(WebMock).to have_requested(:post, list_students_url).with(headers: { 'content-type' => 'application/json' })
415+
end
416+
417+
it 'sets accept header to json' do
418+
list_school_students
419+
expect(WebMock).to have_requested(:post, list_students_url).with(headers: { 'accept' => 'application/json' })
420+
end
421+
422+
it 'sets body to the student IDs' do
423+
list_school_students
424+
expect(WebMock).to have_requested(:post, list_students_url).with(body: student_ids)
425+
end
426+
427+
# rubocop:disable RSpec/ExampleLength
428+
it 'returns a hash representing the student(s) if successful' do
429+
response = [
430+
{
431+
id: '549e4674-6ffd-4ac6-9a97-b4d7e5c0e5c5',
432+
schoolId: '132383f1-702a-46a0-9eb2-a40dd4f212e3',
433+
name: 'student-name',
434+
username: 'student-username',
435+
createdAt: '2024-07-03T13:00:40.041Z',
436+
updatedAt: '2024-07-03T13:00:40.041Z',
437+
discardedAt: nil
438+
}
439+
]
440+
stub_request(:post, list_students_url)
441+
.to_return(status: 200, body: response.to_json)
442+
expect(list_school_students).to eq(response)
443+
end
444+
# rubocop:enable RSpec/ExampleLength
445+
446+
it "returns empty array if the API returns a 404 because one or more of the student IDs aren't found" do
447+
stub_request(:post, list_students_url)
448+
.to_return(status: 404, body: '')
449+
expect(list_school_students).to eq([])
450+
end
451+
452+
it 'raises exception if anything other than a 200 status code is returned' do
453+
stub_request(:post, list_students_url)
454+
.to_return(status: 500)
455+
456+
expect { list_school_students }.to raise_error(RuntimeError)
457+
end
458+
459+
it 'includes details of underlying response when exception is raised' do
460+
stub_request(:post, list_students_url)
461+
.to_return(status: 401)
462+
463+
expect { list_school_students }.to raise_error('Students cannot be listed in Profile API. HTTP response code: 401')
464+
end
465+
466+
def list_school_students
467+
described_class.list_school_students(token:, school_id: school.id, student_ids:)
468+
end
469+
end
387470
end

0 commit comments

Comments
 (0)