Merge branch 'master' into update-gemfile
This commit is contained in:
@ -9,7 +9,7 @@ module SubmissionScoring
|
|||||||
assessment = assessor.assess(output)
|
assessment = assessor.assess(output)
|
||||||
passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score] > 0))
|
passed = ((assessment[:passed] == assessment[:count]) and (assessment[:score] > 0))
|
||||||
testrun_output = passed ? nil : 'message: ' + output[:message].to_s + "\n stdout: " + output[:stdout].to_s + "\n stderr: " + output[:stderr].to_s
|
testrun_output = passed ? nil : 'message: ' + output[:message].to_s + "\n stdout: " + output[:stdout].to_s + "\n stderr: " + output[:stderr].to_s
|
||||||
if !testrun_output.blank?
|
unless testrun_output.blank?
|
||||||
submission.exercise.execution_environment.error_templates.each do |template|
|
submission.exercise.execution_environment.error_templates.each do |template|
|
||||||
pattern = Regexp.new(template.signature).freeze
|
pattern = Regexp.new(template.signature).freeze
|
||||||
if pattern.match(testrun_output)
|
if pattern.match(testrun_output)
|
||||||
@ -47,6 +47,14 @@ module SubmissionScoring
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
submission.update(score: score)
|
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{ |rfc|
|
||||||
|
rfc.full_score_reached = true
|
||||||
|
rfc.save
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
outputs
|
outputs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -416,6 +416,9 @@ class ExercisesController < ApplicationController
|
|||||||
flash[:notice] = I18n.t('exercises.submit.full_score_redirect_to_rfc')
|
flash[:notice] = I18n.t('exercises.submit.full_score_redirect_to_rfc')
|
||||||
flash.keep(:notice)
|
flash.keep(:notice)
|
||||||
|
|
||||||
|
# increase counter 'times_featured' in rfc
|
||||||
|
rfc.increment!(:times_featured)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {redirect_to(rfc)}
|
format.html {redirect_to(rfc)}
|
||||||
format.json {render(json: {redirect: url_for(rfc)})}
|
format.json {render(json: {redirect: url_for(rfc)})}
|
||||||
|
@ -20,7 +20,7 @@ class RequestForCommentsController < ApplicationController
|
|||||||
.group('request_for_comments.id, request_for_comments.user_id, request_for_comments.exercise_id,
|
.group('request_for_comments.id, request_for_comments.user_id, request_for_comments.exercise_id,
|
||||||
request_for_comments.file_id, request_for_comments.question, request_for_comments.created_at,
|
request_for_comments.file_id, request_for_comments.question, request_for_comments.created_at,
|
||||||
request_for_comments.updated_at, request_for_comments.user_type, request_for_comments.solved,
|
request_for_comments.updated_at, request_for_comments.user_type, request_for_comments.solved,
|
||||||
request_for_comments.submission_id, request_for_comments.row_number') # ugly, but rails wants it this way
|
request_for_comments.full_score_reached, request_for_comments.submission_id, request_for_comments.row_number') # ugly, but rails wants it this way
|
||||||
.select('request_for_comments.*, max(comments.updated_at) as last_comment')
|
.select('request_for_comments.*, max(comments.updated_at) as last_comment')
|
||||||
.search(params[:q])
|
.search(params[:q])
|
||||||
@request_for_comments = @search.result.order('created_at DESC').paginate(page: params[:page], total_entries: @search.result.length)
|
@request_for_comments = @search.result.order('created_at DESC').paginate(page: params[:page], total_entries: @search.result.length)
|
||||||
|
@ -202,21 +202,11 @@ class SubmissionsController < ApplicationController
|
|||||||
tubesock.close
|
tubesock.close
|
||||||
end
|
end
|
||||||
|
|
||||||
def extract_errors
|
|
||||||
if !@message_buffer.blank?
|
|
||||||
@submission.exercise.execution_environment.error_templates.each do |template|
|
|
||||||
pattern = Regexp.new(template.signature).freeze
|
|
||||||
if pattern.match(@message_buffer)
|
|
||||||
StructuredError.create_from_template(template, @message_buffer)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_message(message, tubesock, container)
|
def handle_message(message, tubesock, container)
|
||||||
@run_output ||= ""
|
@raw_output ||= ''
|
||||||
|
@run_output ||= ''
|
||||||
# Handle special commands first
|
# Handle special commands first
|
||||||
if (/^#exit/.match(message))
|
if /^#exit/.match(message)
|
||||||
# Just call exit_container on the docker_client.
|
# Just call exit_container on the docker_client.
|
||||||
# Do not call kill_socket for the websocket to the client here.
|
# Do not call kill_socket for the websocket to the client here.
|
||||||
# @docker_client.exit_container closes the socket to the container,
|
# @docker_client.exit_container closes the socket to the container,
|
||||||
@ -228,17 +218,17 @@ class SubmissionsController < ApplicationController
|
|||||||
# Filter out information about run_command, test_command, user or working directory
|
# Filter out information about run_command, test_command, user or working directory
|
||||||
run_command = @submission.execution_environment.run_command % command_substitutions(params[:filename])
|
run_command = @submission.execution_environment.run_command % command_substitutions(params[:filename])
|
||||||
test_command = @submission.execution_environment.test_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))
|
unless /root|workspace|#{run_command}|#{test_command}/.match(message)
|
||||||
parse_message(message, 'stdout', tubesock)
|
parse_message(message, 'stdout', tubesock)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_message(message, output_stream, socket, recursive = true)
|
def parse_message(message, output_stream, socket, recursive = true)
|
||||||
parsed = '';
|
parsed = ''
|
||||||
begin
|
begin
|
||||||
parsed = JSON.parse(message)
|
parsed = JSON.parse(message)
|
||||||
if(parsed.class == Hash && parsed.key?('cmd'))
|
if parsed.class == Hash and parsed.key?('cmd')
|
||||||
socket.send_data message
|
socket.send_data message
|
||||||
Rails.logger.info('parse_message sent: ' + message)
|
Rails.logger.info('parse_message sent: ' + message)
|
||||||
else
|
else
|
||||||
@ -248,24 +238,24 @@ class SubmissionsController < ApplicationController
|
|||||||
end
|
end
|
||||||
rescue JSON::ParserError => e
|
rescue JSON::ParserError => e
|
||||||
# Check wether the message contains multiple lines, if true try to parse each line
|
# Check wether the message contains multiple lines, if true try to parse each line
|
||||||
if ((recursive == true) && (message.include? "\n"))
|
if recursive and message.include? "\n"
|
||||||
for part in message.split("\n")
|
for part in message.split("\n")
|
||||||
self.parse_message(part,output_stream,socket,false)
|
self.parse_message(part,output_stream,socket,false)
|
||||||
end
|
end
|
||||||
elsif(message.include? "<img")
|
elsif message.include? '<img'
|
||||||
#Rails.logger.info('img foung')
|
#Rails.logger.info('img foung')
|
||||||
@buffering = true
|
@buffering = true
|
||||||
@buffer = ""
|
@buffer = ''
|
||||||
@buffer += message
|
@buffer += message
|
||||||
#Rails.logger.info('Starting to buffer')
|
#Rails.logger.info('Starting to buffer')
|
||||||
elsif(@buffering && (message.include? "/>"))
|
elsif @buffering and message.include? '/>'
|
||||||
@buffer += message
|
@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 JSON.dump(parsed)
|
||||||
#socket.send_data @buffer
|
#socket.send_data @buffer
|
||||||
@buffering = false
|
@buffering = false
|
||||||
#Rails.logger.info('Sent complete buffer')
|
#Rails.logger.info('Sent complete buffer')
|
||||||
elsif(@buffering)
|
elsif @buffering
|
||||||
@buffer += message
|
@buffer += message
|
||||||
#Rails.logger.info('Appending to buffer')
|
#Rails.logger.info('Appending to buffer')
|
||||||
else
|
else
|
||||||
@ -275,18 +265,30 @@ class SubmissionsController < ApplicationController
|
|||||||
Rails.logger.info('parse_message sent: ' + JSON.dump(parsed))
|
Rails.logger.info('parse_message sent: ' + JSON.dump(parsed))
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
|
@raw_output += parsed['data'] if parsed.class == Hash and 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"
|
# 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) if @run_output.size <= max_run_output_buffer_size
|
@run_output += JSON.dump(parsed) if @run_output.size <= max_run_output_buffer_size
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_run_output
|
def save_run_output
|
||||||
if !@run_output.blank?
|
unless @run_output.blank?
|
||||||
@run_output = @run_output[(0..max_run_output_buffer_size-1)] # trim the string to max_message_buffer_size chars
|
@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', submission: @submission, output: @run_output)
|
Testrun.create(file: @file, cause: 'run', submission: @submission, output: @run_output)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def extract_errors
|
||||||
|
unless @raw_output.blank?
|
||||||
|
@submission.exercise.execution_environment.error_templates.each do |template|
|
||||||
|
pattern = Regexp.new(template.signature).freeze
|
||||||
|
if pattern.match(@raw_output)
|
||||||
|
StructuredError.create_from_template(template, @raw_output, @submission)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def score
|
def score
|
||||||
hijack do |tubesock|
|
hijack do |tubesock|
|
||||||
Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?
|
Thread.new { EventMachine.run } unless EventMachine.reactor_running? && EventMachine.reactor_thread.alive?
|
||||||
|
@ -364,7 +364,7 @@ class Exercise < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
private :valid_main_file?
|
private :valid_main_file?
|
||||||
|
|
||||||
def needs_more_feedback
|
def needs_more_feedback?
|
||||||
user_exercise_feedbacks.size <= MAX_EXERCISE_FEEDBACKS
|
user_exercise_feedbacks.size <= MAX_EXERCISE_FEEDBACKS
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -52,6 +52,6 @@ class RequestForComment < ActiveRecord::Base
|
|||||||
|
|
||||||
private
|
private
|
||||||
def self.row_number_user_sql
|
def self.row_number_user_sql
|
||||||
select("id, user_id, exercise_id, file_id, question, created_at, updated_at, user_type, solved, submission_id, row_number() OVER (PARTITION BY user_id ORDER BY created_at DESC) as row_number").to_sql
|
select("id, user_id, exercise_id, file_id, question, created_at, updated_at, user_type, solved, full_score_reached, submission_id, row_number() OVER (PARTITION BY user_id ORDER BY created_at DESC) as row_number").to_sql
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
class StructuredError < ActiveRecord::Base
|
class StructuredError < ActiveRecord::Base
|
||||||
belongs_to :error_template
|
belongs_to :error_template
|
||||||
|
belongs_to :submission
|
||||||
belongs_to :file, class_name: 'CodeOcean::File'
|
belongs_to :file, class_name: 'CodeOcean::File'
|
||||||
|
|
||||||
def self.create_from_template(template, message_buffer)
|
def self.create_from_template(template, message_buffer, submission)
|
||||||
instance = self.create(error_template: template)
|
instance = self.create(error_template: template, submission: submission)
|
||||||
template.error_template_attributes.each do |attribute|
|
template.error_template_attributes.each do |attribute|
|
||||||
StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer)
|
StructuredErrorAttribute.create_from_template(attribute, instance, message_buffer)
|
||||||
end
|
end
|
||||||
|
@ -3,15 +3,13 @@ class StructuredErrorAttribute < ActiveRecord::Base
|
|||||||
belongs_to :error_template_attribute
|
belongs_to :error_template_attribute
|
||||||
|
|
||||||
def self.create_from_template(attribute, structured_error, message_buffer)
|
def self.create_from_template(attribute, structured_error, message_buffer)
|
||||||
match = false
|
|
||||||
value = nil
|
value = nil
|
||||||
result = message_buffer.match(attribute.regex)
|
result = message_buffer.match(attribute.regex)
|
||||||
if result != nil
|
if result != nil
|
||||||
match = true
|
|
||||||
if result.captures.size > 0
|
if result.captures.size > 0
|
||||||
value = result.captures[0]
|
value = result.captures[0]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.create(structured_error: structured_error, error_template_attribute: attribute, value: value, match: match)
|
self.create(structured_error: structured_error, error_template_attribute: attribute, value: value, match: result != nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -8,6 +8,7 @@ class Submission < ActiveRecord::Base
|
|||||||
belongs_to :exercise
|
belongs_to :exercise
|
||||||
|
|
||||||
has_many :testruns
|
has_many :testruns
|
||||||
|
has_many :structured_errors
|
||||||
has_many :comments, through: :files
|
has_many :comments, through: :files
|
||||||
|
|
||||||
delegate :execution_environment, to: :exercise
|
delegate :execution_environment, to: :exercise
|
||||||
@ -57,7 +58,7 @@ class Submission < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def redirect_to_feedback?
|
def redirect_to_feedback?
|
||||||
((user_id + exercise.created_at.to_i) % 10 == 1) && exercise.needs_more_feedback
|
((user_id + exercise.created_at.to_i) % 10 == 1) && exercise.needs_more_feedback?
|
||||||
end
|
end
|
||||||
|
|
||||||
def own_unsolved_rfc
|
def own_unsolved_rfc
|
||||||
|
@ -54,8 +54,6 @@ h1 = "#{@exercise} (external user #{@external_user})"
|
|||||||
-submission_or_intervention.testruns.each do |run|
|
-submission_or_intervention.testruns.each do |run|
|
||||||
- if run.passed
|
- if run.passed
|
||||||
.unit-test-result.positive-result title=run.output
|
.unit-test-result.positive-result title=run.output
|
||||||
- elsif run.failed
|
|
||||||
.unit-test-result.negative-result title=run.output
|
|
||||||
- else
|
- else
|
||||||
.unit-test-result.unknown-result title=run.output
|
.unit-test-result.unknown-result title=run.output
|
||||||
td = Time.at(deltas[1..index].inject(:+)).utc.strftime("%H:%M:%S") if index > 0
|
td = Time.at(deltas[1..index].inject(:+)).utc.strftime("%H:%M:%S") if index > 0
|
||||||
|
@ -27,6 +27,9 @@ h1 = RequestForComment.model_name.human(count: 2)
|
|||||||
- if request_for_comment.solved?
|
- if request_for_comment.solved?
|
||||||
td
|
td
|
||||||
span class="fa fa-check" aria-hidden="true"
|
span class="fa fa-check" aria-hidden="true"
|
||||||
|
- elsif request_for_comment.full_score_reached
|
||||||
|
td
|
||||||
|
span class="fa fa-check" style="color:darkgrey" aria-hidden="true"
|
||||||
- else
|
- else
|
||||||
td = ''
|
td = ''
|
||||||
td = link_to(request_for_comment.exercise.title, request_for_comment)
|
td = link_to(request_for_comment.exercise.title, request_for_comment)
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
class AddSubmissionToStructuredErrors < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_reference :structured_errors, :submission, index: true
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,15 @@
|
|||||||
|
class AddReachedFullScoreToRequestForComment < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
add_column :request_for_comments, :full_score_reached, :boolean, default: false
|
||||||
|
RequestForComment.all.each { |rfc|
|
||||||
|
if (rfc.submission.present? && rfc.submission.exercise.has_user_solved(rfc.user))
|
||||||
|
rfc.full_score_reached = true
|
||||||
|
rfc.save
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :request_for_comments, :full_score_reached
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
class AddTimesFeaturedToRequestForComments < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :request_for_comments, :times_featured, :integer, default: 0
|
||||||
|
end
|
||||||
|
end
|
21
db/schema.rb
21
db/schema.rb
@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20171120153705) do
|
ActiveRecord::Schema.define(version: 20180202132034) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@ -270,16 +270,18 @@ ActiveRecord::Schema.define(version: 20171120153705) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
create_table "request_for_comments", force: :cascade do |t|
|
create_table "request_for_comments", force: :cascade do |t|
|
||||||
t.integer "user_id", null: false
|
t.integer "user_id", null: false
|
||||||
t.integer "exercise_id", null: false
|
t.integer "exercise_id", null: false
|
||||||
t.integer "file_id", null: false
|
t.integer "file_id", null: false
|
||||||
t.datetime "created_at"
|
t.datetime "created_at"
|
||||||
t.datetime "updated_at"
|
t.datetime "updated_at"
|
||||||
t.string "user_type", limit: 255
|
t.string "user_type", limit: 255
|
||||||
t.text "question"
|
t.text "question"
|
||||||
t.boolean "solved", default: false
|
t.boolean "solved", default: false
|
||||||
t.integer "submission_id"
|
t.integer "submission_id"
|
||||||
t.text "thank_you_note"
|
t.text "thank_you_note"
|
||||||
|
t.boolean "full_score_reached", default: false
|
||||||
|
t.integer "times_featured", default: 0
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "searches", force: :cascade do |t|
|
create_table "searches", force: :cascade do |t|
|
||||||
@ -305,8 +307,11 @@ ActiveRecord::Schema.define(version: 20171120153705) do
|
|||||||
t.integer "file_id"
|
t.integer "file_id"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.integer "submission_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
add_index "structured_errors", ["submission_id"], name: "index_structured_errors_on_submission_id", using: :btree
|
||||||
|
|
||||||
create_table "submissions", force: :cascade do |t|
|
create_table "submissions", force: :cascade do |t|
|
||||||
t.integer "exercise_id"
|
t.integer "exercise_id"
|
||||||
t.float "score"
|
t.float "score"
|
||||||
@ -354,8 +359,8 @@ ActiveRecord::Schema.define(version: 20171120153705) do
|
|||||||
t.integer "working_time_seconds"
|
t.integer "working_time_seconds"
|
||||||
t.string "feedback_text"
|
t.string "feedback_text"
|
||||||
t.integer "user_estimated_worktime"
|
t.integer "user_estimated_worktime"
|
||||||
t.datetime "created_at", default: '2017-11-20 18:20:25', null: false
|
t.datetime "created_at", default: '2018-01-30 17:39:22', null: false
|
||||||
t.datetime "updated_at", default: '2017-11-20 18:20:25', null: false
|
t.datetime "updated_at", default: '2018-01-30 17:39:22', null: false
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "user_exercise_interventions", force: :cascade do |t|
|
create_table "user_exercise_interventions", force: :cascade do |t|
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
class Xikolo::Client
|
|
||||||
def self.get_user(user_id)
|
|
||||||
params = {:user_id => user_id}
|
|
||||||
response = get_request(user_profile_url(user_id), params)
|
|
||||||
if response
|
|
||||||
return JSON.parse(response)
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.user_profile_url(user_id)
|
|
||||||
return url + 'v2/users/' + user_id
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.post_request(url, params)
|
|
||||||
begin
|
|
||||||
return RestClient.post url, params, http_header
|
|
||||||
rescue
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get_request(url, params)
|
|
||||||
begin
|
|
||||||
return RestClient.get url, {:params => params}.merge(http_header)
|
|
||||||
rescue
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.http_header
|
|
||||||
return {:accept => accept, :authorization => token}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.url
|
|
||||||
@url ||= CodeOcean::Config.new(:code_ocean).read.fetch(:xikolo_api_url, 'http://localhost:3000/api/') #caches this with ||=, second value of fetch is default value
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.accept
|
|
||||||
'application/vnd.xikolo.v1, application/vnd.api+json, application/json'
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.token
|
|
||||||
'Token token='+Rails.application.secrets.openhpi_api_token#+'"'
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def authenticate_with_user
|
|
||||||
params = {:email => "admin@openhpi.de", :password => "admin"}
|
|
||||||
response = post_request(authentication_url, params)
|
|
||||||
@token = 'Token token="'+JSON.parse(response)['token']+'"'
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.authentication_url
|
|
||||||
return @url + 'authenticate'
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,15 +0,0 @@
|
|||||||
class Xikolo::UserClient
|
|
||||||
def self.get(user_id)
|
|
||||||
user = Xikolo::Client.get_user(user_id)
|
|
||||||
|
|
||||||
# return default values if user is not found or if there is a server issue:
|
|
||||||
if user
|
|
||||||
name = user.dig('data', 'attributes', 'name') || "User " + user_id
|
|
||||||
user_visual = user.dig('data', 'attributes', 'avatar_url') || ActionController::Base.helpers.image_path('default.png')
|
|
||||||
language = user.dig('data', 'attributes', 'language') || "DE"
|
|
||||||
return {display_name: name, user_visual: user_visual, language: language}
|
|
||||||
else
|
|
||||||
return {display_name: "User " + user_id, user_visual: ActionController::Base.helpers.image_path('default.png'), language: "DE"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -132,12 +132,14 @@ describe SessionsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'redirects to recommended exercise if requested token of proxy exercise' do
|
it 'redirects to recommended exercise if requested token of proxy exercise' do
|
||||||
|
skip 'test is currently oscillating'
|
||||||
FactoryBot.create(:proxy_exercise, exercises: [exercise])
|
FactoryBot.create(:proxy_exercise, exercises: [exercise])
|
||||||
post :create_through_lti, custom_locale: locale, custom_token: ProxyExercise.first.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id
|
post :create_through_lti, custom_locale: locale, custom_token: ProxyExercise.first.token, oauth_consumer_key: consumer.oauth_key, oauth_nonce: nonce, oauth_signature: SecureRandom.hex, user_id: user.external_id
|
||||||
expect(controller).to redirect_to(implement_exercise_path(exercise.id))
|
expect(controller).to redirect_to(implement_exercise_path(exercise.id))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'recommends only exercises who are 1 degree more complicated than what user has seen' do
|
it 'recommends only exercises who are 1 degree more complicated than what user has seen' do
|
||||||
|
skip 'test is currently oscillating'
|
||||||
# dummy user has no exercises finished, therefore his highest difficulty is 0
|
# dummy user has no exercises finished, therefore his highest difficulty is 0
|
||||||
FactoryBot.create(:proxy_exercise, exercises: [exercise, exercise2])
|
FactoryBot.create(:proxy_exercise, exercises: [exercise, exercise2])
|
||||||
exercise.expected_difficulty = 3
|
exercise.expected_difficulty = 3
|
||||||
|
Reference in New Issue
Block a user