Skip to content

Commit ceb2643

Browse files
authored
fix owners being added to class (#528)
## What's changed? - Fixed ability to add owners to a class - Fixed owner appearing with teacher icon when first added to a class
1 parent caf01c4 commit ceb2643

File tree

4 files changed

+203
-73
lines changed

4 files changed

+203
-73
lines changed

app/controllers/api/class_members_controller.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ def index
2424
def create
2525
user_ids = [class_member_params[:user_id]]
2626
user_type = class_member_params[:type]
27-
if user_type == 'teacher'
28-
teachers = SchoolTeacher::List.call(school: @school, teacher_ids: user_ids)
29-
students = { school_students: [] }
30-
else
27+
owners = SchoolOwner::List.call(school: @school).fetch(:school_owners, [])
28+
@school_owner_ids = owners.map(&:id)
29+
if user_type == 'student'
3130
teachers = { school_teachers: [] }
3231
students = SchoolStudent::List.call(school: @school, token: current_user.token, student_ids: user_ids)
32+
else
33+
teachers = SchoolTeacher::List.call(school: @school, teacher_ids: user_ids)
34+
students = { school_students: [] }
3335
end
3436
result = ClassMember::Create.call(school_class: @school_class, students: students[:school_students], teachers: teachers[:school_teachers])
3537

@@ -42,6 +44,9 @@ def create
4244
end
4345

4446
def create_batch
47+
owners = SchoolOwner::List.call(school: @school).fetch(:school_owners, [])
48+
@school_owner_ids = owners.map(&:id)
49+
4550
# Teacher objects needs to be the compliment of student objects so that every user creation is attempted and validated.
4651
student_objects = create_batch_params.select { |user| user[:type] == 'student' }
4752
teacher_objects = create_batch_params.select { |user| student_objects.pluck(:user_id).exclude?(user[:user_id]) }

app/views/api/class_members/_class_member.json.jbuilder

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ if class_member.respond_to?(:student)
1515
end
1616
elsif class_member.respond_to?(:teacher)
1717
json.teacher_id(class_member.teacher_id)
18-
json.set! :teacher do
19-
json.partial! '/api/school_teachers/school_teacher', teacher: class_member.teacher
18+
if @school_owner_ids.include?(class_member.teacher_id)
19+
json.set! :owner do
20+
json.partial! '/api/school_owners/school_owner', owner: class_member.teacher
21+
end
22+
else
23+
json.set! :teacher do
24+
json.partial! '/api/school_teachers/school_teacher', teacher: class_member.teacher
25+
end
2026
end
2127
end

spec/features/class_member/creating_a_batch_of_class_members_spec.rb

Lines changed: 101 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,6 @@
88
let(:school) { create(:school) }
99
let(:students) { create_list(:student, 3, school:) }
1010
let(:teacher) { create(:teacher, school:) }
11-
let(:another_teacher) { create(:teacher, school:) }
12-
13-
let(:params) do
14-
{
15-
class_members: [{ user_id: another_teacher.id, type: 'teacher' }] + students.map { |student| { user_id: student.id, type: 'student' } }
16-
}
17-
end
1811

1912
context 'with valid params' do
2013
let(:student_attributes) do
@@ -23,45 +16,105 @@
2316
end
2417
end
2518

26-
before do
27-
authenticated_in_hydra_as(teacher)
28-
stub_profile_api_list_school_students(school:, student_attributes:)
29-
stub_user_info_api_for(another_teacher)
30-
end
19+
context 'when adding another teacher' do
20+
let(:another_teacher) { create(:teacher, school:) }
21+
let(:params) do
22+
{
23+
class_members: [{ user_id: another_teacher.id, type: 'teacher' }] + students.map { |student| { user_id: student.id, type: 'student' } }
24+
}
25+
end
3126

32-
it 'responds 201 Created' do
33-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
34-
expect(response).to have_http_status(:created)
35-
end
27+
before do
28+
authenticated_in_hydra_as(teacher)
29+
stub_profile_api_list_school_students(school:, student_attributes:)
30+
stub_user_info_api_for(another_teacher)
31+
end
3632

37-
it 'responds 201 Created when the user is a school-teacher' do
38-
authenticated_in_hydra_as(teacher)
33+
it 'responds 201 Created' do
34+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
35+
expect(response).to have_http_status(:created)
36+
end
3937

40-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
41-
expect(response).to have_http_status(:created)
42-
end
38+
it 'responds 201 Created when the user is a school-teacher' do
39+
authenticated_in_hydra_as(teacher)
4340

44-
it 'responds with the class members JSON array' do
45-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
46-
data = JSON.parse(response.body, symbolize_names: true)
47-
expect(data.size).to eq(4)
48-
end
41+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
42+
expect(response).to have_http_status(:created)
43+
end
4944

50-
it 'responds with the class member JSON' do
51-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
52-
data = JSON.parse(response.body, symbolize_names: true)
45+
it 'responds with the class members JSON array' do
46+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
47+
data = JSON.parse(response.body, symbolize_names: true)
48+
expect(data.size).to eq(4)
49+
end
50+
51+
it 'responds with the class member JSON' do
52+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
53+
data = JSON.parse(response.body, symbolize_names: true)
54+
55+
class_member_ids = data.map { |member| member[:student_id] || member[:teacher_id] }
56+
expect(class_member_ids).to eq(params[:class_members].pluck(:user_id))
57+
end
58+
59+
it 'responds with the teacher/student JSON' do
60+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
61+
data = JSON.parse(response.body, symbolize_names: true)
5362

54-
class_member_ids = data.map { |member| member[:student_id] || member[:teacher_id] }
55-
expect(class_member_ids).to eq(params[:class_members].pluck(:user_id))
63+
response_members = data.map { |member| member[:student] || member[:teacher] }
64+
teacher_attributes = [{ id: another_teacher.id, name: another_teacher.name, email: another_teacher.email, type: 'teacher' }]
65+
expect(response_members).to eq(teacher_attributes + student_attributes)
66+
end
5667
end
5768

58-
it 'responds with the teacher/student JSON' do
59-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
60-
data = JSON.parse(response.body, symbolize_names: true)
69+
context 'when adding an owner as another teacher' do
70+
let(:owner_teacher) { create(:teacher, school:, id: create(:owner, school:).id) }
71+
72+
let(:params) do
73+
{
74+
class_members: [{ user_id: owner_teacher.id, type: 'owner' }] + students.map { |student| { user_id: student.id, type: 'student' } }
75+
}
76+
end
77+
78+
before do
79+
authenticated_in_hydra_as(teacher)
80+
stub_profile_api_list_school_students(school:, student_attributes:)
81+
stub_user_info_api_for(owner_teacher)
82+
end
83+
84+
it 'responds 201 Created' do
85+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
86+
expect(response).to have_http_status(:created)
87+
end
88+
89+
it 'responds 201 Created when the user is a school-teacher' do
90+
authenticated_in_hydra_as(teacher)
91+
92+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
93+
expect(response).to have_http_status(:created)
94+
end
95+
96+
it 'responds with the class members JSON array' do
97+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
98+
data = JSON.parse(response.body, symbolize_names: true)
99+
expect(data.size).to eq(4)
100+
end
101+
102+
it 'responds with the class member JSON' do
103+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
104+
data = JSON.parse(response.body, symbolize_names: true)
105+
106+
class_member_ids = data.map { |member| member[:student_id] || member[:teacher_id] }
107+
expect(class_member_ids).to eq(params[:class_members].pluck(:user_id))
108+
end
109+
110+
it 'responds with the teacher/student JSON' do
111+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", headers:, params:)
112+
data = JSON.parse(response.body, symbolize_names: true)
61113

62-
response_members = data.map { |member| member[:student] || member[:teacher] }
63-
teacher_attributes = [{ id: another_teacher.id, name: another_teacher.name, email: another_teacher.email, type: 'teacher' }]
64-
expect(response_members).to eq(teacher_attributes + student_attributes)
114+
response_members = data.map { |member| member[:student] || member[:teacher] || member[:owner] }
115+
teacher_attributes = [{ id: owner_teacher.id, name: owner_teacher.name, email: owner_teacher.email, type: 'owner' }]
116+
expect(response_members).to eq(teacher_attributes + student_attributes)
117+
end
65118
end
66119
end
67120

@@ -95,13 +148,23 @@
95148

96149
expect(data[:error]).to match(/No valid school members provided/)
97150
end
151+
end
152+
153+
context 'when the user is not authorized' do
154+
let(:another_teacher) { create(:teacher, school:) }
155+
let(:params) do
156+
{
157+
class_members: [{ user_id: another_teacher.id, type: 'teacher' }] + students.map { |student| { user_id: student.id, type: 'student' } }
158+
}
159+
end
98160

99161
it 'responds 401 Unauthorized when no token is given' do
100162
post("/api/schools/#{school.id}/classes/#{school_class.id}/members/batch", params:)
101163
expect(response).to have_http_status(:unauthorized)
102164
end
103165

104-
it 'responds 403 Forbidden when the user is a school-owner for a different school' do
166+
it 'responds 403 Forbidden when the user is a teacher from a different school' do
167+
authenticated_in_hydra_as(teacher)
105168
school = create(:school, id: SecureRandom.uuid)
106169
school_class.update!(school_id: school.id)
107170

spec/features/class_member/creating_a_class_member_spec.rb

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,6 @@
88
let(:school) { create(:school) }
99
let(:student) { create(:student, school:, name: 'School Student', username: 'school-student') }
1010
let(:teacher) { create(:teacher, school:) }
11-
let(:another_teacher) { create(:teacher, school:) }
12-
13-
let(:student_params) do
14-
{
15-
class_member: {
16-
user_id: student.id,
17-
type: 'student'
18-
}
19-
}
20-
end
2111

2212
before do
2313
owner = create(:owner, school:)
@@ -27,6 +17,14 @@
2717

2818
context 'with valid params' do
2919
context 'when new class member is a student' do
20+
let(:student_params) do
21+
{
22+
class_member: {
23+
user_id: student.id,
24+
type: 'student'
25+
}
26+
}
27+
end
3028
let(:student_attributes) { { id: student.id, name: student.name, username: student.username, type: 'student' } }
3129

3230
before do
@@ -63,6 +61,7 @@
6361
end
6462

6563
context 'when new class member is a teacher' do
64+
let(:another_teacher) { create(:teacher, school:) }
6665
let(:teacher_params) do
6766
{
6867
class_member: {
@@ -104,13 +103,59 @@
104103
expect(response_teacher).to eq(teacher_attributes)
105104
end
106105
end
106+
107+
context 'when new class member is an owner' do
108+
let(:owner) { create(:owner, school:) }
109+
let(:owner_teacher) { create(:teacher, school:, id: owner.id, name: owner.name, email: owner.email) }
110+
111+
let(:owner_params) do
112+
{
113+
class_member: {
114+
user_id: owner.id,
115+
type: 'owner'
116+
}
117+
}
118+
end
119+
120+
before do
121+
stub_user_info_api_for(owner_teacher)
122+
end
123+
124+
it 'responds 201 Created' do
125+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: owner_params)
126+
expect(response).to have_http_status(:created)
127+
end
128+
129+
it 'responds 201 Created when the user is a school-teacher' do
130+
authenticated_in_hydra_as(teacher)
131+
132+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: owner_params)
133+
expect(response).to have_http_status(:created)
134+
end
135+
136+
it 'responds with the class member JSON' do
137+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: owner_params)
138+
data = JSON.parse(response.body, symbolize_names: true)
139+
140+
expect(data[:class_member][:teacher_id]).to eq(owner.id)
141+
end
142+
143+
it 'responds with the teacher JSON' do
144+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: owner_params)
145+
data = JSON.parse(response.body, symbolize_names: true)
146+
147+
response_teacher = data[:class_member][:owner]
148+
owner_attributes = { id: owner.id, name: owner.name, email: owner.email, type: 'owner' }
149+
expect(response_teacher).to eq(owner_attributes)
150+
end
151+
end
107152
end
108153

