Merge branch 'master' into client-routesv2

This commit is contained in:
Niklas Kiefer
2017-04-25 13:50:08 +02:00
99 changed files with 2222 additions and 109 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
before_action :set_locale, :allow_iframe_requests
protect_from_forgery(with: :exception)
rescue_from Pundit::NotAuthorizedError, with: :render_not_authorized
@ -29,4 +29,8 @@ class ApplicationController < ActionController::Base
def welcome
end
def allow_iframe_requests
response.headers.delete('X-Frame-Options')
end
end

View File

@ -49,7 +49,7 @@ class CommentsController < ApplicationController
@comment = Comment.new(comment_params_without_request_id)
if comment_params[:request_id]
UserMailer.got_new_comment(@comment, RequestForComment.find(comment_params[:request_id]), current_user)
UserMailer.got_new_comment(@comment, RequestForComment.find(comment_params[:request_id]), current_user).deliver_now
end
respond_to do |format|

View File

@ -74,7 +74,12 @@ module Lti
private :require_valid_consumer_key
def require_valid_exercise_token
@exercise = Exercise.find_by(token: params[:custom_token])
proxy_exercise = ProxyExercise.find_by(token: params[:custom_token])
unless proxy_exercise.nil?
@exercise = proxy_exercise.get_matching_exercise(@current_user)
else
@exercise = Exercise.find_by(token: params[:custom_token])
end
refuse_lti_launch(message: t('sessions.oauth.invalid_exercise_token')) unless @exercise
end
private :require_valid_exercise_token
@ -129,19 +134,16 @@ module Lti
private :set_current_user
def store_lti_session_data(options = {})
exercise = Exercise.where(token: options[:parameters][:custom_token]).first
exercise_id = exercise.id unless exercise.nil?
current_user = ExternalUser.find_or_create_by(consumer_id: options[:consumer].id, external_id: options[:parameters][:user_id].to_s)
lti_parameters = LtiParameter.find_or_create_by(consumers_id: options[:consumer].id,
external_users_id: current_user.id,
exercises_id: exercise_id)
external_users_id: @current_user.id,
exercises_id: @exercise.id)
lti_parameters.lti_parameters = options[:parameters].slice(*SESSION_PARAMETERS).to_json
lti_parameters.save!
@lti_parameters = lti_parameters
session[:consumer_id] = options[:consumer].id
session[:external_user_id] = current_user.id
session[:external_user_id] = @current_user.id
end
private :store_lti_session_data

View File

@ -25,7 +25,7 @@ module SubmissionScoring
def feedback_message(file, score)
set_locale
score == Assessor::MAXIMUM_SCORE ? I18n.t('exercises.implement.default_feedback') : file.feedback_message
score == Assessor::MAXIMUM_SCORE ? I18n.t('exercises.implement.default_feedback') : render_markdown(file.feedback_message)
end
def score_submission(submission)

View File

