Merge branch 'master' into add_groups

This commit is contained in:
rteusner
2018-12-13 16:28:34 +01:00
committed by Sebastian Serth
47 changed files with 253 additions and 116 deletions

View File

@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base
MEMBER_ACTIONS = [:destroy, :edit, :show, :update]
after_action :verify_authorized, except: [:help, :welcome]
before_action :set_locale, :allow_iframe_requests
before_action :set_locale, :allow_iframe_requests, :load_embed_options
protect_from_forgery(with: :exception, prepend: true)
rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized
@ -38,4 +38,14 @@ class ApplicationController < ActionController::Base
def allow_iframe_requests
response.headers.delete('X-Frame-Options')
end
def load_embed_options
if session[:embed_options].present? && session[:embed_options].is_a?(Hash)
@embed_options = session[:embed_options].symbolize_keys
else
@embed_options = {}
end
@embed_options
end
private :load_embed_options
end

View File

@ -22,6 +22,7 @@ module Lti
if (exercise_id.nil?)
session.delete(:consumer_id)
session.delete(:external_user_id)
session.delete(:embed_options)
else
LtiParameter.where(consumers_id: consumer_id,
external_users_id: user_id,
@ -138,6 +139,7 @@ module Lti
end
private :set_current_user
def set_study_group_membership
return if mooc_course
group = StudyGroup.find_or_create_by(external_id: @provider.resource_link_id, consumer: @consumer)
@ -145,6 +147,26 @@ module Lti
group.save
end
def set_embedding_options
@embed_options = {}
[:hide_navbar,
:hide_exercise_description,
:disable_run,
:disable_score,
:disable_rfc,
:disable_interventions,
:hide_sidebar,
:read_only,
:hide_test_results,
:disable_hints].each do |option|
value = params["custom_embed_options_#{option}".to_sym] == 'true'
# Optimize storage and save only those that are true, the session cookie is limited to 4KB
@embed_options[option] = value if value.present?
end
session[:embed_options] = @embed_options
end
private :set_embedding_options
def store_lti_session_data(options = {})
lti_parameters = LtiParameter.find_or_create_by(consumers_id: options[:consumer].id,
external_users_id: @current_user.id,

View File

@ -55,6 +55,11 @@ module SubmissionScoring
}
end
end
if @embed_options.present? && @embed_options[:hide_test_results] && outputs.present?
outputs.each do |output|
output.except!(:error_messages, :count, :failed, :filename, :message, :passed, :stderr, :stdout)
end
end
outputs
end
end

View File

@ -188,7 +188,15 @@ class ExercisesController < ApplicationController
user_got_intervention_in_exercise = UserExerciseIntervention.where(user: current_user, exercise: @exercise).size >= max_intervention_count_per_exercise
user_got_enough_interventions = count_interventions_today >= max_intervention_count_per_day or user_got_intervention_in_exercise
@show_rfc_interventions = (not user_solved_exercise and not user_got_enough_interventions).to_s
unless @embed_options[:disable_interventions]
@show_rfc_interventions = (not user_solved_exercise and not user_got_enough_interventions).to_s
@show_break_interventions = false
else
@show_rfc_interventions = false
@show_break_interventions = false
end
@hide_rfc_button = @embed_options[:disable_rfc]
@search = Search.new

View File

@ -8,7 +8,7 @@ class FlowrController < ApplicationController
.order('testruns.created_at DESC').first
# Return if no submission was found
if submission.blank?
if submission.blank? || @embed_options[:disable_hints] || @embed_options[:hide_test_results]
skip_authorization
render json: [], status: :ok
return

View File

@ -9,7 +9,7 @@ class ProxyExercisesController < ApplicationController
private :authorize!
def clone
proxy_exercise = @proxy_exercise.duplicate(token: nil, exercises: @proxy_exercise.exercises)
proxy_exercise = @proxy_exercise.duplicate(public: false, token: nil, exercises: @proxy_exercise.exercises, user: current_user)
proxy_exercise.send(:generate_token)
if proxy_exercise.save
redirect_to(proxy_exercise, notice: t('shared.object_cloned', model: ProxyExercise.model_name.human))
@ -39,7 +39,7 @@ class ProxyExercisesController < ApplicationController
end
def proxy_exercise_params
params[:proxy_exercise].permit(:description, :title, :exercise_ids => []) if params[:proxy_exercise].present?
params[:proxy_exercise].permit(:description, :title, :public, :exercise_ids => []).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:proxy_exercise].present?
end
private :proxy_exercise_params

View File

