-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathability.rb
More file actions
157 lines (127 loc) · 6.82 KB
/
ability.rb
File metadata and controls
157 lines (127 loc) · 6.82 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# 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_editor_admin_abilities(user)
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 import update destroy regenerate_join_code], 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 destroy_batch], :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])
can(%i[read destroy], Feedback, school_project: { school_id: school.id })
can(%i[exchange_code], :google_auth)
end
def define_school_teacher_abilities(user:, school:)
can(%i[read], School, id: school.id)
can(%i[read], :school_member)
can(%i[create import], SchoolClass, school: { id: school.id })
can(%i[read update destroy regenerate_join_code], 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[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] })
teacher_project_ids = Project.where(
school_id: school.id,
remixed_from_id: nil,
lesson_id: Lesson.where(
school_class_id: ClassTeacher.where(teacher_id: user.id).select(:school_class_id)
)
).pluck(:id)
can(%i[read], Project, remixed_from_id: teacher_project_ids)
can(%i[show_status unsubmit return complete], SchoolProject, project: { remixed_from_id: teacher_project_ids })
can(%i[read create destroy], Feedback, school_project: { project: { remixed_from_id: teacher_project_ids } })
can(%i[exchange_code], :google_auth)
end
def define_school_student_abilities(user:, school:)
visible_lesson_project_ids = Project.where(
school_id: school.id,
lesson_id: Lesson.where(
visibility: 'students'
).select(:id)
).pluck(:id)
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: visible_lesson_project_ids)
can(%i[read show_context], Project, lesson: { school_id: school.id, visibility: 'students', school_class: { students: { student_id: user.id } } })
can(%i[read set_read], Feedback, school_project: { project: { school_id: school.id, user_id: user.id, lesson_id: nil, remixed_from_id: visible_lesson_project_ids } })
can(%i[show_finished set_finished show_status unsubmit submit], SchoolProject, project: { user_id: user.id, lesson_id: nil }, school_id: school.id)
end
def define_school_import_abilities(user)
return unless user&.admin? || user&.experience_cs_admin?
can :import, School
can :read, :school_import_job
end
def define_editor_admin_abilities(user)
return unless user&.admin?
define_school_import_abilities(user)
end
def define_experience_cs_admin_abilities(user)
return unless user&.experience_cs_admin?
can %i[read create update destroy], Project, user_id: nil
define_school_import_abilities(user)
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
end