Skip to content

Commit ed4cc05

Browse files
authored
Merge pull request #1878 from openstax/role_id_urls
Replace become API with (/role/:role_id) or ?role_id= in URLs that use it
2 parents 59fd8a7 + 46b138a commit ed4cc05

File tree

63 files changed

+900
-912
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+900
-912
lines changed

app/access_policies/note_access_policy.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ def self.action_allowed?(action, requestor, note)
33
return false unless note.present? && requestor.is_human?
44

55
case action.to_sym
6-
when :index, :read
6+
when :index
77
true
88
when :create, :update, :destroy
99
note.role.user_profile_id == requestor.id

app/access_policies/teacher_student_access_policy.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ def self.action_allowed?(action, requestor, teacher_student)
44

55
case action
66
when :show
7-
teacher_student.role.user_profile_id == requestor.id &&
8-
UserIsCourseTeacher[user: requestor, course: teacher_student.course] &&
9-
!teacher_student.deleted? &&
7+
UserIsCourseTeacher[user: requestor, course: teacher_student.course] &&
108
!teacher_student.period.nil? &&
119
!teacher_student.period.archived?
1210
else
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
module Admin
22
class SalesforceController < BaseController
3-
def actions
3+
def show
44
end
55

6-
def update_salesforce
6+
def update
77
outputs = PushSalesforceCourseStats.call(allow_error_email: true)
88

99
flash[:notice] = "Ran on #{outputs[:num_courses]} course(s); " +
1010
"updated #{outputs[:num_updates]} course(s); " +
1111
"#{outputs[:num_errors]} error(s) occurred; " +
1212
"#{outputs[:num_skips]} skip(s)"
1313

14-
redirect_to actions_admin_salesforce_path
14+
redirect_to admin_salesforce_path
1515
end
1616
end
1717
end

app/controllers/admin/students_controller.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ def update
2121
end
2222
end
2323

24-
def refund
24+
def destroy
2525
student = CourseMembership::Models::Student.find(params[:id])
26-
RefundPayment[uuid: student.uuid]
27-
redirect_to edit_admin_course_path(student.course, anchor: "roster")
26+
CourseMembership::InactivateStudent[student: student]
27+
redirect_to edit_admin_course_path(student.course) + '#roster'
2828
end
2929

30-
def drop
30+
def refund
3131
student = CourseMembership::Models::Student.find(params[:id])
32-
CourseMembership::InactivateStudent[student: student]
33-
redirect_to edit_admin_course_path(student.course) + '#roster'
32+
RefundPayment[uuid: student.uuid]
33+
redirect_to edit_admin_course_path(student.course, anchor: "roster")
3434
end
3535

3636
def restore

app/controllers/admin/targeted_contracts_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class Admin::TargetedContractsController < Admin::BaseController
22

3-
before_action :load_district_targets, only: [:new]
3+
before_action :load_district_targets, only: :new
44

55
def index
66
@contracts = Legal::GetTargetedContracts[]

app/controllers/admin/teachers_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ def teachers
1515
redirect_to edit_admin_course_path(course, anchor: 'teachers')
1616
end
1717

18-
def delete
18+
def destroy
1919
teacher = CourseMembership::Models::Teacher.find(params[:id])
2020
teacher.destroy
2121
flash[:notice] = "Teacher \"#{teacher.role.name}\" removed from course."
2222
redirect_to edit_admin_course_path(teacher.course, anchor: 'teachers')
2323
end
2424

25-
def undelete
25+
def restore
2626
teacher = CourseMembership::Models::Teacher.find(params[:id])
2727
teacher.restore
2828
flash[:notice] = "Teacher \"#{teacher.role.name}\" readded to course."

app/controllers/admin/users_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Admin::UsersController < Admin::BaseController
22
include Manager::SearchUsers
33

4-
before_action :get_user, only: [:edit, :update, :become]
4+
before_action :get_user, only: [ :edit, :update, :become ]
55

