Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow creating or updating scheduler if invalid #2214

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
82 changes: 77 additions & 5 deletions app/controllers/schedulers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,25 @@ def new; end
action_auth_level :create, :instructor
def create
@scheduler = @course.scheduler.new(scheduler_params)
# Check if the action file exists and is readable
action_path = Rails.root.join(scheduler_params[:action]).to_path
20wildmanj marked this conversation as resolved.
Show resolved Hide resolved
unless File.exist?(action_path) && File.readable?(action_path)
flash[:error] = "Scheduler create failed. Action file does not exist or is
not readable at #{action_path}."
redirect_to(new_course_scheduler_path(@course)) and return
end

jhs-panda marked this conversation as resolved.
Show resolved Hide resolved
if @scheduler.save
flash[:success] = "Scheduler created!"
redirect_to(course_schedulers_path(@course))
# Ensure visual run is successful
begin
test_run_visual_scheduler(@scheduler)
flash[:success] = "Scheduler created and executed successfully!"
redirect_to(course_schedulers_path(@course))
rescue StandardError => e
@scheduler.destroy # Destroy the created scheduler if visual run fails
flash[:error] = "Scheduler creation failed. Error: #{e.message}"
redirect_to(new_course_scheduler_path(@course))
end
else
flash[:error] = "Scheduler create failed. Please check all fields."
redirect_to(new_course_scheduler_path(@course))
Expand Down Expand Up @@ -87,9 +103,29 @@ def visual_run
action_auth_level :update, :instructor
def update
@scheduler = Scheduler.find_by(id: params[:id])
if @scheduler&.update(scheduler_params)
flash[:success] = "Scheduler updated."
redirect_to(course_schedulers_path(@course))
# Check if the action file exists and is readable
action_path = Rails.root.join(scheduler_params[:action]).to_path
jhs-panda marked this conversation as resolved.
Show resolved Hide resolved
unless File.exist?(action_path) && File.readable?(action_path)
flash[:error] = "Scheduler update failed. Action file does not exist or is
not readable at #{action_path}."
redirect_to(edit_course_scheduler_path(@course)) and return
end

# Save the current state of the scheduler in case we need to revert
previous_scheduler_state = @scheduler.attributes

if @scheduler.update(scheduler_params)
begin
# Run the visual scheduler to ensure the new update works
test_run_visual_scheduler(@scheduler)
flash[:success] = "Scheduler updated and executed successfully!"
redirect_to(course_schedulers_path(@course))
rescue StandardError => e
@scheduler.update(previous_scheduler_state) # If error, revert to previous state.
flash[:error] = "Scheduler update failed. Reverting to previous state.
Error: #{e.message}"
redirect_to(edit_course_scheduler_path(@course, @scheduler))
end
jhs-panda marked this conversation as resolved.
Show resolved Hide resolved
else
flash[:error] = "Scheduler update failed! Please check your fields."
redirect_to(edit_course_scheduler_path(@course, @scheduler))
Expand Down Expand Up @@ -119,4 +155,40 @@ def set_manage_scheduler_breadcrumb

@breadcrumbs << (view_context.link_to "Manage Schedulers", course_schedulers_path(@course))
end

def test_run_visual_scheduler(scheduler)
jhs-panda marked this conversation as resolved.
Show resolved Hide resolved
# Do a test visual run to check if created/updated info valid
action = scheduler
read, write = IO.pipe

pid = fork do
read.close
mod_name = Rails.root.join(action.action).to_path
fork_log = ""
begin
require mod_name
output = Updater.update(action.course)
jhs-panda marked this conversation as resolved.
Show resolved Hide resolved
if output.respond_to?(:to_str)
fork_log << "----- Script Output -----\n"
fork_log << output
fork_log << "\n----- End Script Output -----"
end
rescue ScriptError, StandardError => e
fork_log << "----- Script Error Output -----\n"
fork_log << "Error in '#{action.course.name}' updater: #{e.message}\n"
fork_log << e.backtrace.join("\n\t")
fork_log << "\n---- End Script Error Output -----"
end
write.print fork_log
end

write.close
result = read.read
Process.wait2(pid)

# Raise an exception if something goes wrong
return unless result.is_a?(String) && result.include?("Error")

raise "Scheduler execution failed."
jhs-panda marked this conversation as resolved.
Show resolved Hide resolved
end
jhs-panda marked this conversation as resolved.
Show resolved Hide resolved
end