@@ -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
261376end
262377# rubocop:enable Metrics/ClassLength
0 commit comments