66
def create
77
handle_with(

app/controllers/api/v1/courses_controller.rb

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ class Api::V1::CoursesController < Api::V1::ApiController
33
:name, :is_preview, :num_sections, :catalog_offering_id
44
]
55

6-
before_action :get_course, only: [:show, :update, :dashboard, :cc_dashboard, :roster, :clone]
7-
before_action :error_if_student_and_needs_to_pay, only: [:dashboard]
6+
before_action :get_course, only: [ :show, :update, :dashboard, :cc_dashboard, :roster, :clone ]
7+
before_action :error_if_student_and_needs_to_pay, only: :dashboard
88

99
resource_description do
1010
api_versions "v1"
@@ -16,20 +16,16 @@ class Api::V1::CoursesController < Api::V1::ApiController
1616

1717
api :GET, '/courses', 'Returns courses'
1818
description <<-EOS
19-
Returns courses in the system, and the user who requested them is shown
20-
their own roles related to their courses
19+
Returns courses in the system,
20+
and the user who requested them is shown their own roles in each course
2121
#{json_schema(Api::V1::CoursesRepresenter, include: :readable)}
2222
EOS
2323
def index
2424
OSU::AccessPolicy.require_action_allowed!(
2525
:index, current_api_user, CourseProfile::Models::Course
2626
)
2727

28-
course_infos = CollectCourseInfo[
29-
user: current_human_user, current_roles_hash: current_roles_hash
30-
]
31-
32-
respond_with course_infos, represent_with: Api::V1::CoursesRepresenter
28+
respond_with collect_course_info, represent_with: Api::V1::CoursesRepresenter
3329
end
3430

3531
api :POST, '/courses', 'Creates a new course'
@@ -236,15 +232,20 @@ def get_course
236232
@course = CourseProfile::Models::Course.find(params[:id])
237233
end
238234

239-
def collect_course_info(course:)
240-
CollectCourseInfo[
241-
courses: course, user: current_human_user, current_roles_hash: current_roles_hash
242-
].first
235+
def collect_course_info(course: nil)
236+
args = { user: current_human_user }
237+
238+
if course.nil?
239+
CollectCourseInfo[args]
240+
else
241+
args[:courses] = course
242+
CollectCourseInfo[args].first
243+
end
243244
end
244245

245246
def get_course_role(course:)
246247
result = ChooseCourseRole.call(
247-
user: current_human_user, course: course, current_roles_hash: current_roles_hash
248+
user: current_human_user, course: course, role_id: params[:role_id]
248249
)
249250
errors = result.errors
250251
raise(SecurityTransgression, :invalid_role) unless errors.empty?

app/controllers/api/v1/guides_controller.rb

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,21 @@ class GuidesController < ApiController
1818
#{json_schema(Api::V1::CourseGuidePeriodRepresenter, include: :readable)}
1919
EOS
2020
def student
21+
# We don't use the get_course_role method when a role_id is given
22+
# because we allow teachers to look at any student's performance forecast
23+
# not just their own roles'
24+
# We trust the AccessPolicy for access control in this case
2125
role = if params[:role_id].blank?
22-
get_course_role(course: @course, allowed_role_types: [:student, :teacher_student])
26+
get_course_role(course: @course, allowed_role_types: [ :student, :teacher_student ])
2327
else
2428
Entity::Role.where(
2529
role_type: Entity::Role.role_types.values_at(:student, :teacher_student)
2630
).find(params[:role_id])
2731
end
2832

29-
student = role.course_member
30-
31-
OSU::AccessPolicy.require_action_allowed!(:show, current_api_user, student)
33+
OSU::AccessPolicy.require_action_allowed!(:show, current_api_user, role.course_member)
3234

3335
guide = GetStudentGuide[role: role]
34-
3536
respond_with guide, represent_with: Api::V1::CourseGuidePeriodRepresenter
3637
end
3738

