-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathability.rb
More file actions
132 lines (105 loc) · 5.98 KB
/
ability.rb
File metadata and controls
132 lines (105 loc) · 5.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# frozen_string_literal: true
class Ability
include CanCan::Ability
def initialize(user)
define_common_non_student_abilities(user)
return unless user
define_authenticated_non_student_abilities(user)
user.schools.each do |school|
define_school_student_abilities(user:, school:) if user.school_student?(school)
define_school_teacher_abilities(user:, school:) if user.school_teacher?(school)
define_school_owner_abilities(school:) if user.school_owner?(school)
end
define_experience_cs_admin_abilities(user)
end
private
def define_common_non_student_abilities(user)
return if user&.student?
# Anyone can view projects not owned by a user or a school.
can :show, Project, user_id: nil, school_id: nil
can :show, Component, project: { user_id: nil, school_id: nil }
# Anyone can read publicly shared lessons.
can :read, Lesson, visibility: 'public'
end
def define_authenticated_non_student_abilities(user)
return if user&.student?
# Any authenticated user can create a school. They agree to become the school-owner.
can :create, School
# An unverified school owner can read their own school.
can :read, School, creator_id: user.id, verified_at: nil
# Any authenticated user can create a lesson, to support a RPF library of public lessons.
can :create, Lesson, school_id: nil, school_class_id: nil
# Any authenticated user can create a copy of a publicly shared lesson.
can :create_copy, Lesson, visibility: 'public'
# Any authenticated user can manage their own lessons.
can %i[read create_copy update destroy], Lesson, user_id: user.id, school_id: nil
# Any authenticated user can create projects not owned by a school.
can :create, Project, user_id: user.id, school_id: nil
can :create, Component, project: { user_id: user.id, school_id: nil }
# Any authenticated user can manage their own projects.
can %i[read update destroy], Project, user_id: user.id
can %i[read update destroy], Component, project: { user_id: user.id }
end
def define_school_owner_abilities(school:)
can(%i[read update destroy], School, id: school.id)
can(%i[read], :school_member)
can(%i[read create update destroy], SchoolClass, school: { id: school.id })
can(%i[read show_context], Project, school_id: school.id, lesson: { visibility: %w[teachers students] })
can(%i[read create create_batch destroy], ClassStudent, school_class: { school: { id: school.id } })
can(%i[read create destroy], :school_owner)
can(%i[read create destroy], :school_teacher)
can(%i[read create create_batch update destroy], :school_student)
can(%i[create create_copy], Lesson, school_id: school.id)
can(%i[read update destroy], Lesson, school_id: school.id, visibility: %w[teachers students public])
end
def define_school_teacher_abilities(user:, school:)
can(%i[read], School, id: school.id)
can(%i[read], :school_member)
can(%i[create], SchoolClass, school: { id: school.id })
can(%i[read update destroy], SchoolClass, school: { id: school.id }, teachers: { teacher_id: user.id })
can(%i[read create create_batch destroy], ClassStudent, school_class: { school: { id: school.id }, teachers: { teacher_id: user.id } })
can(%i[read], :school_owner)
can(%i[read], :school_teacher)
can(%i[read create create_batch update], :school_student)
can(%i[create update destroy], Lesson) do |lesson|
school_teacher_can_manage_lesson?(user:, school:, lesson:)
end
can(%i[remix], Lesson) do |lesson|
school_teacher_can_remix_lesson?(user:, school:, lesson:)
end
can(%i[read create_copy], Lesson, school_id: school.id, visibility: %w[teachers students])
can(%i[create], Project) do |project|
school_teacher_can_manage_project?(user:, school:, project:)
end
can(%i[read update show_context], Project, school_id: school.id, lesson: { visibility: %w[teachers students] })
can(%i[read], Project,
remixed_from_id: Project.where(school_id: school.id, lesson_id: Lesson.where(school_class_id: ClassTeacher.where(teacher_id: user.id).select(:school_class_id))).pluck(:id))
end
def define_school_student_abilities(user:, school:)
can(%i[read], School, id: school.id)
can(%i[read], SchoolClass, school: { id: school.id }, students: { student_id: user.id })
# Ensure no access to ClassMember resources, relationships otherwise allow access in some circumstances.
can(%i[read], Lesson, school_id: school.id, visibility: 'students', school_class: { students: { student_id: user.id } })
can(%i[read create update], Project, school_id: school.id, user_id: user.id, lesson_id: nil, remixed_from_id: Project.where(school_id: school.id, lesson_id: Lesson.where(visibility: 'students').select(:id)).pluck(:id))
can(%i[read show_context], Project, lesson: { school_id: school.id, visibility: 'students', school_class: { students: { student_id: user.id } } })
can(%i[show_finished set_finished], SchoolProject, project: { user_id: user.id, lesson_id: nil }, school_id: school.id)
end
def define_experience_cs_admin_abilities(user)
return unless user&.experience_cs_admin?
can %i[read create update destroy], Project, user_id: nil
end
def school_teacher_can_manage_lesson?(user:, school:, lesson:)
is_my_lesson = lesson.school_id == school.id && lesson.user_id == user.id
is_my_class = lesson.school_class&.teacher_ids&.include?(user.id)
is_my_class || (is_my_lesson && !lesson.school_class)
end
def school_teacher_can_manage_project?(user:, school:, project:)
is_my_project = project.school_id == school.id && project.user_id == user.id
is_my_lesson = project.lesson && project.lesson.user_id == user.id
is_my_project && (is_my_lesson || !project.lesson)
end
def school_teacher_can_remix_lesson?(user:, school:, lesson:)
original_project_is_public = Project.find(lesson.project.remixed_from_id).user_id.nil?
school_teacher_can_manage_lesson?(user:, school:, lesson:) && original_project_is_public
end
end