Skip to content

Commit 9dd0be3

Browse files
authored
Merge pull request #335 from cs169/mass-approve
Mass approve/ reject functionality and UI changes for request table PR reviewed and merged into Golden Repo. Thank you!
2 parents 41d5d73 + 4f0f627 commit 9dd0be3

8 files changed

Lines changed: 777 additions & 194 deletions

File tree

app/controllers/requests_controller.rb

Lines changed: 121 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class RequestsController < ApplicationController
1111
before_action :check_extensions_enabled_for_students, except: [ :export ]
1212
before_action :ensure_request_is_pending, only: %i[update approve reject]
1313
before_action :set_request, only: %i[show edit cancel]
14-
before_action :check_instructor_permission, only: %i[approve reject]
14+
before_action :check_instructor_permission, only: %i[approve reject mass_approve mass_reject]
1515

1616
def index
1717
@side_nav = 'requests'
@@ -137,21 +137,44 @@ def approve
137137
@assignment = Assignment.find_by(id: @request.assignment_id)
138138
lms_facade = @assignment.lms_facade
139139
if @request.approve(lms_facade.from_user(@user), @user)
140-
redirect_to course_requests_path(@course), notice: 'Request approved and extension created successfully in Canvas.'
140+
notice = 'Request approved and extension created successfully in Canvas.'
141+
respond_to do |format|
142+
format.html { redirect_to course_requests_path(@course), notice: notice }
143+
format.json { render json: { success: true, message: notice, new_status: 'approved', pending_count: @course.requests.where(status: 'pending').count } }
144+
end
141145
else
142-
flash[:alert] = "Failed to approve the request. #{@request.errors.full_messages.join(', ')}"
143-
redirect_to course_requests_path(@course)
146+
alert = "Failed to approve the request. #{@request.errors.full_messages.join(', ')}"
147+
respond_to do |format|
148+
format.html { flash[:alert] = alert; redirect_to course_requests_path(@course) }
149+
format.json { render json: { success: false, message: alert }, status: :unprocessable_content }
150+
end
144151
end
145152
end
146153

147154
def reject
148155
if @request.reject(@user)
149-
redirect_to course_requests_path(@course), notice: 'Request denied successfully.'
156+
notice = 'Request denied successfully.'
157+
respond_to do |format|
158+
format.html { redirect_to course_requests_path(@course), notice: notice }
159+
format.json { render json: { success: true, message: notice, new_status: 'denied', pending_count: @course.requests.where(status: 'pending').count } }
160+
end
150161
else
151-
redirect_to course_requests_path(@course), alert: 'Failed to deny the request.'
162+
alert = 'Failed to deny the request.'
163+
respond_to do |format|
164+
format.html { redirect_to course_requests_path(@course), alert: alert }
165+
format.json { render json: { success: false, message: alert }, status: :unprocessable_content }
166+
end
152167
end
153168
end
154169

170+
def mass_approve
171+
process_mass_action(:approve)
172+
end
173+
174+
def mass_reject
175+
process_mass_action(:reject)
176+
end
177+
155178
def export
156179
course = Course.find_by(id: params[:course_id])
157180
token = params[:readonly_api_token]
@@ -258,5 +281,97 @@ def handle_successful_student_request(student)
258281
result = @request.process_created_request(@user)
259282
redirect_to result[:redirect_to], notice: "Request created for #{student.name}. #{result[:notice]}"
260283
end
284+
285+
def process_mass_action(action)
286+
request_ids = mass_request_ids
287+
if request_ids.empty?
288+
return render_mass_action_response(
289+
success: false,
290+
message: 'Please select at least one request.',
291+
processed_ids: [],
292+
failed_ids: [],
293+
new_status: action == :approve ? 'approved' : 'denied',
294+
status: :unprocessable_content
295+
)
296+
end
297+
298+
requests = @course.requests.where(id: request_ids, status: 'pending').includes(:assignment)
299+
300+
if requests.empty?
301+
return render_mass_action_response(
302+
success: false,
303+
message: 'No pending requests were found for the selected rows.',
304+
processed_ids: [],
305+
failed_ids: request_ids,
306+
new_status: action == :approve ? 'approved' : 'denied',
307+
status: :unprocessable_content
308+
)
309+
end
310+
311+
processed_ids = []
312+
failed_ids = request_ids - requests.map(&:id)
313+
314+
requests.each do |request|
315+
result = action == :approve ? approve_request_for_mass_action(request) : request.reject(@user)
316+
result ? processed_ids << request.id : failed_ids << request.id
317+
end
318+
319+
processed_count = processed_ids.size
320+
failed_count = failed_ids.size
321+
action_label = action == :approve ? 'approved' : 'denied'
322+
message =
323+
if failed_count.zero?
324+
"#{processed_count} request#{'s' unless processed_count == 1} #{action_label} successfully."
325+
else
326+
"#{processed_count} request#{'s' unless processed_count == 1} #{action_label}. "\
327+
"#{failed_count} failed."
328+
end
329+
330+
render_mass_action_response(
331+
success: processed_count.positive?,
332+
message: message,
333+
processed_ids: processed_ids,
334+
failed_ids: failed_ids,
335+
new_status: action_label,
336+
status: processed_count.positive? ? :ok : :unprocessable_content
337+
)
338+
end
339+
340+
def render_mass_action_response(success:, message:, processed_ids:, failed_ids:, new_status:, status:)
341+
pending_count = @course.requests.where(status: 'pending').count
342+
respond_to do |format|
343+
format.html do
344+
if success
345+
redirect_to course_requests_path(@course), notice: message
346+
else
347+
redirect_to course_requests_path(@course), alert: message
348+
end
349+
end
350+
format.json do
351+
render json: {
352+
success: success,
353+
message: message,
354+
processed_ids: processed_ids,
355+
failed_ids: failed_ids,
356+
new_status: new_status,
357+
pending_count: pending_count
358+
}, status: status
359+
end
360+
end
361+
end
362+
363+
def approve_request_for_mass_action(request)
364+
lms_facade = request.assignment&.lms_facade
365+
return false unless lms_facade
366+
367+
request.approve(lms_facade.from_user(@user), @user)
368+
rescue StandardError => e
369+
Rails.logger.error("Mass approve failed for request #{request.id}: #{e.message}")
370+
false
371+
end
372+
373+
def mass_request_ids
374+
Array(params[:request_ids]).map(&:to_i).uniq.select(&:positive?)
375+
end
261376
end
262377
# rubocop:enable Metrics/ClassLength

0 commit comments

Comments
 (0)