@ -40,7 +40,7 @@ class ExecutionEnvironmentsController < ApplicationController
FROM
(SELECT user_id,
exercise_id,
CASE WHEN working_time >= '0:30:00' THEN '0' ELSE working_time END AS working_time_new
CASE WHEN working_time >= '0:05:00' THEN '0' ELSE working_time END AS working_time_new
FROM
(SELECT user_id,
exercise_id,

View File

@ -6,9 +6,10 @@ class ExercisesController < ApplicationController
before_action :handle_file_uploads, only: [:create, :update]
before_action :set_execution_environments, only: [:create, :edit, :new, :update]
before_action :set_exercise, only: MEMBER_ACTIONS + [:clone, :implement, :run, :statistics, :submit, :reload]
before_action :set_exercise, only: MEMBER_ACTIONS + [:clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload]
before_action :set_external_user, only: [:statistics]
before_action :set_file_types, only: [:create, :edit, :new, :update]
before_action :set_course_token, only: [:implement]
skip_before_filter :verify_authenticity_token, only: [:import_proforma_xml]
skip_after_action :verify_authorized, only: [:import_proforma_xml]
@ -19,6 +20,15 @@ class ExercisesController < ApplicationController
end
private :authorize!
def max_intervention_count
3
end
def java_course_token
"702cbd2a-c84c-4b37-923a-692d7d1532d0"
end
def batch_update
@exercises = Exercise.all
authorize!
@ -54,6 +64,20 @@ class ExercisesController < ApplicationController
def create
@exercise = Exercise.new(exercise_params)
collect_set_and_unset_exercise_tags
myparam = exercise_params
checked_exercise_tags = @exercise_tags.select { | et | myparam[:tag_ids].include? et.tag.id.to_s }
removed_exercise_tags = @exercise_tags.reject { | et | myparam[:tag_ids].include? et.tag.id.to_s }
for et in checked_exercise_tags
et.factor = params[:tag_factors][et.tag_id.to_s][:factor]
et.exercise = @exercise
end
myparam[:exercise_tags] = checked_exercise_tags
myparam.delete :tag_ids
removed_exercise_tags.map {|et| et.destroy}
authorize!
create_and_respond(object: @exercise)
end
@ -63,6 +87,7 @@ class ExercisesController < ApplicationController
end
def edit
collect_set_and_unset_exercise_tags
end
def import_proforma_xml
@ -118,7 +143,8 @@ class ExercisesController < ApplicationController
private :user_by_code_harbor_token
def exercise_params
params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :allow_file_creation, :allow_auto_completion, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name)
params[:exercise][:expected_worktime_seconds] = params[:exercise][:expected_worktime_minutes].to_i * 60
params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :allow_file_creation, :allow_auto_completion, :title, :expected_difficulty, :expected_worktime_seconds, files_attributes: file_attributes, :tag_ids => []).merge(user_id: current_user.id, user_type: current_user.class.name)
end
private :exercise_params
@ -139,6 +165,22 @@ class ExercisesController < ApplicationController
def implement
redirect_to(@exercise, alert: t('exercises.implement.no_files')) unless @exercise.files.visible.exists?
user_solved_exercise = @exercise.has_user_solved(current_user)
user_got_enough_interventions = UserExerciseIntervention.where(user: current_user).where("created_at >= ?", Time.zone.now.beginning_of_day).count >= max_intervention_count
is_java_course = @course_token && @course_token.eql?(java_course_token)
user_intervention_group = UserGroupSeparator.getInterventionGroup(current_user)
case user_intervention_group
when :no_intervention
when :break_intervention
@show_break_interventions = (user_solved_exercise || !is_java_course || user_got_enough_interventions) ? "false" : "true"
when :rfc_intervention
@show_rfc_interventions = (user_solved_exercise || !is_java_course || user_got_enough_interventions) ? "false" : "true"
end
@search = Search.new
@search.exercise = @exercise
@submission = current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first
@files = (@submission ? @submission.collect_files : @exercise.files).select(&:visible).sort_by(&:name_with_extension)
@paths = collect_paths(@files)
@ -150,6 +192,59 @@ class ExercisesController < ApplicationController
end
end
def set_course_token
lti_parameters = LtiParameter.find_by(external_users_id: current_user.id,
exercises_id: @exercise.id)
if lti_parameters
lti_json = lti_parameters.lti_parameters["launch_presentation_return_url"]
@course_token =
unless lti_json.nil?
if match = lti_json.match(/^.*courses\/([a-z0-9\-]+)\/sections/)
match.captures.first
else
java_course_token
end
else
""
end
else
# no consumer, therefore implementation with internal user
@course_token = java_course_token
end
end
private :set_course_token
def working_times
working_time_accumulated = @exercise.accumulated_working_time_for_only(current_user)
working_time_75_percentile = @exercise.get_quantiles([0.75]).first
render(json: {working_time_75_percentile: working_time_75_percentile, working_time_accumulated: working_time_accumulated})
end
def intervention
intervention = Intervention.find_by_name(params[:intervention_type])
unless intervention.nil?
uei = UserExerciseIntervention.new(
user: current_user, exercise: @exercise, intervention: intervention,
accumulated_worktime_s: @exercise.accumulated_working_time_for_only(current_user))
uei.save
render(json: {success: 'true'})
else
render(json: {success: 'false', error: "undefined intervention #{params[:intervention_type]}"})
end
end
def search
search_text = params[:search_text]
search = Search.new(user: current_user, exercise: @exercise, search: search_text)
begin search.save
render(json: {success: 'true'})
rescue
render(json: {success: 'false', error: "could not save search: #{$!}"})
end
end
def index
@search = policy_scope(Exercise).search(params[:q])
@exercises = @search.result.includes(:execution_environment, :user).order(:title).paginate(page: params[:page])
@ -174,6 +269,8 @@ class ExercisesController < ApplicationController
def new
@exercise = Exercise.new
collect_set_and_unset_exercise_tags
authorize!
end
@ -201,6 +298,16 @@ class ExercisesController < ApplicationController
end
private :set_file_types
def collect_set_and_unset_exercise_tags
@search = policy_scope(Tag).search(params[:q])
@tags = @search.result.order(:name)
checked_exercise_tags = @exercise.exercise_tags
checked_tags = checked_exercise_tags.collect{|e| e.tag}.to_set
unchecked_tags = Tag.all.to_set.subtract checked_tags
@exercise_tags = checked_exercise_tags + unchecked_tags.collect { |tag| ExerciseTag.new(exercise: @exercise, tag: tag)}
end
private :collect_set_and_unset_exercise_tags
def show
end
@ -252,7 +359,20 @@ class ExercisesController < ApplicationController
private :transmit_lti_score
def update
update_and_respond(object: @exercise, params: exercise_params)
collect_set_and_unset_exercise_tags
myparam = exercise_params
checked_exercise_tags = @exercise_tags.select { | et | myparam[:tag_ids].include? et.tag.id.to_s }
removed_exercise_tags = @exercise_tags.reject { | et | myparam[:tag_ids].include? et.tag.id.to_s }
for et in checked_exercise_tags
et.factor = params[:tag_factors][et.tag_id.to_s][:factor]
et.exercise = @exercise
end
myparam[:exercise_tags] = checked_exercise_tags
myparam.delete :tag_ids
removed_exercise_tags.map {|et| et.destroy}
update_and_respond(object: @exercise, params: myparam)
end
def redirect_after_submit
@ -260,8 +380,12 @@ class ExercisesController < ApplicationController
if @submission.normalized_score == 1.0
# if user is external and has an own rfc, redirect to it and message him to clean up and accept the answer. (we need to check that the user is external,
# otherwise an internal user could be shown a false rfc here, since current_user.id is polymorphic, but only makes sense for external users when used with rfcs.)
# redirect 10 percent pseudorandomly to the feedback page
if current_user.respond_to? :external_id
if rfc = RequestForComment.unsolved.where(exercise_id: @submission.exercise, user_id: current_user.id).first
if ((current_user.id + @submission.exercise.created_at.to_i) % 10 == 1)
redirect_to_user_feedback
return
elsif rfc = RequestForComment.unsolved.where(exercise_id: @submission.exercise, user_id: current_user.id).first
# set a message that informs the user that his own RFC should be closed.
flash[:notice] = I18n.t('exercises.submit.full_score_redirect_to_own_rfc')
flash.keep(:notice)
@ -273,7 +397,7 @@ class ExercisesController < ApplicationController
return
# else: show open rfc for same exercise if available
elsif rfc = RequestForComment.unsolved.where(exercise_id: @submission.exercise).where.not(question: nil).order("RANDOM()").first
elsif rfc = RequestForComment.unsolved.where(exercise_id: @submission.exercise).where.not(question: nil).order("RANDOM()").find { | rfc_element |(rfc_element.comments_count < 5) }
# set a message that informs the user that his score was perfect and help in RFC is greatly appreciated.
flash[:notice] = I18n.t('exercises.submit.full_score_redirect_to_rfc')
flash.keep(:notice)
@ -285,8 +409,25 @@ class ExercisesController < ApplicationController
return
end
end
else
# redirect to feedback page if score is less than 100 percent
redirect_to_user_feedback
return
end
redirect_to_lti_return_path
end
def redirect_to_user_feedback
url = if UserExerciseFeedback.find_by(exercise: @exercise, user: current_user)
edit_user_exercise_feedback_path(user_exercise_feedback: {exercise_id: @exercise.id})
else
new_user_exercise_feedback_path(user_exercise_feedback: {exercise_id: @exercise.id})
end
respond_to do |format|
format.html { redirect_to(url) }
format.json { render(json: {redirect: url}) }
end
end
end

