Skip to content

Commit 0eb0ae4

Browse files
committed
use school id for safeguarding
1 parent 86d2996 commit 0eb0ae4

11 files changed

Lines changed: 64 additions & 34 deletions

app/controllers/api/school_members_controller.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def create_teacher_safeguarding_flag
3232
ProfileApiClient.create_safeguarding_flag(
3333
token: current_user.token,
3434
flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher],
35-
email: current_user.email
35+
email: current_user.email,
36+
school_id: @school.id
3637
)
3738
end
3839

@@ -42,7 +43,8 @@ def create_owner_safeguarding_flag
4243
ProfileApiClient.create_safeguarding_flag(
4344
token: current_user.token,
4445
flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner],
45-
email: current_user.email
46+
email: current_user.email,
47+
school_id: @school.id
4648
)
4749
end
4850
end

app/controllers/api/school_students_controller.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ def create_teacher_safeguarding_flag
195195
ProfileApiClient.create_safeguarding_flag(
196196
token: current_user.token,
197197
flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher],
198-
email: current_user.email
198+
email: current_user.email,
199+
school_id: @school.id
199200
)
200201
end
201202

@@ -205,7 +206,8 @@ def create_owner_safeguarding_flag
205206
ProfileApiClient.create_safeguarding_flag(
206207
token: current_user.token,
207208
flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner],
208-
email: current_user.email
209+
email: current_user.email,
210+
school_id: @school.id
209211
)
210212
end
211213
end

app/services/school_onboarding_service.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ def onboard(token:)
1414

1515
ProfileApiClient.create_school(token:, id: school.id, code: school.code)
1616
end
17+
rescue ProfileApiClient::UnauthorizedError
18+
# Do not log noise to sentry.
19+
# TODO: consider returning a separate error here to distinguish from other errors and return 401 from the API, not 422
20+
Rails.logger.warn { "Failed to onboard school #{@school.id}: user is unauthorized" }
21+
false
1722
rescue StandardError => e
1823
Sentry.capture_exception(e)
1924
Rails.logger.error { "Failed to onboard school #{@school.id}: #{e.message}" }

lib/profile_api_client.rb

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ class ProfileApiClient
88

99
# rubocop:disable Naming/MethodName
1010
School = Data.define(:id, :schoolCode, :updatedAt, :createdAt, :discardedAt)
11-
SafeguardingFlag = Data.define(:id, :userId, :flag, :email, :createdAt, :updatedAt, :discardedAt)
11+
SafeguardingFlag = Data.define(:id, :userId, :schoolId, :flag, :email, :createdAt, :updatedAt, :discardedAt)
1212
Student = Data.define(:id, :schoolId, :name, :username, :createdAt, :updatedAt, :discardedAt, :email, :ssoProviders)
1313
# rubocop:enable Naming/MethodName
1414

@@ -27,6 +27,8 @@ def initialize(errors)
2727
end
2828
end
2929

30+
class UnauthorizedError < Error; end
31+
3032
class UnexpectedResponse < Error
3133
attr_reader :response_status, :response_headers, :response_body
3234

@@ -50,6 +52,7 @@ def create_school(token:, id:, code:)
5052
}
5153
end
5254

55+
unauthorized!(response)
5356
raise UnexpectedResponse, response unless response.status == 201
5457

5558
School.new(**response.body)
@@ -58,6 +61,7 @@ def create_school(token:, id:, code:)
5861
def school_student(token:, school_id:, student_id:)
5962
response = connection(token).get("/api/v1/schools/#{school_id}/students/#{student_id}")
6063

64+
unauthorized!(response)
6165
raise UnexpectedResponse, response unless response.status == 200
6266

6367
build_student(response.body)
@@ -70,6 +74,7 @@ def list_school_students(token:, school_id:, student_ids:)
7074
request.body = student_ids
7175
end
7276

77+
unauthorized!(response)
7378
raise UnexpectedResponse, response unless response.status == 200
7479

7580
response.body.map { |attrs| build_student(attrs) }
@@ -86,6 +91,7 @@ def create_school_student(token:, username:, password:, name:, school_id:)
8691
}]
8792
end
8893

94+
unauthorized!(response)
8995
raise UnexpectedResponse, response unless response.status == 201
9096

9197
response.body.deep_symbolize_keys
@@ -103,6 +109,7 @@ def validate_school_students(token:, students:, school_id:)
103109
request.headers['Content-Type'] = 'application/json'
104110
end
105111