109154
context 'with invalid params' do
110155
let(:invalid_params) { { class_member: { user_id: SecureRandom.uuid } } }
111156

112157
before do
113-
stub_profile_api_list_school_students(school:, student_attributes: [])
158+
stub_user_info_api_for_unknown_users(user_id: invalid_params[:class_member][:user_id])
114159
end
115160

116161
it 'responds 400 Bad Request when params are missing' do
@@ -129,34 +174,45 @@
129174

130175
expect(data[:error]).to match(/No valid school members provided/)
131176
end
177+
end
178+
179+
context 'when the user is not authorized' do
180+
let(:student_params) do
181+
{
182+
class_member: {
183+
user_id: student.id,
184+
type: 'student'
185+
}
186+
}
187+
end
132188

133189
it 'responds 401 Unauthorized when no token is given' do
134190
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", params: student_params)
135191
expect(response).to have_http_status(:unauthorized)
136192
end
137-
end
138193

139-
it 'responds 403 Forbidden when the user is a school-owner for a different school' do
140-
school = create(:school, id: SecureRandom.uuid)
141-
school_class.update!(school_id: school.id)
194+
it 'responds 403 Forbidden when the user is a school-owner for a different school' do
195+
school = create(:school, id: SecureRandom.uuid)
196+
school_class.update!(school_id: school.id)
142197

