Apply automatic rubocop fixes

This commit is contained in:
Sebastian Serth
2021-05-14 10:51:44 +02:00
parent fe4000916c
commit 6cbecb5b39
440 changed files with 2705 additions and 1853 deletions

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
module Admin
class DashboardController < ApplicationController
include DashboardHelper

View File

@ -14,7 +14,8 @@ class ApplicationController < ActionController::Base
rescue_from ActionController::InvalidAuthenticityToken, with: :render_csrf_error
def current_user
::NewRelic::Agent.add_custom_attributes(external_user_id: session[:external_user_id], session_user_id: session[:user_id])
::NewRelic::Agent.add_custom_attributes(external_user_id: session[:external_user_id],
session_user_id: session[:user_id])
@current_user ||= ExternalUser.find_by(id: session[:external_user_id]) || login_from_session || login_from_other_sources || nil
end
@ -59,7 +60,7 @@ class ApplicationController < ActionController::Base
respond_to do |format|
format.html do
# Prevent redirect loop
if request.url == request.referrer
if request.url == request.referer
redirect_to :root, alert: message
else
redirect_back fallback_location: :root, allow_other_host: false, alert: message

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
module CodeOcean
class FilesController < ApplicationController
include CommonBehavior
@ -25,9 +27,10 @@ module CodeOcean
if @object.save
yield if block_given?
path = options[:path].try(:call) || @object
respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human), path: path, status: :created)
respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human),
path: path, status: :created)
else
filename = (@object.path || '') + '/' + (@object.name || '') + (@object.file_type.try(:file_extension) || '')
filename = "#{@object.path || ''}/#{@object.name || ''}#{@object.file_type.try(:file_extension) || ''}"
format.html { redirect_to(options[:path]); flash[:danger] = t('files.error.filename', name: filename) }
format.json { render(json: @object.errors, status: :unprocessable_entity) }
end
@ -41,7 +44,10 @@ module CodeOcean
end
def file_params
params[:code_ocean_file].permit(file_attributes).merge(context_type: 'Submission', role: 'user_defined_file') if params[:code_ocean_file].present?
if params[:code_ocean_file].present?
params[:code_ocean_file].permit(file_attributes).merge(context_type: 'Submission',
role: 'user_defined_file')
end
end
private :file_params
end

View File

@ -7,7 +7,8 @@ class CodeharborLinksController < ApplicationController
def new
base_url = CodeOcean::Config.new(:code_ocean).read[:codeharbor][:url] || ''
@codeharbor_link = CodeharborLink.new(push_url: base_url + '/import_exercise', check_uuid_url: base_url + '/import_uuid_check')
@codeharbor_link = CodeharborLink.new(push_url: "#{base_url}/import_exercise",
check_uuid_url: "#{base_url}/import_uuid_check")
authorize!
end

View File

@ -1,8 +1,10 @@
# frozen_string_literal: true
class CommentsController < ApplicationController
before_action :set_comment, only: [:show, :edit, :update, :destroy]
before_action :set_comment, only: %i[show edit update destroy]
# to disable authorization check: comment the line below back in
# skip_after_action :verify_authorized
# skip_after_action :verify_authorized
def authorize!
authorize(@comment || @comments)
@ -12,16 +14,16 @@ class CommentsController < ApplicationController
# GET /comments.json
def index
file = CodeOcean::File.find(params[:file_id])
#there might be no submission yet, so dont use find
# there might be no submission yet, so dont use find
submission = Submission.find_by(id: file.context_id)
if submission
@comments = Comment.where(file_id: params[:file_id])
@comments.map{|comment|
@comments.map do |comment|
comment.username = comment.user.displayname
comment.date = comment.created_at.strftime('%d.%m.%Y %k:%M')
comment.updated = (comment.created_at != comment.updated_at)
comment.editable = comment.user == current_user
}
end
else
@comments = []
end
@ -81,9 +83,10 @@ class CommentsController < ApplicationController
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
#params.require(:comment).permit(:user_id, :file_id, :row, :column, :text)
# params.require(:comment).permit(:user_id, :file_id, :row, :column, :text)
# fuer production mode, damit böse menschen keine falsche user_id uebergeben:
params.require(:comment).permit(:file_id, :row, :column, :text, :request_id).merge(user_id: current_user.id, user_type: current_user.class.name)
params.require(:comment).permit(:file_id, :row, :column, :text, :request_id).merge(user_id: current_user.id,
user_type: current_user.class.name)
end
def send_mail_to_author(comment, request_for_comment)
@ -96,15 +99,14 @@ class CommentsController < ApplicationController
request_for_comment.commenters.each do |commenter|
already_sent_mail = false
subscriptions = Subscription.where(
:request_for_comment_id => request_for_comment.id,
:user_id => commenter.id, :user_type => commenter.class.name,
:deleted => false)
request_for_comment_id: request_for_comment.id,
user_id: commenter.id, user_type: commenter.class.name,
deleted: false
)
subscriptions.each do |subscription|
if (subscription.subscription_type == 'author' and current_user == request_for_comment.user) or subscription.subscription_type == 'all'
unless subscription.user == current_user or already_sent_mail
UserMailer.got_new_comment_for_subscription(comment, subscription, current_user).deliver_now
already_sent_mail = true
end
if (((subscription.subscription_type == 'author') && (current_user == request_for_comment.user)) || (subscription.subscription_type == 'all')) && !((subscription.user == current_user) || already_sent_mail)
UserMailer.got_new_comment_for_subscription(comment, subscription, current_user).deliver_now
already_sent_mail = true
end
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
module CommonBehavior
def create_and_respond(options = {})
@object = options[:object]
@ -5,7 +7,8 @@ module CommonBehavior
if @object.save
yield if block_given?
path = options[:path].try(:call) || @object
respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human), path: path, status: :created)
respond_with_valid_object(format, notice: t('shared.object_created', model: @object.class.model_name.human),
path: path, status: :created)
else
respond_with_invalid_object(format, template: :new)
end
@ -40,7 +43,8 @@ module CommonBehavior
respond_to do |format|
if @object.update(options[:params])
path = options[:path] || @object
respond_with_valid_object(format, notice: t('shared.object_updated', model: @object.class.model_name.human), path: path, status: :ok)
respond_with_valid_object(format, notice: t('shared.object_updated', model: @object.class.model_name.human),
path: path, status: :ok)
else
respond_with_invalid_object(format, template: :edit)
end

View File

@ -15,7 +15,8 @@ module FileParameters
private :reject_illegal_file_attributes
def file_attributes
%w[content context_id feedback_message file_id file_type_id hidden id name native_file path read_only role weight file_template_id]
%w[content context_id feedback_message file_id file_type_id hidden id name native_file path read_only role weight
file_template_id]
end
private :file_attributes
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'oauth/request_proxy/rack_request'
module Lti
@ -6,7 +8,7 @@ module Lti
MAXIMUM_SCORE = 1
MAXIMUM_SESSION_AGE = 60.minutes
SESSION_PARAMETERS = %w(launch_presentation_return_url lis_outcome_service_url lis_result_sourcedid)
SESSION_PARAMETERS = %w[launch_presentation_return_url lis_outcome_service_url lis_result_sourcedid].freeze
def build_tool_provider(options = {})
if options[:consumer] && options[:parameters]
@ -20,7 +22,7 @@ module Lti
# exercise_id.exists? ==> the user has submitted the results of an exercise to the consumer.
# Only the lti_parameters are deleted.
def clear_lti_session_data(exercise_id = nil, user_id = nil)
if (exercise_id.nil?)
if exercise_id.nil?
session.delete(:external_user_id)
session.delete(:study_group_id)
session.delete(:embed_options)
@ -48,27 +50,23 @@ module Lti
def external_user_name(provider)
# save person_name_full if supplied. this is the display_name, if it is set.
# else only save the firstname, we don't want lastnames (family names)
if provider.lis_person_name_full
provider.lis_person_name_full
else
provider.lis_person_name_given
end
provider.lis_person_name_full || provider.lis_person_name_given
end
private :external_user_name
def external_user_role(provider)
result = 'learner'
unless provider.roles.blank?
if provider.roles.present?
provider.roles.each do |role|
case role.downcase
when 'administrator'
# We don't want anyone to get admin privileges through LTI
result = 'teacher' if result == 'learner'
when 'instructor'
result = 'teacher' if result == 'learner'
else # 'learner'
next
when 'administrator'
# We don't want anyone to get admin privileges through LTI
result = 'teacher' if result == 'learner'
when 'instructor'
result = 'teacher' if result == 'learner'
else # 'learner'
next
end
end
end
@ -141,7 +139,9 @@ module Lti
def send_score(submission)
::NewRelic::Agent.add_custom_attributes({score: submission.normalized_score, session: session})
fail(Error, "Score #{submission.normalized_score} must be between 0 and #{MAXIMUM_SCORE}!") unless (0..MAXIMUM_SCORE).include?(submission.normalized_score)
unless (0..MAXIMUM_SCORE).cover?(submission.normalized_score)
raise Error.new("Score #{submission.normalized_score} must be between 0 and #{MAXIMUM_SCORE}!")
end
if submission.user.consumer
lti_parameter = LtiParameter.where(consumers_id: submission.user.consumer.id,
@ -155,12 +155,12 @@ module Lti
{status: 'error'}
elsif provider.outcome_service?
Sentry.set_extras({
provider: provider.inspect,
provider: provider.inspect,
score: submission.normalized_score,
lti_parameter: lti_parameter.inspect,
session: session.to_hash,
exercise_id: submission.exercise_id
})
exercise_id: submission.exercise_id,
})
normalized_lit_score = submission.normalized_score
if submission.before_deadline?
# Keep the full score
@ -170,11 +170,10 @@ module Lti
elsif submission.after_late_deadline?
# Reduce score by 100%
normalized_lit_score *= 0.0
else # no deadline
# Keep the full score
end
response = provider.post_replace_result!(normalized_lit_score)
{code: response.response_code, message: response.post_response.body, status: response.code_major, score_sent: normalized_lit_score}
{code: response.response_code, message: response.post_response.body, status: response.code_major,
score_sent: normalized_lit_score}
else
{status: 'unsupported'}
end
@ -186,22 +185,21 @@ module Lti
@current_user = ExternalUser.find_or_create_by(consumer_id: @consumer.id, external_id: @provider.user_id)
external_role = external_user_role(@provider)
internal_role = @current_user.role
desired_role = internal_role != 'admin' ? external_role : internal_role
desired_role = internal_role == 'admin' ? internal_role : external_role
# Update user with new information but change the role only if he is no admin user
@current_user.update(email: external_user_email(@provider), name: external_user_name(@provider), role: desired_role)
end
private :set_current_user
def set_study_group_membership
group = if not context_id?
StudyGroup.find_or_create_by(external_id: @provider.resource_link_id, consumer: @consumer)
else
group = if context_id?
# Ensure to find the group independent of the name and set it only once.
StudyGroup.find_or_create_by(external_id: @provider.context_id, consumer: @consumer) do |new_group|
new_group.name = @provider.context_title
end
else
StudyGroup.find_or_create_by(external_id: @provider.resource_link_id, consumer: @consumer)
end
group.external_users << @current_user unless group.external_users.include? @current_user
group.save

