Skip to content

Commit bfccdd1

Browse files
committed
WIP: Implement ProfileApiClient.list_school_students
1 parent 6151170 commit bfccdd1

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

0 commit comments

Comments
 (0)