View File

@ -27,7 +27,7 @@ class ExternalUsersController < ApplicationController
score,
id,
CASE
WHEN working_time >= '0:30:00' THEN '0'
WHEN working_time >= '0:05:00' THEN '0'
ELSE working_time
END AS working_time_new
FROM

View File

@ -0,0 +1,55 @@
class InterventionsController < ApplicationController
include CommonBehavior
before_action :set_intervention, only: MEMBER_ACTIONS
def authorize!
authorize(@intervention || @interventions)
end
private :authorize!
def create
#@intervention = Intervention.new(intervention_params)
#authorize!
#create_and_respond(object: @intervention)
end
def destroy
destroy_and_respond(object: @intervention)
end
def edit
end
def intervention_params
params[:intervention].permit(:name)
end
private :intervention_params
def index
@interventions = Intervention.all.paginate(page: params[:page])
authorize!
end
def new
#@intervention = Intervention.new
#authorize!
end
def set_intervention
@intervention = Intervention.find(params[:id])
authorize!
end
private :set_intervention
def show
end
def update
update_and_respond(object: @intervention, params: intervention_params)
end
def to_s
name
end
end

View File

@ -0,0 +1,80 @@
class ProxyExercisesController < ApplicationController
include CommonBehavior
before_action :set_exercise, only: MEMBER_ACTIONS + [:clone, :reload]
def authorize!
authorize(@proxy_exercise || @proxy_exercises)
end
private :authorize!
def clone
proxy_exercise = @proxy_exercise.duplicate(token: nil, exercises: @proxy_exercise.exercises)
proxy_exercise.send(:generate_token)
if proxy_exercise.save
redirect_to(proxy_exercise, notice: t('shared.object_cloned', model: ProxyExercise.model_name.human))
else
flash[:danger] = t('shared.message_failure')
redirect_to(@proxy_exercise)
end
end
def create
myparams = proxy_exercise_params
myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject { |c| c.empty? })
@proxy_exercise = ProxyExercise.new(myparams)
authorize!
create_and_respond(object: @proxy_exercise)
end
def destroy
destroy_and_respond(object: @proxy_exercise)
end
def edit
@search = policy_scope(Exercise).search(params[:q])
@exercises = @search.result.order(:title)
authorize!
end
def proxy_exercise_params
params[:proxy_exercise].permit(:description, :title, :exercise_ids => [])
end
private :proxy_exercise_params
def index
@search = policy_scope(ProxyExercise).search(params[:q])
@proxy_exercises = @search.result.order(:title).paginate(page: params[:page])
authorize!
end
def new
@proxy_exercise = ProxyExercise.new
@search = policy_scope(Exercise).search(params[:q])
@exercises = @search.result.order(:title)
authorize!
end
def set_exercise
@proxy_exercise = ProxyExercise.find(params[:id])
authorize!
end
private :set_exercise
def show
@search = @proxy_exercise.exercises.search
@exercises = @proxy_exercise.exercises.search.result.order(:title) #@search.result.order(:title)
end
#we might want to think about auth here
def reload
end
def update
myparams = proxy_exercise_params
myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject { |c| c.blank? })
update_and_respond(object: @proxy_exercise, params: myparams)
end
end