View File

@ -1,8 +1,13 @@
# frozen_string_literal: true
module RemoteEvaluationParameters
include FileParameters
def remote_evaluation_params
remote_evaluation_params = params[:remote_evaluation].permit(:validation_token, files_attributes: file_attributes) if params[:remote_evaluation].present?
if params[:remote_evaluation].present?
remote_evaluation_params = params[:remote_evaluation].permit(:validation_token,
files_attributes: file_attributes)
end
end
private :remote_evaluation_params
end
end

View File

@ -4,7 +4,12 @@ module SubmissionParameters
include FileParameters
def submission_params
submission_params = params[:submission].present? ? params[:submission].permit(:cause, :exercise_id, files_attributes: file_attributes) : {}
submission_params = if params[:submission].present?
params[:submission].permit(:cause, :exercise_id,
files_attributes: file_attributes)
else
{}
end
submission_params = merge_user(submission_params)
files_attributes = submission_params[:files_attributes]
exercise = Exercise.find_by(id: submission_params[:exercise_id])

View File

@ -12,8 +12,8 @@ module SubmissionScoring
output = execute_test_file(file, submission)
assessment = assessor.assess(output)
passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score]).positive?)
testrun_output = passed ? nil : 'status: ' + output[:status].to_s + "\n stdout: " + output[:stdout].to_s + "\n stderr: " + output[:stderr].to_s
unless testrun_output.blank?
testrun_output = passed ? nil : "status: #{output[:status]}\n stdout: #{output[:stdout]}\n stderr: #{output[:stderr]}"
if testrun_output.present?
submission.exercise.execution_environment.error_templates.each do |template|
pattern = Regexp.new(template.signature).freeze
StructuredError.create_from_template(template, testrun_output, submission) if pattern.match(testrun_output)
@ -50,7 +50,8 @@ module SubmissionScoring
private :collect_test_results
def execute_test_file(file, submission)
DockerClient.new(execution_environment: file.context.execution_environment).execute_test_command(submission, file.name_with_extension)
DockerClient.new(execution_environment: file.context.execution_environment).execute_test_command(submission,
file.name_with_extension)
end
private :execute_test_file
@ -69,17 +70,21 @@ module SubmissionScoring
def score_submission(submission)
outputs = collect_test_results(submission)
score = 0.0
unless outputs.nil? || outputs.empty?
if outputs.present?
outputs.each do |output|
score += output[:score] * output[:weight] unless output.nil?
output[:stderr] += "\n\n#{t('exercises.editor.timeout', permitted_execution_time: submission.exercise.execution_environment.permitted_execution_time.to_s)}" if output.present? && output[:status] == :timeout
if output.present? && output[:status] == :timeout
output[:stderr] += "\n\n#{t('exercises.editor.timeout',
permitted_execution_time: submission.exercise.execution_environment.permitted_execution_time.to_s)}"
end
end
end
submission.update(score: score)
if submission.normalized_score == 1.0
Thread.new do
RequestForComment.where(exercise_id: submission.exercise_id, user_id: submission.user_id, user_type: submission.user_type).each do |rfc|
RequestForComment.where(exercise_id: submission.exercise_id, user_id: submission.user_id,
user_type: submission.user_type).each do |rfc|
rfc.full_score_reached = true
rfc.save
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class ConsumersController < ApplicationController
include CommonBehavior
@ -18,8 +20,7 @@ class ConsumersController < ApplicationController
destroy_and_respond(object: @consumer)
end
def edit
end
def edit; end
def consumer_params
params[:consumer].permit(:name, :oauth_key, :oauth_secret) if params[:consumer].present?
@ -42,8 +43,7 @@ class ConsumersController < ApplicationController
end
private :set_consumer
def show
end
def show; end
def update
update_and_respond(object: @consumer, params: consumer_params)

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
class ErrorTemplateAttributesController < ApplicationController
before_action :set_error_template_attribute, only: [:show, :edit, :update, :destroy]
before_action :set_error_template_attribute, only: %i[show edit update destroy]
def authorize!
authorize(@error_template_attributes || @error_template_attribute)
@ -9,7 +11,8 @@ class ErrorTemplateAttributesController < ApplicationController
# GET /error_template_attributes
# GET /error_template_attributes.json
def index
@error_template_attributes = ErrorTemplateAttribute.all.order('important DESC', :key, :id).paginate(page: params[:page])
@error_template_attributes = ErrorTemplateAttribute.all.order('important DESC', :key,
:id).paginate(page: params[:page])
authorize!
end
@ -38,7 +41,9 @@ class ErrorTemplateAttributesController < ApplicationController
respond_to do |format|
if @error_template_attribute.save
format.html { redirect_to @error_template_attribute, notice: 'Error template attribute was successfully created.' }
format.html do
redirect_to @error_template_attribute, notice: 'Error template attribute was successfully created.'
end
format.json { render :show, status: :created, location: @error_template_attribute }
else
format.html { render :new }
@ -53,7 +58,9 @@ class ErrorTemplateAttributesController < ApplicationController
authorize!
respond_to do |format|
if @error_template_attribute.update(error_template_attribute_params)
format.html { redirect_to @error_template_attribute, notice: 'Error template attribute was successfully updated.' }
format.html do
redirect_to @error_template_attribute, notice: 'Error template attribute was successfully updated.'
end
format.json { render :show, status: :ok, location: @error_template_attribute }
else
format.html { render :edit }
@ -68,19 +75,25 @@ class ErrorTemplateAttributesController < ApplicationController
authorize!
@error_template_attribute.destroy
respond_to do |format|
format.html { redirect_to error_template_attributes_url, notice: 'Error template attribute was successfully destroyed.' }
format.html do
redirect_to error_template_attributes_url, notice: 'Error template attribute was successfully destroyed.'
end
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_error_template_attribute
@error_template_attribute = ErrorTemplateAttribute.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def error_template_attribute_params
params[:error_template_attribute].permit(:key, :description, :regex, :important) if params[:error_template_attribute].present?
# Use callbacks to share common setup or constraints between actions.
def set_error_template_attribute
@error_template_attribute = ErrorTemplateAttribute.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def error_template_attribute_params
if params[:error_template_attribute].present?
params[:error_template_attribute].permit(:key, :description, :regex,
:important)
end
end
end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
class ErrorTemplatesController < ApplicationController
before_action :set_error_template, only: [:show, :edit, :update, :destroy, :add_attribute, :remove_attribute]
before_action :set_error_template, only: %i[show edit update destroy add_attribute remove_attribute]
def authorize!
authorize(@error_templates || @error_template)
@ -92,13 +94,17 @@ class ErrorTemplatesController < ApplicationController
end
private
# Use callbacks to share common setup or constraints between actions.
def set_error_template
@error_template = ErrorTemplate.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def error_template_params
params[:error_template].permit(:name, :execution_environment_id, :signature, :description, :hint) if params[:error_template].present?
# Use callbacks to share common setup or constraints between actions.
def set_error_template
@error_template = ErrorTemplate.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def error_template_params
if params[:error_template].present?
params[:error_template].permit(:name, :execution_environment_id, :signature, :description,
:hint)
end
end
end

View File