112+
unauthorized!(response)
106113
raise UnexpectedResponse, response unless response.status == 200
107114
rescue Faraday::UnprocessableEntityError => e
108115
raise Student422Error, JSON.parse(e.response_body)['errors']
@@ -119,6 +126,7 @@ def create_school_students(token:, students:, school_id:, preflight: false)
119126
request.headers['Content-Type'] = 'application/json'
120127
end
121128

129+
unauthorized!(response)
122130
raise UnexpectedResponse, response unless [200, 201].include?(response.status)
123131

124132
response.body.deep_symbolize_keys
@@ -136,6 +144,7 @@ def create_school_students_sso(token:, students:, school_id:)
136144
request.headers['Content-Type'] = 'application/json'
137145
end
138146

147+
unauthorized!(response)
139148
raise UnexpectedResponse, response unless [200, 201].include?(response.status)
140149

141150
response.body.map(&:deep_symbolize_keys)
@@ -154,6 +163,7 @@ def update_school_student(token:, school_id:, student_id:, name: nil, username:
154163
}.compact
155164
end
156165

166+
unauthorized!(response)
157167
raise UnexpectedResponse, response unless response.status == 200
158168

159169
build_student(response.body)
@@ -166,28 +176,32 @@ def delete_school_student(token:, school_id:, student_id:)
166176

167177
response = connection(token).delete("/api/v1/schools/#{school_id}/students/#{student_id}")
168178

179+
unauthorized!(response)
169180
raise UnexpectedResponse, response unless response.status == 204
170181
end
171182

172183
def safeguarding_flags(token:)
173184
response = connection(token).get('/api/v1/safeguarding-flags')
174185

186+
unauthorized!(response)
175187
raise UnexpectedResponse, response unless response.status == 200
176188

177189
response.body.map { |flag| SafeguardingFlag.new(**flag.symbolize_keys) }
178190
end
179191

180-
def create_safeguarding_flag(token:, flag:, email:)
192+
def create_safeguarding_flag(token:, flag:, email:, school_id:)
181193
response = connection(token).post('/api/v1/safeguarding-flags') do |request|
182-
request.body = { flag:, email: }
194+
request.body = { flag:, email:, schoolId: school_id }
183195
end
184196

197+
unauthorized!(response)
185198
raise UnexpectedResponse, response unless [201, 303].include?(response.status)
186199
end
187200

188201
def delete_safeguarding_flag(token:, flag:)
189202
response = connection(token).delete("/api/v1/safeguarding-flags/#{flag}")
190203

204+
unauthorized!(response)
191205
raise UnexpectedResponse, response unless response.status == 204
192206
end
193207

@@ -197,7 +211,7 @@ def connection(token)
197211
Faraday.new(ENV.fetch('IDENTITY_URL')) do |faraday|
198212
faraday.request :json
199213
faraday.response :json
200-
faraday.response :raise_error
214+
faraday.response :raise_error, allowed_statuses: [401]
201215
faraday.headers = {
202216
'Accept' => 'application/json',
203217
'Authorization' => "Bearer #{token}",
@@ -218,6 +232,7 @@ def handle_student_creation_error(faraday_error)
218232
end
219233
end
220234

235+
221236
def build_student(attrs)
222237
symbolized_attrs = attrs.symbolize_keys
223238

@@ -229,5 +244,10 @@ def build_student(attrs)
229244

230245
Student.new(**symbolized_attrs)
231246
end
247+
248+
def unauthorized!(response)
249+
# The API is only available to verified non-student users that are over 13. Others get a 401.
250+
raise UnauthorizedError, 'Profile API unauthorized' if response.status == 401
251+
end
232252
end
233253
end

spec/features/school_member/listing_school_members_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@
9494

9595
it 'creates the school owner safeguarding flag' do
9696
get("/api/schools/#{school.id}/students", headers:)
97-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
97+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
9898
end
9999

100100
it 'does not create the school teacher safeguarding flag' do
101101
get("/api/schools/#{school.id}/students", headers:)
102-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email)
102+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email, school_id: school.id)
103103
end
104104

105105
it "responds with nil attributes for students if the user profile doesn't exist" do
@@ -136,14 +136,14 @@
136136
authenticated_in_hydra_as(teacher)
137137

138138
get("/api/schools/#{school.id}/students", headers:)
139-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
139+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
140140
end
141141

142142
it 'creates the school teacher safeguarding flag when the user is a school teacher' do
143143
teacher = create(:teacher, school:)
144144
authenticated_in_hydra_as(teacher)
145145

146146
get("/api/schools/#{school.id}/students", headers:)
147-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email)
147+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email, school_id: school.id)
148148
end
149149
end

spec/features/school_student/creating_a_batch_of_school_students_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@
5656

