Skip to content

Commit 494b434

Browse files
authored
Reduce logged in students abilities (#427)
## Status - Related to https://github.com/RaspberryPiFoundation/editor-standalone/issues/335 ## What's changed? - Ensure from an API perspective students are unable to perform project/component calls that aren't assigned to a school (i.e. only assigned to their `user_id`) - Remove capability to create a school or lesson - Slight abilities refactor for readability Limitations are in place on the frontend but this change ensures its also not possible from the backend too
1 parent b733226 commit 494b434

File tree

4 files changed

+67
-19
lines changed

4 files changed

+67
-19
lines changed

app/models/ability.rb

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,34 @@ class Ability
44
include CanCan::Ability
55

66
def initialize(user)
7-
# Anyone can view projects not owner by a user or a school.
7+
define_common_non_student_abilities(user)
8+
9+
return unless user
10+
11+
define_authenticated_non_student_abilities(user)
12+
13+
user.schools.each do |school|
14+
define_school_student_abilities(user:, school:) if user.school_student?(school)
15+
define_school_teacher_abilities(user:, school:) if user.school_teacher?(school)
16+
define_school_owner_abilities(school:) if user.school_owner?(school)
17+
end
18+
end
19+
20+
private
21+
22+
def define_common_non_student_abilities(user)
23+
return if user&.student?
24+
25+
# Anyone can view projects not owned by a user or a school.
826
can :show, Project, user_id: nil, school_id: nil
927
can :show, Component, project: { user_id: nil, school_id: nil }
1028

1129
# Anyone can read publicly shared lessons.
1230
can :read, Lesson, visibility: 'public'
31+
end
1332

14-
return unless user
15-
16-
# Any authenticated user can create projects not owned by a school.
17-
can :create, Project, user_id: user.id, school_id: nil
18-
can :create, Component, project: { user_id: user.id, school_id: nil }
19-
20-
# Any authenticated user can manage their own projects.
21-
can %i[read update destroy], Project, user_id: user.id
22-
can %i[read update destroy], Component, project: { user_id: user.id }
33+
def define_authenticated_non_student_abilities(user)
34+
return if user&.student?
2335

2436
# Any authenticated user can create a school. They agree to become the school-owner.
2537
can :create, School
@@ -34,16 +46,16 @@ def initialize(user)
3446
can :create_copy, Lesson, visibility: 'public'
3547

3648
# Any authenticated user can manage their own lessons.
37-
can %i[read create_copy update destroy], Lesson, user_id: user.id
49+
can %i[read create_copy update destroy], Lesson, user_id: user.id, school_id: nil
3850

39-
user.schools.each do |school|
40-
define_school_student_abilities(user:, school:) if user.school_student?(school)
41-
define_school_teacher_abilities(user:, school:) if user.school_teacher?(school)
42-
define_school_owner_abilities(school:) if user.school_owner?(school)
43-
end
44-
end
51+
# Any authenticated user can create projects not owned by a school.
52+
can :create, Project, user_id: user.id, school_id: nil
53+
can :create, Component, project: { user_id: user.id, school_id: nil }
4554

46-
private
55+
# Any authenticated user can manage their own projects.
56+
can %i[read update destroy], Project, user_id: user.id
57+
can %i[read update destroy], Component, project: { user_id: user.id }
58+
end
4759

4860
def define_school_owner_abilities(school:)
4961
can(%i[read update destroy], School, id: school.id)
@@ -69,7 +81,7 @@ def define_school_teacher_abilities(user:, school:)
6981
can(%i[read], :school_owner)
7082
can(%i[read], :school_teacher)
7183
can(%i[read create create_batch update], :school_student)
72-
can(%i[create destroy], Lesson) do |lesson|
84+
can(%i[create update destroy], Lesson) do |lesson|
7385
school_teacher_can_manage_lesson?(user:, school:, lesson:)
7486
end
7587
can(%i[read create_copy], Lesson, school_id: school.id, visibility: %w[teachers students])

app/models/user.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ def school_student?(school)
4646
Role.student.find_by(school:, user_id: id)
4747
end
4848

49+
def student?
50+
Role.student.exists?(user_id: id)
51+
end
52+
4953
def admin?
5054
(roles&.to_s&.split(',')&.map(&:strip) || []).include?('editor-admin')
5155
end

spec/models/ability_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,22 @@
245245
it { is_expected.to be_able_to(:read, school) }
246246
it { is_expected.not_to be_able_to(:update, school) }
247247
it { is_expected.not_to be_able_to(:destroy, school) }
248+
249+
context 'with a starter project' do
250+
it { is_expected.not_to be_able_to(:index, starter_project) }
251+
it { is_expected.not_to be_able_to(:show, starter_project) }
252+
it { is_expected.not_to be_able_to(:create, starter_project) }
253+
it { is_expected.not_to be_able_to(:update, starter_project) }
254+
it { is_expected.not_to be_able_to(:destroy, starter_project) }
255+
end
256+
257+
context 'with an owned project' do
258+
it { is_expected.not_to be_able_to(:index, project) }
259+
it { is_expected.not_to be_able_to(:show, project) }
260+
it { is_expected.not_to be_able_to(:create, project) }
261+
it { is_expected.not_to be_able_to(:update, project) }
262+
it { is_expected.not_to be_able_to(:destroy, project) }
263+
end
248264
end
249265
end
250266

spec/models/user_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,22 @@
261261
end
262262
end
263263

264+
describe '#student?' do
265+
subject(:user) { create(:user) }
266+
267+
let(:school) { create(:school) }
268+
269+
it 'returns true when the user has a student role' do
270+
create(:student_role, school:, user_id: user.id)
271+
expect(user).to be_student
272+
end
273+
274+
it 'returns false when the user does not have a student role' do
275+
create(:owner_role, school:, user_id: user.id)
276+
expect(user).not_to be_student
277+
end
278+
end
279+
264280
describe '#admin?' do
265281
it 'returns true if the user has the editor-admin role in Hydra' do
266282
user = build(:user, roles: 'editor-admin')

0 commit comments

Comments
 (0)