@ -1,9 +1,11 @@
# frozen_string_literal: true
class ExecutionEnvironmentsController < ApplicationController
include CommonBehavior
before_action :set_docker_images, only: [:create, :edit, :new, :update]
before_action :set_execution_environment, only: MEMBER_ACTIONS + [:execute_command, :shell, :statistics]
before_action :set_testing_framework_adapters, only: [:create, :edit, :new, :update]
before_action :set_docker_images, only: %i[create edit new update]
before_action :set_execution_environment, only: MEMBER_ACTIONS + %i[execute_command shell statistics]
before_action :set_testing_framework_adapters, only: %i[create edit new update]
def authorize!
authorize(@execution_environment || @execution_environments)
@ -20,17 +22,15 @@ class ExecutionEnvironmentsController < ApplicationController
destroy_and_respond(object: @execution_environment)
end
def edit
end
def edit; end
def execute_command
@docker_client = DockerClient.new(execution_environment: @execution_environment)
render(json: @docker_client.execute_arbitrary_command(params[:command]))
end
def working_time_query
"""
"
SELECT exercise_id, avg(working_time) as average_time, stddev_samp(extract('epoch' from working_time)) * interval '1 second' as stddev_time
FROM
(
@ -52,11 +52,11 @@ class ExecutionEnvironmentsController < ApplicationController
GROUP BY exercise_id, user_id, id) AS foo) AS bar
GROUP BY user_id, exercise_id
) AS baz GROUP BY exercise_id;
"""
"
end
def user_query
"""
"
SELECT
id AS exercise_id,
COUNT(DISTINCT user_id) AS users,
@ -79,7 +79,7 @@ class ExecutionEnvironmentsController < ApplicationController
GROUP BY e.id,
s.user_id) AS inner_query
GROUP BY id;
"""
"
end
def statistics
@ -87,21 +87,25 @@ class ExecutionEnvironmentsController < ApplicationController
user_statistics = {}
ApplicationRecord.connection.execute(working_time_query).each do |tuple|
working_time_statistics[tuple["exercise_id"].to_i] = tuple
working_time_statistics[tuple['exercise_id'].to_i] = tuple
end
ApplicationRecord.connection.execute(user_query).each do |tuple|
user_statistics[tuple["exercise_id"].to_i] = tuple
user_statistics[tuple['exercise_id'].to_i] = tuple
end
render locals: {
working_time_statistics: working_time_statistics,
user_statistics: user_statistics
user_statistics: user_statistics,
}
end
def execution_environment_params
params[:execution_environment].permit(:docker_image, :exposed_ports, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :name, :network_enabled, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:execution_environment].present?
if params[:execution_environment].present?
params[:execution_environment].permit(:docker_image, :exposed_ports, :editor_mode, :file_extension, :file_type_id, :help, :indent_size, :memory_limit, :name, :network_enabled, :permitted_execution_time, :pool_size, :run_command, :test_command, :testing_framework).merge(
user_id: current_user.id, user_type: current_user.class.name
)
end
end
private :execution_environment_params
@ -118,10 +122,10 @@ class ExecutionEnvironmentsController < ApplicationController
def set_docker_images
DockerClient.check_availability!
@docker_images = DockerClient.image_tags.sort
rescue DockerClient::Error => error
rescue DockerClient::Error => e
@docker_images = []
flash[:warning] = error.message
Sentry.capture_exception(error)
flash[:warning] = e.message
Sentry.capture_exception(e)
end
private :set_docker_images
@ -139,8 +143,7 @@ class ExecutionEnvironmentsController < ApplicationController
end
private :set_testing_framework_adapters
def shell
end
def shell; end
def show
if @execution_environment.testing_framework?

View File

@ -1,15 +1,16 @@
# frozen_string_literal: true
class ExerciseCollectionsController < ApplicationController
include CommonBehavior
before_action :set_exercise_collection, only: [:show, :edit, :update, :destroy, :statistics]
before_action :set_exercise_collection, only: %i[show edit update destroy statistics]
def index
@exercise_collections = ExerciseCollection.all.paginate(:page => params[:page])
@exercise_collections = ExerciseCollection.all.paginate(page: params[:page])
authorize!
end
def show
end
def show; end
def new
@exercise_collection = ExerciseCollection.new
@ -28,16 +29,14 @@ class ExerciseCollectionsController < ApplicationController
destroy_and_respond(object: @exercise_collection)
end
def edit
end
def edit; end
def update
authorize!
update_and_respond(object: @exercise_collection, params: exercise_collection_params)
end
def statistics
end
def statistics; end
private
@ -51,8 +50,18 @@ class ExerciseCollectionsController < ApplicationController
end
def exercise_collection_params
sanitized_params = params[:exercise_collection].present? ? params[:exercise_collection].permit(:name, :use_anomaly_detection, :user_id, :user_type, :exercise_ids => []).merge(user_type: InternalUser.name) : {}
sanitized_params[:exercise_ids] = sanitized_params[:exercise_ids].reject {|v| v.nil? or v == ''}
sanitized_params.tap {|p| p[:exercise_collection_items] = p[:exercise_ids].map.with_index {|_id, index| ExerciseCollectionItem.find_or_create_by(exercise_id: _id, exercise_collection_id: @exercise_collection.id, position: index)}; p.delete(:exercise_ids)}
sanitized_params = if params[:exercise_collection].present?
params[:exercise_collection].permit(:name,
:use_anomaly_detection, :user_id, :user_type, exercise_ids: []).merge(user_type: InternalUser.name)
else
{}
end
sanitized_params[:exercise_ids] = sanitized_params[:exercise_ids].reject {|v| v.nil? or v == '' }
sanitized_params.tap do |p|
p[:exercise_collection_items] = p[:exercise_ids].map.with_index do |_id, index|
ExerciseCollectionItem.find_or_create_by(exercise_id: _id, exercise_collection_id: @exercise_collection.id, position: index)
end
p.delete(:exercise_ids)
end
end
end

View File