143-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: student_params)
144-
expect(response).to have_http_status(:forbidden)
145-
end
198+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: student_params)
199+
expect(response).to have_http_status(:forbidden)
200+
end
146201

147-
it 'responds 403 Forbidden when the user is not the school-teacher for the class' do
148-
teacher = create(:teacher, school:)
149-
authenticated_in_hydra_as(teacher)
202+
it 'responds 403 Forbidden when the user is not the school-teacher for the class' do
203+
teacher = create(:teacher, school:)
204+
authenticated_in_hydra_as(teacher)
150205

151-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: student_params)
152-
expect(response).to have_http_status(:forbidden)
153-
end
206+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: student_params)
207+
expect(response).to have_http_status(:forbidden)
208+
end
154209

155-
it 'responds 403 Forbidden when the user is a school-student' do
156-
student = create(:student, school:)
157-
authenticated_in_hydra_as(student)
210+
it 'responds 403 Forbidden when the user is a school-student' do
211+
student = create(:student, school:)
212+
authenticated_in_hydra_as(student)
158213

159-
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: student_params)
160-
expect(response).to have_http_status(:forbidden)
214+
post("/api/schools/#{school.id}/classes/#{school_class.id}/members", headers:, params: student_params)
215+
expect(response).to have_http_status(:forbidden)
216+
end
161217
end
162218
end

0 commit comments

Comments
 (0)