View File

@ -11,12 +11,14 @@ class RequestForCommentsController < ApplicationController
# GET /request_for_comments
# GET /request_for_comments.json
def index
@request_for_comments = RequestForComment.last_per_user(2).order('created_at DESC').paginate(page: params[:page])
@search = RequestForComment.last_per_user(2).search(params[:q])
@request_for_comments = @search.result.order('created_at DESC').paginate(page: params[:page])
authorize!
end
def get_my_comment_requests
@request_for_comments = RequestForComment.where(user_id: current_user.id).order('created_at DESC').paginate(page: params[:page])
@search = RequestForComment.where(user_id: current_user.id).order('created_at DESC').search(params[:q])
@request_for_comments = @search.result.paginate(page: params[:page])
render 'index'
end
@ -32,6 +34,10 @@ class RequestForCommentsController < ApplicationController
end
end
def submit
end
# GET /request_for_comments/1
# GET /request_for_comments/1.json
def show
@ -63,6 +69,20 @@ class RequestForCommentsController < ApplicationController
authorize!
end
def create_comment_exercise
old = UserExerciseFeedback.find_by(exercise_id: params[:exercise_id], user_id: current_user.id, user_type: current_user.class.name)
if old
old.delete
end
uef = UserExerciseFeedback.new(comment_params)
if uef.save
render(json: {success: "true"})
else
render(json: {success: "false"})
end
end
# DELETE /request_for_comments/1
# DELETE /request_for_comments/1.json
def destroy
@ -74,6 +94,10 @@ class RequestForCommentsController < ApplicationController
authorize!
end
def comment_params
params.permit(:exercise_id, :feedback_text).merge(user_id: current_user.id, user_type: current_user.class.name)
end
private
# Use callbacks to share common setup or constraints between actions.
def set_request_for_comment
@ -85,4 +109,5 @@ class RequestForCommentsController < ApplicationController
# we are using the current_user.id here, since internal users are not able to create comments. The external_user.id is a primary key and does not require the consumer_id to be unique.
params.require(:request_for_comment).permit(:exercise_id, :file_id, :question, :requested_at, :solved, :submission_id).merge(user_id: current_user.id, user_type: current_user.class.name)
end
end

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, :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].each do |method_name|
before_action(method_name, only: :create_through_lti)
end
@ -18,7 +18,6 @@ class SessionsController < ApplicationController
end
def create_through_lti
set_current_user
store_lti_session_data(consumer: @consumer, parameters: params)
store_nonce(params[:oauth_nonce])
redirect_to(implement_exercise_path(@exercise),

View File

@ -13,6 +13,10 @@ class SubmissionsController < ApplicationController
before_action :set_mime_type, only: [:download_file, :render_file]
skip_before_action :verify_authenticity_token, only: [:download_file, :render_file]
def max_message_buffer_size
500
end
def authorize!
authorize(@submission || @submissions)
end
@ -156,7 +160,7 @@ class SubmissionsController < ApplicationController
tubesock.onmessage do |data|
Rails.logger.info(Time.now.getutc.to_s + ": Client sending: " + data)
# Check whether the client send a JSON command and kill container
# if the command is 'client_exit', send it to docker otherwise.
# if the command is 'client_kill', send it to docker otherwise.
begin
parsed = JSON.parse(data)
if parsed['cmd'] == 'client_kill'
@ -183,21 +187,31 @@ class SubmissionsController < ApplicationController
end
def kill_socket(tubesock)
# save the output of this "run" as a "testrun" (scoring runs are saved in submission_scoring.rb)
save_run_output
# Hijacked connection needs to be notified correctly
tubesock.send_data JSON.dump({'cmd' => 'exit'})
tubesock.close
end
def handle_message(message, tubesock, container)
@message_buffer ||= ""
# Handle special commands first
if (/^exit/.match(message))
kill_socket(tubesock)
if (/^#exit/.match(message))
# Just call exit_container on the docker_client.
# Do not call kill_socket for the websocket to the client here.
# @docker_client.exit_container closes the socket to the container,
# kill_socket is called in the "on close handler" of the websocket to the container
@docker_client.exit_container(container)
elsif /^#timeout/.match(message)
@message_buffer = 'timeout: ' + @message_buffer # 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])
if !(/root|workspace|#{run_command}|#{test_command}/.match(message))
@message_buffer += message if @message_buffer.size <= max_message_buffer_size
parse_message(message, 'stdout', tubesock)
end
end
@ -245,6 +259,13 @@ class SubmissionsController < ApplicationController
end
end
def save_run_output
if !@message_buffer.blank?
@message_buffer = @message_buffer[(0..max_message_buffer_size-1)] # trim the string to max_message_buffer_size chars
Testrun.create(file: @file, submission: @submission, output: @message_buffer)
end
end
def score
hijack do |tubesock|
Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?

View File

@ -0,0 +1,55 @@
class TagsController < ApplicationController
include CommonBehavior
before_action :set_tag, only: MEMBER_ACTIONS
def authorize!
authorize(@tag || @tags)
end
private :authorize!
def create
@tag = Tag.new(tag_params)
authorize!
create_and_respond(object: @tag)
end
def destroy
destroy_and_respond(object: @tag)
end
def edit
end
def tag_params
params[:tag].permit(:name)
end
private :tag_params
def index
@tags = Tag.all.paginate(page: params[:page])
authorize!
end
def new
@tag = Tag.new
authorize!
end
def set_tag
@tag = Tag.find(params[:id])
authorize!
end
private :set_tag
def show
end
def update
update_and_respond(object: @tag, params: tag_params)
end
def to_s
name
end
end

View File

@ -0,0 +1,115 @@
class UserExerciseFeedbacksController < ApplicationController
include CommonBehavior
before_action :set_user_exercise_feedback, only: [:edit, :update]
def comment_presets
[[0,t('user_exercise_feedback.difficulty_easy')],
[1,t('user_exercise_feedback.difficulty_some_what_easy')],
[2,t('user_exercise_feedback.difficulty_ok')],
[3,t('user_exercise_feedback.difficulty_some_what_difficult')],
[4,t('user_exercise_feedback.difficult_too_difficult')]]
end
def time_presets
[[0,t('user_exercise_feedback.estimated_time_less_5')],
[1,t('user_exercise_feedback.estimated_time_5_to_10')],
[2,t('user_exercise_feedback.estimated_time_10_to_20')],
[3,t('user_exercise_feedback.estimated_time_20_to_30')],
[4,t('user_exercise_feedback.estimated_time_more_30')]]
end
def authorize!
authorize(@uef)
end
private :authorize!
def create
@exercise = Exercise.find(uef_params[:exercise_id])
rfc = RequestForComment.unsolved.where(exercise_id: @exercise.id, user_id: current_user.id).first
submission = current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first rescue nil
if @exercise
@uef = UserExerciseFeedback.new(uef_params)
if validate_inputs(uef_params)
authorize!
path =
if rfc && submission && submission.normalized_score == 1.0
request_for_comment_path(rfc)
else
implement_exercise_path(@exercise)
end
create_and_respond(object: @uef, path: proc{path})
else
flash[:danger] = t('shared.message_failure')
redirect_to(:back, id: uef_params[:exercise_id])
end
end
end
def destroy
destroy_and_respond(object: @tag)
end
def edit
@texts = comment_presets.to_a
@times = time_presets.to_a
authorize!
end
def uef_params
params[:user_exercise_feedback].permit(:feedback_text, :difficulty, :exercise_id, :user_estimated_worktime).merge(user_id: current_user.id, user_type: current_user.class.name)
end
private :uef_params
def new
@texts = comment_presets.to_a
@times = time_presets.to_a
@uef = UserExerciseFeedback.new
@exercise = Exercise.find(params[:user_exercise_feedback][:exercise_id])
authorize!
end
def update
submission = current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first rescue nil
rfc = RequestForComment.unsolved.where(exercise_id: @exercise.id, user_id: current_user.id).first
authorize!
if @exercise && validate_inputs(uef_params)
path =
if rfc && submission && submission.normalized_score == 1.0
request_for_comment_path(rfc)
else
implement_exercise_path(@exercise)
end
update_and_respond(object: @uef, params: uef_params, path: path)
else
flash[:danger] = t('shared.message_failure')
redirect_to(:back, id: uef_params[:exercise_id])
end
end
def to_s
name
end
def set_user_exercise_feedback
@exercise = Exercise.find(params[:user_exercise_feedback][:exercise_id])
@uef = UserExerciseFeedback.find_by(exercise_id: params[:user_exercise_feedback][:exercise_id], user: current_user)
end
def validate_inputs(uef_params)
begin
if uef_params[:difficulty].to_i < 0 || uef_params[:difficulty].to_i >= comment_presets.size
return false
elsif uef_params[:user_estimated_worktime].to_i < 0 || uef_params[:user_estimated_worktime].to_i >= time_presets.size
return false
else
return true
end
rescue
return false
end
end
end