@ -9,15 +9,19 @@ class ExercisesController < ApplicationController
before_action :handle_file_uploads, only: %i[create update]
before_action :set_execution_environments, only: %i[create edit new update]
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + %i[clone implement working_times intervention search run statistics submit reload feedback requests_for_comments study_group_dashboard export_external_check export_external_confirm]
before_action :set_exercise_and_authorize,
only: MEMBER_ACTIONS + %i[clone implement working_times intervention search run statistics submit reload feedback
requests_for_comments study_group_dashboard export_external_check export_external_confirm]
before_action :set_external_user_and_authorize, only: [:statistics]
before_action :set_file_types, only: %i[create edit new update]
before_action :set_course_token, only: [:implement]
before_action :set_available_tips, only: %i[implement show new edit]
skip_before_action :verify_authenticity_token, only: %i[import_exercise import_uuid_check export_external_confirm export_external_check]
skip_before_action :verify_authenticity_token,
only: %i[import_exercise import_uuid_check export_external_confirm export_external_check]
skip_after_action :verify_authorized, only: %i[import_exercise import_uuid_check export_external_confirm]
skip_after_action :verify_policy_scoped, only: %i[import_exercise import_uuid_check export_external_confirm], raise: false
skip_after_action :verify_policy_scoped, only: %i[import_exercise import_uuid_check export_external_confirm],
raise: false
def authorize!
authorize(@exercise || @exercises)
@ -72,8 +76,8 @@ class ExercisesController < ApplicationController
return if performed?
myparam = exercise_params.presence || {}
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 }
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 }
checked_exercise_tags.each do |et|
et.factor = params[:tag_factors][et.tag_id.to_s][:factor]
@ -106,7 +110,8 @@ class ExercisesController < ApplicationController
end
def export_external_check
codeharbor_check = ExerciseService::CheckExternal.call(uuid: @exercise.uuid, codeharbor_link: current_user.codeharbor_link)
codeharbor_check = ExerciseService::CheckExternal.call(uuid: @exercise.uuid,
codeharbor_link: current_user.codeharbor_link)
render json: {
message: codeharbor_check[:message],
actions: render_to_string(
@ -116,9 +121,9 @@ class ExercisesController < ApplicationController
exercise_found: codeharbor_check[:exercise_found],
update_right: codeharbor_check[:update_right],
error: codeharbor_check[:error],
exported: false
exported: false,
}
)
),
}, status: :ok
end
@ -133,14 +138,16 @@ class ExercisesController < ApplicationController
render json: {
status: 'success',
message: t('exercises.export_codeharbor.successfully_exported', id: @exercise.id, title: @exercise.title),
actions: render_to_string(partial: 'export_actions', locals: {exercise: @exercise, exported: true, error: error})
actions: render_to_string(partial: 'export_actions',
locals: {exercise: @exercise, exported: true, error: error}),
}
@exercise.save
else
render json: {
status: 'fail',
message: t('exercises.export_codeharbor.export_failed', id: @exercise.id, title: @exercise.title, error: error),
actions: render_to_string(partial: 'export_actions', locals: {exercise: @exercise, exported: true, error: error})
actions: render_to_string(partial: 'export_actions',
locals: {exercise: @exercise, exported: true, error: error}),
}
end
end
@ -177,7 +184,7 @@ class ExercisesController < ApplicationController
render json: t('exercises.import_codeharbor.import_errors.invalid'), status: :bad_request
rescue StandardError => e
Sentry.capture_exception(e)
render json: t('exercises.import_codeharbor.import_errors.internal_error'), status: 500
render json: t('exercises.import_codeharbor.import_errors.internal_error'), status: :internal_server_error
end
def user_from_api_key
@ -194,7 +201,11 @@ class ExercisesController < ApplicationController
private :user_by_codeharbor_token
def exercise_params
params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :submission_deadline, :late_submission_deadline, :public, :unpublished, :hide_file_tree, :allow_file_creation, :allow_auto_completion, :title, :expected_difficulty, :tips, files_attributes: file_attributes, tag_ids: []).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:exercise].present?
if params[:exercise].present?
params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :submission_deadline, :late_submission_deadline, :public, :unpublished, :hide_file_tree, :allow_file_creation, :allow_auto_completion, :title, :expected_difficulty, :tips, files_attributes: file_attributes, tag_ids: []).merge(
user_id: current_user.id, user_type: current_user.class.name
)
end
end
private :exercise_params
@ -261,8 +272,10 @@ class ExercisesController < ApplicationController
redirect_to(@exercise, alert: t('exercises.implement.unpublished')) if @exercise.unpublished? && current_user.role != 'admin' && current_user.role != 'teacher' # TODO: TESTESTEST
redirect_to(@exercise, alert: t('exercises.implement.no_files')) unless @exercise.files.visible.exists?
user_solved_exercise = @exercise.has_user_solved(current_user)
count_interventions_today = UserExerciseIntervention.where(user: current_user).where('created_at >= ?', Time.zone.now.beginning_of_day).count
user_got_intervention_in_exercise = UserExerciseIntervention.where(user: current_user, exercise: @exercise).size >= max_intervention_count_per_exercise
count_interventions_today = UserExerciseIntervention.where(user: current_user).where('created_at >= ?',
Time.zone.now.beginning_of_day).count
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) || user_got_intervention_in_exercise
if @embed_options[:disable_interventions]
@ -331,14 +344,15 @@ class ExercisesController < ApplicationController
end
# Return an array with top-level tips
@tips = nested_tips.values.select { |tip| tip.parent_exercise_tip_id.nil? }
@tips = nested_tips.values.select {|tip| tip.parent_exercise_tip_id.nil? }
end
private :set_available_tips
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})
render(json: {working_time_75_percentile: working_time_75_percentile,
working_time_accumulated: working_time_accumulated})
end
def intervention
@ -436,7 +450,9 @@ class ExercisesController < ApplicationController
checked_exercise_tags = @exercise.exercise_tags
checked_tags = checked_exercise_tags.collect(&: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) }
@exercise_tags = checked_exercise_tags + unchecked_tags.collect do |tag|
ExerciseTag.new(exercise: @exercise, tag: tag)
end
end
private :collect_set_and_unset_exercise_tags
@ -453,8 +469,10 @@ class ExercisesController < ApplicationController
# Render statistics page for one specific external user
authorize(@external_user, :statistics?)
if policy(@exercise).detailed_statistics?
@submissions = Submission.where(user: @external_user, exercise_id: @exercise.id).in_study_group_of(current_user).order('created_at')
interventions = UserExerciseIntervention.where('user_id = ? AND exercise_id = ?', @external_user.id, @exercise.id)
@submissions = Submission.where(user: @external_user,
exercise_id: @exercise.id).in_study_group_of(current_user).order('created_at')
interventions = UserExerciseIntervention.where('user_id = ? AND exercise_id = ?', @external_user.id,
@exercise.id)
@all_events = (@submissions + interventions).sort_by(&:created_at)
@deltas = @all_events.map.with_index do |item, index|
delta = item.created_at - @all_events[index - 1].created_at if index.positive?
@ -465,7 +483,8 @@ class ExercisesController < ApplicationController
@working_times_until.push((format_time_difference(@deltas[0..index].inject(:+)) if index.positive?))
end
else
final_submissions = Submission.where(user: @external_user, exercise_id: @exercise.id).in_study_group_of(current_user).final
final_submissions = Submission.where(user: @external_user,
exercise_id: @exercise.id).in_study_group_of(current_user).final
@submissions = []
%i[before_deadline within_grace_period after_late_deadline].each do |filter|
relevant_submission = final_submissions.send(filter).latest
@ -492,7 +511,7 @@ class ExercisesController < ApplicationController
user_statistics[tuple['user_id'].to_i] = tuple
end
render locals: {
user_statistics: user_statistics
user_statistics: user_statistics,
}
end
end
@ -508,7 +527,8 @@ class ExercisesController < ApplicationController
end
def transmit_lti_score
::NewRelic::Agent.add_custom_attributes({submission: @submission.id, normalized_score: @submission.normalized_score})
::NewRelic::Agent.add_custom_attributes({submission: @submission.id,
normalized_score: @submission.normalized_score})
response = send_score(@submission)
if response[:status] == 'success'
@ -533,8 +553,8 @@ class ExercisesController < ApplicationController
return if performed?
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 }
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 }
checked_exercise_tags.each do |et|
et.factor = params[:tag_factors][et.tag_id.to_s][:factor]
@ -624,9 +644,9 @@ class ExercisesController < ApplicationController
authorize!
@study_group_id = params[:study_group_id]
@request_for_comments = RequestForComment
.where(exercise: @exercise).includes(:submission)
.where(submissions: {study_group_id: @study_group_id})
.order(created_at: :desc)
.where(exercise: @exercise).includes(:submission)
.where(submissions: {study_group_id: @study_group_id})
.order(created_at: :desc)
@graph_data = @exercise.get_working_times_for_study_group(@study_group_id)
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class ExternalUsersController < ApplicationController
before_action :require_user!
@ -17,8 +19,8 @@ class ExternalUsersController < ApplicationController
authorize!
end
def working_time_query(tag=nil)
"""
def working_time_query(tag = nil)
"
SELECT user_id,
bar.exercise_id,
max(score) as maximum_score,
@ -43,16 +45,16 @@ class ExternalUsersController < ApplicationController
FROM submissions
WHERE user_id = #{@user.id}
AND user_type = 'ExternalUser'
#{!current_user.admin? ? "AND study_group_id IN (#{current_user.study_groups.pluck(:id).join(', ')}) AND cause = 'submit'" : ''}
#{current_user.admin? ? '' : "AND study_group_id IN (#{current_user.study_groups.pluck(:id).join(', ')}) AND cause = 'submit'"}
GROUP BY exercise_id,
user_id,
id
) AS foo
) AS bar
#{tag.nil? ? '' : ' JOIN exercise_tags et ON et.exercise_id = bar.exercise_id AND et.tag_id = ' + tag + ' '}
#{tag.nil? ? '' : " JOIN exercise_tags et ON et.exercise_id = bar.exercise_id AND et.tag_id = #{tag} "}
GROUP BY user_id,
bar.exercise_id;
"""
"
end
def statistics
@ -62,11 +64,11 @@ class ExternalUsersController < ApplicationController
statistics = {}
ApplicationRecord.connection.execute(working_time_query(params[:tag])).each do |tuple|
statistics[tuple["exercise_id"].to_i] = tuple
statistics[tuple['exercise_id'].to_i] = tuple
end
render locals: {
statistics: statistics
statistics: statistics,
}
end
@ -75,15 +77,15 @@ class ExternalUsersController < ApplicationController
authorize!
statistics = []
tags = ProxyExercise.new().get_user_knowledge_and_max_knowledge(@user, @user.participations.uniq.compact)
tags = ProxyExercise.new.get_user_knowledge_and_max_knowledge(@user, @user.participations.uniq.compact)
tags[:user_topic_knowledge].each_pair do |tag, value|
statistics.append({key: tag.name.to_s, value: (100.0 / tags[:max_topic_knowledge][tag] * value).round, id: tag.id})
statistics.append({key: tag.name.to_s, value: (100.0 / tags[:max_topic_knowledge][tag] * value).round,
id: tag.id})
end
statistics.sort_by! {|item| -item[:value]}
statistics.sort_by! {|item| -item[:value] }
respond_to do |format|
format.json { render(json: statistics) }
end
end
end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
class FileTemplatesController < ApplicationController
before_action :set_file_template, only: [:show, :edit, :update, :destroy]
before_action :set_file_template, only: %i[show edit update destroy]
def authorize!
authorize(@file_template || @file_templates)
@ -7,7 +9,7 @@ class FileTemplatesController < ApplicationController
private :authorize!
def by_file_type
@file_templates = FileTemplate.where(:file_type_id => params[:file_type_id])
@file_templates = FileTemplate.where(file_type_id: params[:file_type_id])
authorize!
respond_to do |format|
format.json { render :show, status: :ok, json: @file_templates.to_json }
@ -82,13 +84,14 @@ class FileTemplatesController < ApplicationController
end
private
# Use callbacks to share common setup or constraints between actions.
def set_file_template
@file_template = FileTemplate.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def file_template_params
params[:file_template].permit(:name, :file_type_id, :content) if params[:file_template].present?
end
# Use callbacks to share common setup or constraints between actions.
def set_file_template
@file_template = FileTemplate.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def file_template_params
params[:file_template].permit(:name, :file_type_id, :content) if params[:file_template].present?
end
end

View File