5757
it 'creates the school owner safeguarding flag' do
5858
post("/api/schools/#{school.id}/students/batch", headers:, params:)
59-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
59+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
6060
end
6161

6262
it 'does not create the school teacher safeguarding flag' do
6363
post("/api/schools/#{school.id}/students/batch", headers:, params:)
64-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email)
64+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email, school_id: school.id)
6565
end
6666

6767
it 'responds 202 Accepted' do
@@ -113,15 +113,15 @@
113113
authenticated_in_hydra_as(teacher)
114114

115115
post("/api/schools/#{school.id}/students/batch", headers:, params:)
116-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
116+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
117117
end
118118

119119
it 'creates the school teacher safeguarding flag when the user is a school-teacher' do
120120
teacher = create(:teacher, school:)
121121
authenticated_in_hydra_as(teacher)
122122

123123
post("/api/schools/#{school.id}/students/batch", headers:, params:)
124-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email)
124+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email, school_id: school.id)
125125
end
126126

127127
it 'responds 422 Unprocessable Entity when params are invalid' do

spec/features/school_student/creating_a_school_student_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525

2626
it 'creates the school owner safeguarding flag' do
2727
post("/api/schools/#{school.id}/students", headers:, params:)
28-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
28+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
2929
end
3030

3131
it 'does not create the school teacher safeguarding flag' do
3232
post("/api/schools/#{school.id}/students", headers:, params:)
33-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email)
33+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email, school_id: school.id)
3434
end
3535

3636
it 'responds 204 No Content' do
@@ -51,15 +51,15 @@
5151
authenticated_in_hydra_as(teacher)
5252

5353
post("/api/schools/#{school.id}/students", headers:, params:)
54-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
54+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
5555
end
5656

5757
it 'creates the school teacher safeguarding flag when the user is a school teacher' do
5858
teacher = create(:teacher, school:)
5959
authenticated_in_hydra_as(teacher)
6060

6161
post("/api/schools/#{school.id}/students", headers:, params:)
62-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email)
62+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email, school_id: school.id)
6363
end
6464

6565
it 'responds 400 Bad Request when params are missing' do

spec/features/school_student/deleting_a_school_student_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222

2323
it 'creates the school owner safeguarding flag' do
2424
delete("/api/schools/#{school.id}/students/#{student_id}", headers:)
25-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
25+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
2626
end
2727

2828
it 'does not create the school teacher safeguarding flag' do
2929
delete("/api/schools/#{school.id}/students/#{student_id}", headers:)
30-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email)
30+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email, school_id: school.id)
3131
end
3232

3333
it 'responds 200 OK' do
@@ -61,15 +61,15 @@
6161
authenticated_in_hydra_as(teacher)
6262

6363
delete("/api/schools/#{school.id}/students/#{student_id}", headers:)
64-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
64+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
6565
end
6666

6767
it 'does not create the school teacher safeguarding flag when logged in as a teacher' do
6868
teacher = create(:teacher, school:)
6969
authenticated_in_hydra_as(teacher)
7070

7171
delete("/api/schools/#{school.id}/students/#{student_id}", headers:)
72-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email)
72+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email, school_id: school.id)
7373
end
7474

7575
it 'responds 403 Forbidden when the user is a school-student' do

spec/features/school_student/listing_school_students_spec.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222

2323
it 'creates the school owner safeguarding flag' do
2424
get("/api/schools/#{school.id}/students", headers:)
25-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
25+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
2626
end
2727

2828
it 'does not create the school teacher safeguarding flag' do
2929
get("/api/schools/#{school.id}/students", headers:)
30-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email)
30+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: owner.email, school_id: school.id)
3131
end
3232

3333
it 'responds 200 OK when the user is a school-teacher' do
@@ -43,15 +43,15 @@
4343
authenticated_in_hydra_as(teacher)
4444

4545
get("/api/schools/#{school.id}/students", headers:)
46-
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email)
46+
expect(ProfileApiClient).not_to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:owner], email: owner.email, school_id: school.id)
4747
end
4848

4949
it 'creates the school teacher safeguarding flag when the user is a school teacher' do
5050
teacher = create(:teacher, school:)
5151
authenticated_in_hydra_as(teacher)
5252

5353
get("/api/schools/#{school.id}/students", headers:)
54-
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email)
54+
expect(ProfileApiClient).to have_received(:create_safeguarding_flag).with(token: UserProfileMock::TOKEN, flag: ProfileApiClient::SAFEGUARDING_FLAGS[:teacher], email: teacher.email, school_id: school.id)
5555
end
5656

5757
it 'responds with the school students JSON' do

0 commit comments

Comments
 (0)