@ -96,6 +96,10 @@ class RequestForCommentsController < ApplicationController
# POST /request_for_comments
# POST /request_for_comments.json
def create
# Consider all requests as JSON
request.format = 'json'
raise Pundit::NotAuthorizedError if @embed_options[:disable_rfc]
@request_for_comment = RequestForComment.new(request_for_comment_params)
respond_to do |format|
if @request_for_comment.save

View File

@ -1,7 +1,7 @@
class SessionsController < ApplicationController
include Lti
[:require_oauth_parameters, :require_valid_consumer_key, :require_valid_oauth_signature, :require_unique_oauth_nonce, :set_current_user, :set_study_group_membership, :require_valid_exercise_token].each do |method_name|
[:require_oauth_parameters, :require_valid_consumer_key, :require_valid_oauth_signature, :require_unique_oauth_nonce, :set_current_user, :require_valid_exercise_token, :set_study_group_membership, :set_embedding_options].each do |method_name|
before_action(method_name, only: :create_through_lti)
end

View File

@ -122,13 +122,18 @@ class SubmissionsController < ApplicationController
def run
# TODO reimplement SSEs with websocket commands
# with_server_sent_events do |server_sent_event|
# output = @docker_client.execute_run_command(@submission, params[:filename])
# output = @docker_client.execute_run_command(@submission, sanitize_filename)
# server_sent_event.write({stdout: output[:stdout]}, event: 'output') if output[:stdout]
# server_sent_event.write({stderr: output[:stderr]}, event: 'output') if output[:stderr]
# end
hijack do |tubesock|
if @embed_options[:disable_run]
kill_socket(tubesock)
return
end
# probably add:
# ensure
# #guarantee that the thread is releasing the DB connection after it is done
@ -142,7 +147,7 @@ class SubmissionsController < ApplicationController
# give the docker_client the tubesock object, so that it can send messages (timeout)
@docker_client.tubesock = tubesock
result = @docker_client.execute_run_command(@submission, params[:filename])
result = @docker_client.execute_run_command(@submission, sanitize_filename)
tubesock.send_data JSON.dump({'cmd' => 'status', 'status' => result[:status]})
if result[:status] == :container_running
@ -195,6 +200,10 @@ class SubmissionsController < ApplicationController
# save the output of this "run" as a "testrun" (scoring runs are saved in submission_scoring.rb)
save_run_output
if @run_output.blank?
parse_message t('exercises.implement.no_output', timestamp: l(Time.now, format: :short)), 'stdout', tubesock
end
# Hijacked connection needs to be notified correctly
tubesock.send_data JSON.dump({'cmd' => 'exit'})
tubesock.close
@ -214,8 +223,8 @@ class SubmissionsController < ApplicationController
@run_output = 'timeout: ' + @run_output # add information that this run timed out to the buffer
else
# Filter out information about run_command, test_command, user or working directory
run_command = @submission.execution_environment.run_command % command_substitutions(params[:filename])
test_command = @submission.execution_environment.test_command % command_substitutions(params[:filename])
run_command = @submission.execution_environment.run_command % command_substitutions(sanitize_filename)
test_command = @submission.execution_environment.test_command % command_substitutions(sanitize_filename)
unless /root|workspace|#{run_command}|#{test_command}/.match(message)
parse_message(message, 'stdout', tubesock)
end
@ -291,6 +300,11 @@ class SubmissionsController < ApplicationController
def score
hijack do |tubesock|
if @embed_options[:disable_score]
kill_socket(tubesock)
return
end
Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?
# tubesock is the socket to the client
@ -308,6 +322,7 @@ class SubmissionsController < ApplicationController
end
def send_hints(tubesock, errors)
return if @embed_options[:disable_hints]
errors = errors.to_a.uniq { |e| e.hint}
errors.each do | error |
tubesock.send_data JSON.dump({cmd: 'hint', hint: error.hint, description: error.error_template.description})
@ -320,7 +335,7 @@ class SubmissionsController < ApplicationController
private :set_docker_client
def set_file
@file = @files.detect { |file| file.name_with_extension == params[:filename] }
@file = @files.detect { |file| file.name_with_extension == sanitize_filename }
head :not_found unless @file
end
private :set_file
@ -361,7 +376,7 @@ class SubmissionsController < ApplicationController
hijack do |tubesock|
Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?
output = @docker_client.execute_test_command(@submission, params[:filename])
output = @docker_client.execute_test_command(@submission, sanitize_filename)
# tubesock is the socket to the client
tubesock.send_data JSON.dump(output)
@ -405,4 +420,8 @@ class SubmissionsController < ApplicationController
end
path
end
def sanitize_filename
params[:filename].gsub(/\.json$/, '')
end
end