@ -1,7 +1,9 @@
# frozen_string_literal: true
class FileTypesController < ApplicationController
include CommonBehavior
before_action :set_editor_modes, only: [:create, :edit, :new, :update]
before_action :set_editor_modes, only: %i[create edit new update]
before_action :set_file_type, only: MEMBER_ACTIONS
def authorize!
@ -19,11 +21,14 @@ class FileTypesController < ApplicationController
destroy_and_respond(object: @file_type)
end
def edit
end
def edit; end
def file_type_params
params[:file_type].permit(:binary, :editor_mode, :executable, :file_extension, :name, :indent_size, :renderable).merge(user_id: current_user.id, user_type: current_user.class.name) if params[:file_type].present?
if params[:file_type].present?
params[:file_type].permit(:binary, :editor_mode, :executable, :file_extension, :name, :indent_size, :renderable).merge(
user_id: current_user.id, user_type: current_user.class.name
)
end
end
private :file_type_params
@ -39,7 +44,7 @@ class FileTypesController < ApplicationController
def set_editor_modes
@editor_modes = Dir.glob('vendor/assets/javascripts/ace/mode-*.js').sort.map do |filename|
name = filename.gsub(/\w+\/|mode-|.js$/, '')
name = filename.gsub(%r{\w+/|mode-|.js$}, '')
[name, "ace/mode/#{name}"]
end
end
@ -51,8 +56,7 @@ class FileTypesController < ApplicationController
end
private :set_file_type
def show
end
def show; end
def update
update_and_respond(object: @file_type, params: file_type_params)

View File

@ -1,11 +1,12 @@
class FlowrController < ApplicationController
# frozen_string_literal: true
class FlowrController < ApplicationController
def insights
require_user!
# get the latest submission for this user that also has a test run (i.e. structured_errors if applicable)
submission = Submission.joins(:testruns)
.where(submissions: {user_id: current_user.id, user_type: current_user.class.name})
.order('testruns.created_at DESC').first
.where(submissions: {user_id: current_user.id, user_type: current_user.class.name})
.order('testruns.created_at DESC').first
# Return if no submission was found
if submission.blank? || @embed_options[:disable_hints] || @embed_options[:hide_test_results]
@ -26,8 +27,8 @@ class FlowrController < ApplicationController
end
# once the programming language model becomes available, the language name can be added to the query to
# produce more relevant results
query = attributes.map{|att| att.value}.join(' ')
{ submission: submission, error: error, attributes: attributes, query: query }
query = attributes.map(&:value).join(' ')
{submission: submission, error: error, attributes: attributes, query: query}
end
# Always return JSON

View File

@ -93,7 +93,8 @@ class InternalUsersController < ApplicationController
private :require_reset_password_token
def require_token(type)
@user = InternalUser.send(:"load_from_#{type}_token", params[:token] || params[:internal_user].try(:[], :"#{type}_token"))
@user = InternalUser.send(:"load_from_#{type}_token",
params[:token] || params[:internal_user].try(:[], :"#{type}_token"))
render_not_authorized unless @user
end
private :require_token

View File

@ -1,7 +1,9 @@
# frozen_string_literal: true
class ProxyExercisesController < ApplicationController
include CommonBehavior
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :reload]
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + %i[clone reload]
def authorize!
authorize(@proxy_exercise || @proxy_exercises)
@ -9,10 +11,11 @@ class ProxyExercisesController < ApplicationController
private :authorize!
def clone
proxy_exercise = @proxy_exercise.duplicate(public: false, token: nil, exercises: @proxy_exercise.exercises, user: current_user)
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))
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)
@ -21,7 +24,7 @@ class ProxyExercisesController < ApplicationController
def create
myparams = proxy_exercise_params
myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject { |c| c.empty? })
myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject(&:empty?))
@proxy_exercise = ProxyExercise.new(myparams)
authorize!
@ -39,7 +42,10 @@ class ProxyExercisesController < ApplicationController
end
def proxy_exercise_params
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?
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)
end
end
private :proxy_exercise_params
@ -50,7 +56,7 @@ class ProxyExercisesController < ApplicationController
end
def new
@proxy_exercise = ProxyExercise.new
@proxy_exercise = ProxyExercise.new
@search = policy_scope(Exercise).ransack(params[:q])
@exercises = @search.result.order(:title)
authorize!
@ -64,17 +70,15 @@ class ProxyExercisesController < ApplicationController
def show
@search = @proxy_exercise.exercises.ransack
@exercises = @proxy_exercise.exercises.ransack.result.order(:title) #@search.result.order(:title)
@exercises = @proxy_exercise.exercises.ransack.result.order(:title) # @search.result.order(:title)
end
#we might want to think about auth here
def reload
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? })
myparams[:exercises] = Exercise.find(myparams[:exercise_ids].reject(&:blank?))
update_and_respond(object: @proxy_exercise, params: myparams)
end
end

View File

@ -26,7 +26,7 @@ class RemoteEvaluationController < ApplicationController
if @submission.present?
score_achieved_percentage = @submission.normalized_score
result = try_lti
result.merge!({score: score_achieved_percentage * 100}) unless result[:score]
result[:score] = score_achieved_percentage * 100 unless result[:score]
status = result[:status]
end
@ -38,7 +38,9 @@ class RemoteEvaluationController < ApplicationController
lti_response = send_score(@submission)
process_lti_response(lti_response)
else
{message: "Your submission was successfully scored with #{@submission.normalized_score}%. However, your score could not be sent to the e-Learning platform. Please reopen the exercise through the e-Learning platform and try again.", status: 410}
{
message: "Your submission was successfully scored with #{@submission.normalized_score}%. However, your score could not be sent to the e-Learning platform. Please reopen the exercise through the e-Learning platform and try again.", status: 410
}
end
end
private :try_lti
@ -48,7 +50,8 @@ class RemoteEvaluationController < ApplicationController
# Score has been reduced due to the passed deadline
{message: I18n.t('exercises.submit.too_late'), status: 207, score: lti_response[:score_sent] * 100}
elsif lti_response[:status] == 'success'
{message: I18n.t('sessions.destroy_through_lti.success_with_outcome', consumer: @submission.user.consumer.name), status: 202}
{message: I18n.t('sessions.destroy_through_lti.success_with_outcome', consumer: @submission.user.consumer.name),
status: 202}
else
{message: I18n.t('exercises.submit.failure'), status: 424}
end
@ -77,7 +80,8 @@ class RemoteEvaluationController < ApplicationController
submission_params[:study_group_id] = remote_evaluation_mapping.study_group_id
submission_params[:cause] = cause
submission_params[:user_type] = remote_evaluation_mapping.user_type
submission_params[:files_attributes] = reject_illegal_file_attributes(remote_evaluation_mapping.exercise, files_attributes)
submission_params[:files_attributes] =
reject_illegal_file_attributes(remote_evaluation_mapping.exercise, files_attributes)
submission_params
end
private :build_submission_params

View File

@ -5,7 +5,8 @@ class RequestForCommentsController < ApplicationController
before_action :require_user!
before_action :set_request_for_comment, only: %i[show mark_as_solved set_thank_you_note]
before_action :set_study_group_grouping, only: %i[index get_my_comment_requests get_rfcs_with_my_comments get_rfcs_for_exercise]
before_action :set_study_group_grouping,
only: %i[index get_my_comment_requests get_rfcs_with_my_comments get_rfcs_for_exercise]
def authorize!
authorize(@request_for_comments || @request_for_comment)
@ -16,15 +17,15 @@ class RequestForCommentsController < ApplicationController
# GET /request_for_comments.json
def index
@search = RequestForComment
.last_per_user(2)
.with_last_activity
.ransack(params[:q])
.last_per_user(2)
.with_last_activity
.ransack(params[:q])
@request_for_comments = @search.result
.joins(:exercise)
.where(exercises: {unpublished: false})
.includes(submission: [:study_group])
.order('created_at DESC')
.paginate(page: params[:page], total_entries: @search.result.length)
.joins(:exercise)
.where(exercises: {unpublished: false})
.includes(submission: [:study_group])
.order('created_at DESC')
.paginate(page: params[:page], total_entries: @search.result.length)
authorize!
end
@ -32,12 +33,12 @@ class RequestForCommentsController < ApplicationController
# GET /my_request_for_comments
def get_my_comment_requests
@search = RequestForComment
.with_last_activity
.where(user: current_user)
.ransack(params[:q])
.with_last_activity
.where(user: current_user)
.ransack(params[:q])
@request_for_comments = @search.result
.order('created_at DESC')
.paginate(page: params[:page])
.order('created_at DESC')
.paginate(page: params[:page])
authorize!
render 'index'
end
@ -45,13 +46,13 @@ class RequestForCommentsController < ApplicationController
# GET /my_rfc_activity
def get_rfcs_with_my_comments
@search = RequestForComment
.with_last_activity
.joins(:comments) # we don't need to outer join here, because we know the user has commented on these
.where(comments: {user_id: current_user.id})
.ransack(params[:q])
.with_last_activity
.joins(:comments) # we don't need to outer join here, because we know the user has commented on these
.where(comments: {user_id: current_user.id})
.ransack(params[:q])
@request_for_comments = @search.result
.order('last_comment DESC')
.paginate(page: params[:page])
.order('last_comment DESC')
.paginate(page: params[:page])
authorize!
render 'index'
end
@ -60,13 +61,13 @@ class RequestForCommentsController < ApplicationController
def get_rfcs_for_exercise
exercise = Exercise.find(params[:exercise_id])
@search = RequestForComment
.with_last_activity
.where(exercise_id: exercise.id)
.ransack(params[:q])
.with_last_activity
.where(exercise_id: exercise.id)
.ransack(params[:q])
@request_for_comments = @search.result
.joins(:exercise)
.order('last_comment DESC')
.paginate(page: params[:page])
.joins(:exercise)
.order('last_comment DESC')
.paginate(page: params[:page])
# let the exercise decide, whether its rfcs should be visible
authorize(exercise)
render 'index'
@ -91,7 +92,7 @@ class RequestForCommentsController < ApplicationController
@request_for_comment.thank_you_note = params[:note]
commenters = @request_for_comment.commenters
commenters.each { |commenter| UserMailer.send_thank_you_note(@request_for_comment, commenter).deliver_now }
commenters.each {|commenter| UserMailer.send_thank_you_note(@request_for_comment, commenter).deliver_now }
respond_to do |format|
if @request_for_comment.save
@ -143,14 +144,16 @@ class RequestForCommentsController < ApplicationController
# Never trust parameters from the scary internet, only allow the white list through.
def request_for_comment_params
# The study_group_id might not be present in the session (e.g. for internal users), resulting in session[:study_group_id] = nil which is intended.
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)
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
# The index page requires the grouping of the study groups
# The study groups are grouped by the current study group and other study groups of the user
def set_study_group_grouping
current_study_group = StudyGroup.find_by(id: session[:study_group_id])
my_study_groups = current_user.study_groups.reject { |group| group == current_study_group }
my_study_groups = current_user.study_groups.reject {|group| group == current_study_group }
@study_groups_grouping = [[t('request_for_comments.index.study_groups.current'), Array(current_study_group)],
[t('request_for_comments.index.study_groups.my'), my_study_groups]]
end