@@ -42,7 +43,9 @@ def student
4243
EOS
4344
def teacher
4445
role = get_course_role(course: @course, allowed_role_types: :teacher)
46+
4547
OSU::AccessPolicy.require_action_allowed!(:show, current_api_user, role.teacher)
48+
4649
guide = GetTeacherGuide[role: role]
4750
respond_with guide, represent_with: Api::V1::TeacherCourseGuideRepresenter
4851
end
@@ -56,10 +59,9 @@ def get_course
5659
def get_course_role(course:, allowed_role_types:)
5760
result = ChooseCourseRole.call(
5861
user: current_human_user, course: course,
59-
current_roles_hash: current_roles_hash, allowed_role_types: allowed_role_types
62+
role_id: params[:role_id], allowed_role_types: allowed_role_types
6063
)
61-
errors = result.errors
62-
raise(SecurityTransgression, :invalid_role) unless errors.empty?
64+
raise(SecurityTransgression, :invalid_role) unless result.errors.empty?
6365
result.outputs.role
6466
end
6567
end
Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,53 @@
11
# coding: utf-8
22
class Api::V1::NotesController < Api::V1::ApiController
33

4-
before_action :get_course_role
5-
before_action :get_note, only: [:update, :destroy]
4+
before_action :get_course, except: [ :update, :destroy ]
5+
before_action :get_user_roles_and_page_uuid, only: [ :index, :highlighted_sections ]
6+
before_action :choose_course_role, only: :create
7+
before_action :get_note, only: [ :update, :destroy ]
68

79
resource_description do
810
api_versions "v1"
911
short_description 'Represents a note added by the student on a course'
1012
description <<-EOS
11-
Stores text selection (notes) on a course’s content. Notes are generated
12-
by users as they highlight content, and then are fetched and re-stored when
13-
the content is reloaded.
13+
Stores text selection (notes) on a course’s content.
14+
Notes are generated by users as they highlight content,
15+
and then are fetched and re-stored when the content is reloaded.
1416
EOS
1517
end
1618

1719
####################################################################
1820
## index ##
1921
####################################################################
20-
api :GET, '/api/courses/:course_id/notes/:chapter.:section', 'Lists all user notes for the given course/page/section'
22+
api :GET, '/api/courses/:course_id/notes/:chapter.:section', 'Lists all notes'
2123
description <<-EOS
22-
list all the notes added by the student to the given course, page and section
24+
Lists all the notes added by the student to the given course, page and section
25+
2326
#{json_schema(Api::V1::NotesRepresenter, include: :readable)}
2427
EOS
2528
def index
26-
page_ids = Content::Models::Page
27-
.joins(:notes)
28-
.where(notes: { role: @role })
29-
.book_location(params[:chapter], params[:section])
30-
.pluck(:id)
31-
notes = Content::Models::Note.where(role: @role, content_page_id: page_ids)
29+
notes = Content::Models::Note.joins(:page).where(role: @roles, page: { uuid: @page_uuid })
3230
respond_with notes, represent_with: Api::V1::NotesRepresenter
3331
end
3432

35-
###############################################################
36-
# post
37-
###############################################################
38-
api :POST, '/api/courses/:course_id/notes/:chapter.:section', 'Creates a Note'
33+
####################################################################
34+
## create ##
35+
####################################################################
36+
api :POST, '/api/courses/:course_id/notes/:chapter.:section(/role/:role_id)', 'Creates a note'
3937
description <<-EOS
40-
Create a new note for the given course, chapter and section
38+
Creates a new note for the given course, chapter and section
39+
4140
#{json_schema(Api::V1::NoteRepresenter, include: :readable)}
4241
EOS
4342
def create
4443
note = Content::Models::Note.new(role: @role, content_page_id: params[:page_id])
4544
consume!(note, represent_with: Api::V1::NoteRepresenter)
4645
OSU::AccessPolicy.require_action_allowed!(:create, current_api_user, note)
47-
note.page = @course.ecosystem.pages.book_location(
48-
params[:chapter], params[:section],
49-
).first!
46+
note.page = @course.ecosystem.pages.book_location(params[:chapter], params[:section]).first!
5047
if note.save
5148
respond_with note, responder: ResponderWithPutPatchDeleteContent,
52-
represent_with: Api::V1::NoteRepresenter,
53-
location: nil
49+
represent_with: Api::V1::NoteRepresenter,
50+
location: nil
5451
else
5552
render_api_errors(note.errors)
5653
end
@@ -59,9 +56,10 @@ def create
5956
####################################################################
6057
## update ##
6158
####################################################################
62-
api :PUT, '/api/courses/:course_id/notes/:chapter.:section/:id', 'Updates a Note'
59+
api :PUT, '/api/courses/:course_id/notes/:chapter.:section/:id', 'Updates a note'
6360
description <<-EOS
64-
Updates a note for the given course, chapter, section and id
61+
Updates the note with the given id
62+
6563
#{json_schema(Api::V1::NoteRepresenter, include: :readable)}
6664
EOS
6765
def update
@@ -77,50 +75,60 @@ def update
7775
end
7876