View File

@ -1,7 +1,10 @@
# frozen_string_literal: true
class SessionsController < ApplicationController
include Lti
[: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|
%i[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
@ -24,8 +27,8 @@ class SessionsController < ApplicationController
redirect_to(params[:custom_redirect_target])
else
redirect_to(implement_exercise_path(@exercise),
notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id) ? 'with' : 'without'}_outcome",
consumer: @consumer))
notice: t("sessions.create_through_lti.session_#{lti_outcome_service?(@exercise.id, @current_user.id) ? 'with' : 'without'}_outcome",
consumer: @consumer))
end
end

View File

@ -1,8 +1,10 @@
# frozen_string_literal: true
class StatisticsController < ApplicationController
include StatisticsHelper
before_action :authorize!, only: [:show, :graphs, :user_activity, :user_activity_history, :rfc_activity,
:rfc_activity_history]
before_action :authorize!, only: %i[show graphs user_activity user_activity_history rfc_activity
rfc_activity_history]
def policy_class
StatisticsPolicy
@ -15,8 +17,7 @@ class StatisticsController < ApplicationController
end
end
def graphs
end
def graphs; end
def user_activity
respond_to do |format|
@ -27,7 +28,7 @@ class StatisticsController < ApplicationController
def user_activity_history
respond_to do |format|
format.html { render('activity_history', locals: {resource: :user}) }
format.json { render_ranged_data :ranged_user_data}
format.json { render_ranged_data :ranged_user_data }
end
end
@ -46,14 +47,21 @@ class StatisticsController < ApplicationController
def render_ranged_data(data_source)
interval = params[:interval].to_s.empty? ? 'year' : params[:interval]
from = DateTime.strptime(params[:from], '%Y-%m-%d') rescue DateTime.new(0)
to = DateTime.strptime(params[:to], '%Y-%m-%d') rescue DateTime.now
render(json: self.send(data_source, interval, from, to))
from = begin
DateTime.strptime(params[:from], '%Y-%m-%d')
rescue StandardError
DateTime.new(0)
end
to = begin
DateTime.strptime(params[:to], '%Y-%m-%d')
rescue StandardError
DateTime.now
end
render(json: send(data_source, interval, from, to))
end
def authorize!
authorize self
end
private :authorize!
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class StudyGroupsController < ApplicationController
include CommonBehavior
@ -20,7 +22,8 @@ class StudyGroupsController < ApplicationController
def update
myparams = study_group_params
myparams[:external_users] = StudyGroupMembership.find(myparams[:study_group_membership_ids].reject(&:empty?)).map(&:user)
myparams[:external_users] =
StudyGroupMembership.find(myparams[:study_group_membership_ids].reject(&:empty?)).map(&:user)
myparams.delete(:study_group_membership_ids)
update_and_respond(object: @study_group, params: myparams)
end
@ -30,7 +33,7 @@ class StudyGroupsController < ApplicationController
end
def study_group_params
params[:study_group].permit(:id, :name, :study_group_membership_ids => []) if params[:study_group].present?
params[:study_group].permit(:id, :name, study_group_membership_ids: []) if params[:study_group].present?
end
private :study_group_params
@ -44,5 +47,4 @@ class StudyGroupsController < ApplicationController
authorize(@study_groups || @study_group)
end
private :authorize!
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class SubmissionsController < ApplicationController
include ActionController::Live
include CommonBehavior
@ -6,15 +8,16 @@ class SubmissionsController < ApplicationController
include SubmissionScoring
include Tubesock::Hijack
before_action :set_submission, only: [:download, :download_file, :render_file, :run, :score, :extract_errors, :show, :statistics, :stop, :test]
before_action :set_docker_client, only: [:run, :test]
before_action :set_files, only: [:download, :download_file, :render_file, :show, :run]
before_action :set_file, only: [:download_file, :render_file, :run]
before_action :set_mime_type, only: [:download_file, :render_file]
skip_before_action :verify_authenticity_token, only: [:download_file, :render_file]
before_action :set_submission,
only: %i[download download_file render_file run score extract_errors show statistics stop test]
before_action :set_docker_client, only: %i[run test]
before_action :set_files, only: %i[download download_file render_file show run]
before_action :set_file, only: %i[download_file render_file run]
before_action :set_mime_type, only: %i[download_file render_file]
skip_before_action :verify_authenticity_token, only: %i[download_file render_file]
def max_run_output_buffer_size
if(@submission.cause == 'requestComments')
if @submission.cause == 'requestComments'
5000
else
500
@ -34,30 +37,30 @@ class SubmissionsController < ApplicationController
end
def command_substitutions(filename)
{class_name: File.basename(filename, File.extname(filename)).camelize, filename: filename, module_name: File.basename(filename, File.extname(filename)).underscore}
{class_name: File.basename(filename, File.extname(filename)).camelize, filename: filename,
module_name: File.basename(filename, File.extname(filename)).underscore}
end
private :command_substitutions
def copy_comments
# copy each annotation and set the target_file.id
unless(params[:annotations_arr].nil?)
params[:annotations_arr].each do | annotation |
#comment = Comment.new(annotation[1].permit(:user_id, :file_id, :user_type, :row, :column, :text, :created_at, :updated_at))
comment = Comment.new(:user_id => annotation[1][:user_id], :file_id => annotation[1][:file_id], :user_type => current_user.class.name, :row => annotation[1][:row], :column => annotation[1][:column], :text => annotation[1][:text])
source_file = CodeOcean::File.find(annotation[1][:file_id])
params[:annotations_arr]&.each do |annotation|
# comment = Comment.new(annotation[1].permit(:user_id, :file_id, :user_type, :row, :column, :text, :created_at, :updated_at))
comment = Comment.new(user_id: annotation[1][:user_id], file_id: annotation[1][:file_id],
user_type: current_user.class.name, row: annotation[1][:row], column: annotation[1][:column], text: annotation[1][:text])
source_file = CodeOcean::File.find(annotation[1][:file_id])
# retrieve target file
target_file = @submission.files.detect do |file|
# file_id has to be that of a the former iteration OR of the initial file (if this is the first run)
file.file_id == source_file.file_id || file.file_id == source_file.id #seems to be needed here: (check this): || file.file_id == source_file.id ; yes this is needed, for comments on templates as well as comments on files added by users.
end
#save to assign an id
target_file.save!
comment.file_id = target_file.id
comment.save!
# retrieve target file
target_file = @submission.files.detect do |file|
# file_id has to be that of a the former iteration OR of the initial file (if this is the first run)
file.file_id == source_file.file_id || file.file_id == source_file.id # seems to be needed here: (check this): || file.file_id == source_file.id ; yes this is needed, for comments on templates as well as comments on files added by users.
end
# save to assign an id
target_file.save!
comment.file_id = target_file.id
comment.save!
end
end
@ -75,30 +78,35 @@ class SubmissionsController < ApplicationController
require 'zip'
stringio = Zip::OutputStream.write_buffer do |zio|
@files.each do |file|
zio.put_next_entry(file.path.to_s == '' ? file.name_with_extension : File.join(file.path, file.name_with_extension))
zio.write(file.content.present? ? file.content : file.native_file.read)
zio.put_next_entry(if file.path.to_s == ''
file.name_with_extension
else
File.join(file.path,
file.name_with_extension)
end)
zio.write(file.content.presence || file.native_file.read)
end
# zip exercise description
zio.put_next_entry(t('activerecord.models.exercise.one') + '.txt')
zio.write(@submission.exercise.title + "\r\n======================\r\n")
zio.put_next_entry("#{t('activerecord.models.exercise.one')}.txt")
zio.write("#{@submission.exercise.title}\r\n======================\r\n")
zio.write(@submission.exercise.description)
# zip .co file
zio.put_next_entry(".co")
zio.write(File.read id_file)
zio.put_next_entry('.co')
zio.write(File.read(id_file))
File.delete(id_file) if File.exist?(id_file)
# zip client scripts
scripts_path = 'app/assets/remote_scripts'
Dir.foreach(scripts_path) do |file|
next if file == '.' or file == '..'
zio.put_next_entry(File.join('.scripts', File.basename(file)))
zio.write(File.read File.join(scripts_path, file))
end
next if (file == '.') || (file == '..')
zio.put_next_entry(File.join('.scripts', File.basename(file)))
zio.write(File.read(File.join(scripts_path, file)))
end
end
send_data(stringio.string, filename: @submission.exercise.title.tr(" ", "_") + ".zip")
send_data(stringio.string, filename: "#{@submission.exercise.title.tr(' ', '_')}.zip")
end
def download_file
@ -128,7 +136,7 @@ class SubmissionsController < ApplicationController
end
def run
# TODO reimplement SSEs with websocket commands
# TODO: reimplement SSEs with websocket commands
# with_server_sent_events do |server_sent_event|
# output = @docker_client.execute_run_command(@submission, sanitize_filename)
@ -155,56 +163,54 @@ class SubmissionsController < ApplicationController
end
end
# socket is the socket into the container, tubesock is the socket to the client
# give the docker_client the tubesock object, so that it can send messages (timeout)
@docker_client.tubesock = tubesock
container_request_time = Time.now
container_request_time = Time.zone.now
result = @docker_client.execute_run_command(@submission, sanitize_filename)
tubesock.send_data JSON.dump({'cmd' => 'status', 'status' => result[:status]})
@waiting_for_container_time = Time.now - container_request_time
@waiting_for_container_time = Time.zone.now - container_request_time
if result[:status] == :container_running
socket = result[:socket]
command = result[:command]
socket.on :message do |event|
Rails.logger.info( Time.now.getutc.to_s + ": Docker sending: " + event.data)
Rails.logger.info("#{Time.zone.now.getutc}: Docker sending: #{event.data}")
handle_message(event.data, tubesock, result[:container])
end
socket.on :close do |event|
socket.on :close do |_event|
kill_socket(tubesock)
end
tubesock.onmessage do |data|
Rails.logger.info(Time.now.getutc.to_s + ": Client sending: " + data)
Rails.logger.info("#{Time.zone.now.getutc}: Client sending: #{data}")
# Check whether the client send a JSON command and kill container
# if the command is 'client_kill', send it to docker otherwise.
begin
parsed = JSON.parse(data) unless data == "\n"
if parsed.class == Hash && parsed['cmd'] == 'client_kill'
Rails.logger.debug("Client exited container.")
if parsed.instance_of?(Hash) && parsed['cmd'] == 'client_kill'
Rails.logger.debug('Client exited container.')
@docker_client.kill_container(result[:container])
else
socket.send data
Rails.logger.debug('Sent the received client data to docker:' + data)
Rails.logger.debug("Sent the received client data to docker:#{data}")
end
rescue JSON::ParserError => error
rescue JSON::ParserError => e
socket.send data
Rails.logger.debug('Rescued parsing error, sent the received client data to docker:' + data)
Rails.logger.debug("Rescued parsing error, sent the received client data to docker:#{data}")
Sentry.set_extras(data: data)
end
end
# Send command after all listeners are attached.
# Newline required to flush
@execution_request_time = Time.now
socket.send command + "\n"
Rails.logger.info('Sent command: ' + command.to_s)
@execution_request_time = Time.zone.now
socket.send "#{command}\n"
Rails.logger.info("Sent command: #{command}")
else
kill_socket(tubesock)
end
@ -212,7 +218,7 @@ class SubmissionsController < ApplicationController
end
def kill_socket(tubesock)
@container_execution_time = Time.now - @execution_request_time unless @execution_request_time.blank?
@container_execution_time = Time.zone.now - @execution_request_time if @execution_request_time.present?
# search for errors and save them as StructuredError (for scoring runs see submission_scoring.rb)
errors = extract_errors
send_hints(tubesock, errors)
@ -225,7 +231,7 @@ class SubmissionsController < ApplicationController
if @run_output.blank? || @run_output&.strip == '{"cmd":"exit"}' || @run_output&.strip == 'timeout:'
@raw_output ||= ''
@run_output ||= ''
parse_message t('exercises.implement.no_output', timestamp: l(Time.now, format: :short)), 'stdout', tubesock
parse_message t('exercises.implement.no_output', timestamp: l(Time.zone.now, format: :short)), 'stdout', tubesock
end
# Hijacked connection needs to be notified correctly
@ -237,25 +243,26 @@ class SubmissionsController < ApplicationController
@raw_output ||= ''
@run_output ||= ''
# Handle special commands first
if /^#exit|{"cmd": "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)
@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(sanitize_filename)
test_command = @submission.execution_environment.test_command % command_substitutions(sanitize_filename)
if test_command.blank?
# If no test command is set, use the run_command for the RegEx below. Otherwise, no output will be displayed!
test_command = run_command
end
unless /root@|:\/workspace|#{run_command}|#{test_command}|bash: cmd:canvasevent: command not found/.match(message)
parse_message(message, 'stdout', tubesock, container)
end
case message
when /^#exit|{"cmd": "exit"}/
# 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)
when /^#timeout/
@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(sanitize_filename)
test_command = @submission.execution_environment.test_command % command_substitutions(sanitize_filename)
if test_command.blank?
# If no test command is set, use the run_command for the RegEx below. Otherwise, no output will be displayed!
test_command = run_command
end
unless %r{root@|:/workspace|#{run_command}|#{test_command}|bash: cmd:canvasevent: command not found}.match?(message)
parse_message(message, 'stdout', tubesock, container)
end
end
end
@ -263,58 +270,58 @@ class SubmissionsController < ApplicationController
parsed = ''
begin
parsed = JSON.parse(message)
if parsed.class == Hash and parsed.key?('cmd')
if parsed.instance_of?(Hash) && parsed.key?('cmd')
socket.send_data message
Rails.logger.info('parse_message sent: ' + message)
Rails.logger.info("parse_message sent: #{message}")
@docker_client.exit_container(container) if container && parsed['cmd'] == 'exit'
else
parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>message}
parsed = {'cmd' => 'write', 'stream' => output_stream, 'data' => message}
socket.send_data JSON.dump(parsed)
Rails.logger.info('parse_message sent: ' + JSON.dump(parsed))
Rails.logger.info("parse_message sent: #{JSON.dump(parsed)}")
end
rescue JSON::ParserError => e
# Check wether the message contains multiple lines, if true try to parse each line
if recursive and message.include? "\n"
for part in message.split("\n")
self.parse_message(part,output_stream,socket, container, false)
if recursive && message.include?("\n")
message.split("\n").each do |part|
parse_message(part, output_stream, socket, container, false)
end
elsif message.include?('<img') || message.start_with?('{"cmd') || message.include?('"turtlebatch"')
#Rails.logger.info('img foung')
# Rails.logger.info('img foung')
@buffering = true
@buffer = ''
@buffer += message
#Rails.logger.info('Starting to buffer')
elsif @buffering and message.include?('/>')
# Rails.logger.info('Starting to buffer')
elsif @buffering && message.include?('/>')
@buffer += message
parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>@buffer}
parsed = {'cmd' => 'write', 'stream' => output_stream, 'data' => @buffer}
socket.send_data JSON.dump(parsed)
#socket.send_data @buffer
# socket.send_data @buffer
@buffering = false
#Rails.logger.info('Sent complete buffer')
elsif @buffering and message.end_with?("}\r")
# Rails.logger.info('Sent complete buffer')
elsif @buffering && message.end_with?("}\r")
@buffer += message
socket.send_data @buffer
@buffering = false
#Rails.logger.info('Sent complete buffer')
# Rails.logger.info('Sent complete buffer')
elsif @buffering
@buffer += message
#Rails.logger.info('Appending to buffer')
# Rails.logger.info('Appending to buffer')
else
#Rails.logger.info('else')
parsed = {'cmd'=>'write','stream'=>output_stream,'data'=>message}
# Rails.logger.info('else')
parsed = {'cmd' => 'write', 'stream' => output_stream, 'data' => message}
socket.send_data JSON.dump(parsed)
Rails.logger.info('parse_message sent: ' + JSON.dump(parsed))
Rails.logger.info("parse_message sent: #{JSON.dump(parsed)}")
end
ensure
@raw_output += parsed['data'].to_s if parsed.class == Hash and parsed.key? 'data'
@raw_output += parsed['data'].to_s if parsed.instance_of?(Hash) && parsed.key?('data')
# save the data that was send to the run_output if there is enough space left. this will be persisted as a testrun with cause "run"
@run_output += JSON.dump(parsed).to_s if @run_output.size <= max_run_output_buffer_size
end
end
def save_run_output
unless @run_output.blank?
@run_output = @run_output[(0..max_run_output_buffer_size-1)] # trim the string to max_message_buffer_size chars
if @run_output.present?
@run_output = @run_output[(0..max_run_output_buffer_size - 1)] # trim the string to max_message_buffer_size chars
Testrun.create(
file: @file,
cause: 'run',
@ -328,7 +335,7 @@ class SubmissionsController < ApplicationController
def extract_errors
results = []
unless @raw_output.blank?
if @raw_output.present?
@submission.exercise.execution_environment.error_templates.each do |template|
pattern = Regexp.new(template.signature).freeze
if pattern.match(@raw_output)
@ -361,7 +368,7 @@ class SubmissionsController < ApplicationController
tubesock.send_data JSON.dump(score_submission(@submission))
# To enable hints when scoring a submission, uncomment the next line:
#send_hints(tubesock, StructuredError.where(submission: @submission))
# send_hints(tubesock, StructuredError.where(submission: @submission))
tubesock.send_data JSON.dump({'cmd' => 'exit'})
ensure
@ -372,8 +379,9 @@ class SubmissionsController < ApplicationController
def send_hints(tubesock, errors)
return if @embed_options[:disable_hints]
errors = errors.to_a.uniq { |e| e.hint}
errors.each do | error |
errors = errors.to_a.uniq(&:hint)
errors.each do |error|
tubesock.send_data JSON.dump({cmd: 'hint', hint: error.hint, description: error.error_template.description})
end
end
@ -384,7 +392,7 @@ class SubmissionsController < ApplicationController
private :set_docker_client
def set_file
@file = @files.detect { |file| file.name_with_extension == sanitize_filename }
@file = @files.detect {|file| file.name_with_extension == sanitize_filename }
head :not_found unless @file
end
private :set_file
@ -406,11 +414,9 @@ class SubmissionsController < ApplicationController
end
private :set_submission
def show
end
def show; end
def statistics
end
def statistics; end
def test
hijack do |tubesock|
@ -436,10 +442,10 @@ class SubmissionsController < ApplicationController
server_sent_event.write(nil, event: 'start')
yield(server_sent_event) if block_given?
server_sent_event.write({code: 200}, event: 'close')
rescue => exception
Sentry.capture_exception(exception)
logger.error(exception.message)
logger.error(exception.backtrace.join("\n"))
rescue StandardError => e
Sentry.capture_exception(e)
logger.error(e.message)
logger.error(e.backtrace.join("\n"))
server_sent_event.write({code: 500}, event: 'close')
ensure
server_sent_event.close
@ -457,16 +463,16 @@ class SubmissionsController < ApplicationController
)
# create .co file
path = "tmp/" + user.id.to_s + ".co"
path = "tmp/#{user.id}.co"
# parse validation token
content = "#{remote_evaluation_mapping.validation_token}\n"
# parse remote request url
content += "#{request.base_url}/evaluate\n"
@submission.files.each do |file|
file_path = file.path.to_s == '' ? file.name_with_extension : File.join(file.path, file.name_with_extension)
content += "#{file_path}=#{file.file_id.to_s}\n"
content += "#{file_path}=#{file.file_id}\n"
end
File.open(path, "w+") do |f|
File.open(path, 'w+') do |f|
f.write(content)
end
path

View File

@ -1,5 +1,6 @@
class SubscriptionsController < ApplicationController
# frozen_string_literal: true
class SubscriptionsController < ApplicationController
def authorize!
authorize(@subscription || @subscriptions)
end
@ -21,28 +22,26 @@ class SubscriptionsController < ApplicationController
# DELETE /subscriptions/1
# DELETE /subscriptions/1.json
def destroy
begin
@subscription = Subscription.find(params[:id])
rescue
skip_authorization
@subscription = Subscription.find(params[:id])
rescue StandardError
skip_authorization
respond_to do |format|
format.html { redirect_to request_for_comments_url, alert: t('subscriptions.subscription_not_existent') }
format.json { render json: {message: t('subscriptions.subscription_not_existent')}, status: :not_found }
end
else
authorize!
rfc = @subscription.try(:request_for_comment)
@subscription.deleted = true
if @subscription.save
respond_to do |format|
format.html { redirect_to request_for_comments_url, alert: t('subscriptions.subscription_not_existent') }
format.json { render json: {message: t('subscriptions.subscription_not_existent')}, status: :not_found }
format.html { redirect_to request_for_comment_url(rfc), notice: t('subscriptions.successfully_unsubscribed') }
format.json { render json: {message: t('subscriptions.successfully_unsubscribed')}, status: :ok }
end
else
authorize!
rfc = @subscription.try(:request_for_comment)
@subscription.deleted = true
if @subscription.save
respond_to do |format|
format.html { redirect_to request_for_comment_url(rfc), notice: t('subscriptions.successfully_unsubscribed') }
format.json { render json: {message: t('subscriptions.successfully_unsubscribed')}, status: :ok}
end
else
respond_to do |format|
format.html { redirect_to request_for_comment_url(rfc), :flash => { :danger => t('shared.message_failure') } }
format.json { render json: {message: t('shared.message_failure')}, status: :internal_server_error}
end
respond_to do |format|
format.html { redirect_to request_for_comment_url(rfc), flash: {danger: t('shared.message_failure')} }
format.json { render json: {message: t('shared.message_failure')}, status: :internal_server_error }
end
end
end
@ -56,7 +55,10 @@ class SubscriptionsController < ApplicationController
def subscription_params
current_user_id = current_user.try(:id)
current_user_class_name = current_user.try(:class).try(:name)
params[:subscription].permit(:request_for_comment_id, :subscription_type).merge(user_id: current_user_id, user_type: current_user_class_name, deleted: false) if params[:subscription].present?
if params[:subscription].present?
params[:subscription].permit(:request_for_comment_id, :subscription_type).merge(user_id: current_user_id,
user_type: current_user_class_name, deleted: false)
end
end
private :subscription_params
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class TagsController < ApplicationController
include CommonBehavior
@ -18,8 +20,7 @@ class TagsController < ApplicationController
destroy_and_respond(object: @tag)
end
def edit
end
def edit; end
def tag_params
params[:tag].permit(:name) if params[:tag].present?
@ -42,8 +43,7 @@ class TagsController < ApplicationController
end
private :set_tag
def show
end
def show; end
def update
update_and_respond(object: @tag, params: tag_params)

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
class TipsController < ApplicationController
include CommonBehavior
@ -19,15 +21,14 @@ class TipsController < ApplicationController
destroy_and_respond(object: @tip)
end
def edit
end
def edit; end
def tip_params
return unless params[:tip].present?
return if params[:tip].blank?
params[:tip]
.permit(:title, :description, :example, :file_type_id)
.each { |_key, value| value.strip! unless value.is_a?(Array) }
.each {|_key, value| value.strip! unless value.is_a?(Array) }
.merge(user_id: current_user.id, user_type: current_user.class.name)
end
private :tip_params
@ -48,8 +49,7 @@ class TipsController < ApplicationController
end
private :set_tip
def show
end
def show; end
def update
update_and_respond(object: @tip, params: tip_params)