7977
####################################################################
80-
## delete ##
78+
## destroy ##
8179
####################################################################
82-
api :DELETE, '/api/courses/:course_id/notes/:chapter.:section/:id', 'Deletes the note from the students course'
80+
api :DELETE, '/api/courses/:course_id/notes/:chapter.:section/:id', 'Deletes a note'
8381
description <<-EOS
84-
Deletes the note from the student's course with the provided :id
82+
Deletes the note with the given id
8583
EOS
8684
def destroy
8785
OSU::AccessPolicy.require_action_allowed!(:destroy, current_api_user, @note)
88-
@note.destroy!
86+
@note.destroy
8987
render_api_errors(@note.errors) || head(:ok)
9088
end
9189

92-
api :GET, '/api/courses/:course_id/highlighted_sections', 'Lists a notes summary from the students course'
90+
####################################################################
91+
## highlighted_sections ##
92+
####################################################################
93+
api :GET, '/api/courses/:course_id/highlighted_sections',
94+
'Shows a summary of sections highlighted by the student'
9395
description <<-EOS
94-
list all the notes added by the student to a course
96+
List all sections highlighted by the student
97+
9598
#{json_schema(Api::V1::HighlightRepresenter, include: :readable)}
9699
EOS
97100
def highlighted_sections
98-
pages = Content::Models::Page
99-
.select('content_pages.id, content_pages.title, content_pages.book_location, count(*) as notes_count')
100-
.group(:id)
101-
.joins(:notes)
102-
.where(notes: { role: @role })
101+
pages = Content::Models::Page.select(:id, :title, :book_location, 'count(*) as notes_count')
102+
.joins(:notes)
103+
.where(uuid: @page_uuid, notes: { role: @roles })
104+
.group(:id)
103105
respond_with pages, represent_with: Api::V1::HighlightRepresenter
104106
end
105107

106108
protected
107109

108-
def get_note
109-
@note = Content::Models::Note.find_by(
110-
id: params[:id], role: @role
111-
)
110+
def get_course
111+
@course = CourseProfile::Models::Course.find(params[:course_id])
112112
end
113113

114-
def get_course_role
115-
@course = CourseProfile::Models::Course.find(params[:course_id])
114+
def get_user_roles_and_page_uuid
115+
@roles = current_human_user.roles
116+
@page_uuid = @course.ecosystem.pages.book_location(params[:chapter], params[:section])
117+
.pluck(:uuid)
118+
.first || raise(ActiveRecord::RecordNotFound)
119+
end
116120

121+
def choose_course_role
117122
result = ChooseCourseRole.call(
118-
user: current_human_user, course: @course, current_roles_hash: current_roles_hash
123+
user: current_human_user, course: @course, role_id: params[:role_id]
119124
)
120-
errors = result.errors
121-
raise(SecurityTransgression, :invalid_role) unless errors.empty?
125+
raise(SecurityTransgression, :invalid_role) unless result.errors.empty?
122126

123127
@role = result.outputs.role
124128
end
125129

130+
def get_note
131+
@note = Content::Models::Note.find(params[:id])
132+
end
133+
126134
end

0 commit comments

Comments
 (0)