View File

@ -28,10 +28,10 @@ class UserExerciseFeedbacksController < ApplicationController
@exercise = Exercise.find(uef_params[:exercise_id])
rfc = RequestForComment.unsolved.where(exercise_id: @exercise.id, user_id: current_user.id).first
submission = begin
current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first
rescue StandardError
nil
end
current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first
rescue StandardError
nil
end
if @exercise
@uef = UserExerciseFeedback.find_or_initialize_by(user: current_user, exercise: @exercise)
@ -74,10 +74,10 @@ class UserExerciseFeedbacksController < ApplicationController
def update
submission = begin
current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first
rescue StandardError
nil
end
current_user.submissions.where(exercise_id: @exercise.id).order('created_at DESC').first
rescue StandardError
nil
end
rfc = RequestForComment.unsolved.where(exercise_id: @exercise.id, user_id: current_user.id).first
authorize!
if @exercise && validate_inputs(uef_params)
@ -115,7 +115,7 @@ class UserExerciseFeedbacksController < ApplicationController
end
def uef_params
return unless params[:user_exercise_feedback].present?
return if params[:user_exercise_feedback].blank?
exercise_id = if params[:user_exercise_feedback].nil?
params[:exercise_id]
@ -126,8 +126,8 @@ class UserExerciseFeedbacksController < ApplicationController
user_id = current_user.id
user_type = current_user.class.name
latest_submission = Submission
.where(user_id: user_id, user_type: user_type, exercise_id: exercise_id)
.order(created_at: :desc).first
.where(user_id: user_id, user_type: user_type, exercise_id: exercise_id)
.order(created_at: :desc).first
params[:user_exercise_feedback]
.permit(:feedback_text, :difficulty, :exercise_id, :user_estimated_worktime)
@ -140,10 +140,8 @@ class UserExerciseFeedbacksController < ApplicationController
def validate_inputs(uef_params)
if uef_params[:difficulty].to_i.negative? || uef_params[:difficulty].to_i >= comment_presets.size
false
elsif uef_params[:user_estimated_worktime].to_i.negative? || uef_params[:user_estimated_worktime].to_i >= time_presets.size
false
else
true
!(uef_params[:user_estimated_worktime].to_i.negative? || uef_params[:user_estimated_worktime].to_i >= time_presets.size)
end
rescue StandardError
false