enable export to codeharbor
This commit is contained in:
1
Gemfile
1
Gemfile
@ -50,6 +50,7 @@ group :development, :staging do
|
||||
gem 'capistrano-rails'
|
||||
gem 'capistrano-rvm'
|
||||
gem 'capistrano-upload-config'
|
||||
gem 'pry-rails'
|
||||
gem 'rack-mini-profiler'
|
||||
gem 'rubocop', require: false
|
||||
gem 'rubocop-rspec'
|
||||
|
@ -226,6 +226,8 @@ GEM
|
||||
pry-byebug (3.7.0)
|
||||
byebug (~> 11.0)
|
||||
pry (~> 0.10)
|
||||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (3.0.3)
|
||||
puma (3.12.1)
|
||||
pundit (2.0.1)
|
||||
@ -441,6 +443,7 @@ DEPENDENCIES
|
||||
pg
|
||||
proforma!
|
||||
pry-byebug
|
||||
pry-rails
|
||||
puma
|
||||
pundit
|
||||
rack-mini-profiler
|
||||
|
@ -7,7 +7,7 @@ class ExercisesController < ApplicationController
|
||||
|
||||
before_action :handle_file_uploads, only: [:create, :update]
|
||||
before_action :set_execution_environments, only: [:create, :edit, :new, :update]
|
||||
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload, :feedback, :study_group_dashboard]
|
||||
before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:push_proforma_xml, :clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload, :feedback, :study_group_dashboard]
|
||||
before_action :set_external_user_and_authorize, only: [:statistics]
|
||||
before_action :set_file_types, only: [:create, :edit, :new, :update]
|
||||
before_action :set_course_token, only: [:implement]
|
||||
@ -108,16 +108,29 @@ class ExercisesController < ApplicationController
|
||||
end
|
||||
|
||||
def push_proforma_xml
|
||||
codeharbor_link = CodeharborLink.find(params[:account_link])
|
||||
oauth2_client = OAuth2::Client.new(codeharbor_link.client_id, codeharbor_link.client_secret, url: codeharbor_link.push_url, ssl: {verify: false})
|
||||
oauth2token = codeharbor_link[:oauth2token]
|
||||
token = OAuth2::AccessToken.from_hash(oauth2_client, access_token: oauth2token)
|
||||
# codeharbor_link = current_user.codeharbor_link # CodeharborLink.find(params[:account_link])
|
||||
|
||||
# xml_generator = Proforma::XmlGenerator.new
|
||||
xml_document = xml_generator.generate_xml(@exercise)
|
||||
request = token.post(codeharbor_link.push_url, body: xml_document, headers: {'Content-Type' => 'text/xml'})
|
||||
puts request
|
||||
redirect_to @exercise, notice: t('exercises.push_proforma_xml.notice', link: codeharbor_link.push_url)
|
||||
error = ExerciseService::PushExternal.call(
|
||||
zip: ProformaService::ExportTask.call(exercise: @exercise),
|
||||
codeharbor_link: current_user.codeharbor_link
|
||||
)
|
||||
if error.nil?
|
||||
redirect_to exercises_path, notice: 'klappt' # t('controllers.exercise.push_external_notice', account_link: account_link.readable)
|
||||
# redirect_to @exercise, notice: 'klappt' # t('controllers.exercise.push_external_notice', account_link: account_link.readable)
|
||||
else
|
||||
# logger.debug(error)
|
||||
redirect_to exercises_path, alert: 'klappt nicht' # t('controllers.account_links.not_working', account_link: account_link.readable)
|
||||
# redirect_to @exercise, alert: 'klappt nicht' # t('controllers.account_links.not_working', account_link: account_link.readable)
|
||||
end
|
||||
# oauth2_client = OAuth2::Client.new(codeharbor_link.client_id, codeharbor_link.client_secret, url: codeharbor_link.push_url, ssl: {verify: false})
|
||||
# oauth2token = codeharbor_link[:oauth2token]
|
||||
# token = OAuth2::AccessToken.from_hash(oauth2_client, access_token: oauth2token)
|
||||
|
||||
# # xml_generator = Proforma::XmlGenerator.new
|
||||
# xml_document = xml_generator.generate_xml(@exercise)
|
||||
# request = token.post(codeharbor_link.push_url, body: xml_document, headers: {'Content-Type' => 'text/xml'})
|
||||
# puts request
|
||||
# redirect_to @exercise, notice: t('exercises.push_proforma_xml.notice', link: codeharbor_link.push_url)
|
||||
end
|
||||
|
||||
def import_proforma_xml
|
||||
|
@ -7,7 +7,7 @@ class ExercisePolicy < AdminOrAuthorPolicy
|
||||
define_method(action) { admin? || teacher? }
|
||||
end
|
||||
|
||||
[:clone?, :destroy?, :edit?, :statistics?, :update?, :feedback?].each do |action|
|
||||
[:clone?, :destroy?, :edit?, :statistics?, :update?, :feedback?, :push_proforma_xml?].each do |action|
|
||||
define_method(action) { admin? || author? }
|
||||
end
|
||||
|
||||
|
28
app/services/exercise_service/push_external.rb
Normal file
28
app/services/exercise_service/push_external.rb
Normal file
@ -0,0 +1,28 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ExerciseService
|
||||
class PushExternal < ServiceBase
|
||||
CODEHARBOR_PUSH_LINK = 'http://localhost:3001/import_exercise'
|
||||
def initialize(zip:, codeharbor_link:)
|
||||
@zip = zip
|
||||
@codeharbor_link = codeharbor_link
|
||||
end
|
||||
|
||||
def execute
|
||||
oauth2_client = OAuth2::Client.new(@codeharbor_link.client_id, @codeharbor_link.client_secret, site: CODEHARBOR_PUSH_LINK)
|
||||
oauth2_token = @codeharbor_link[:oauth2token]
|
||||
token = OAuth2::AccessToken.from_hash(oauth2_client, access_token: oauth2_token)
|
||||
body = @zip.string
|
||||
begin
|
||||
token.post(
|
||||
CODEHARBOR_PUSH_LINK,
|
||||
body: body,
|
||||
headers: {'Content-Type' => 'application/zip', 'Content-Length' => body.length.to_s}
|
||||
)
|
||||
return nil
|
||||
rescue StandardError => e
|
||||
return e
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -4,6 +4,8 @@ require 'mimemagic'
|
||||
|
||||
module ProformaService
|
||||
class ConvertExerciseToTask < ServiceBase
|
||||
DEFAULT_LANGUAGE = 'de'
|
||||
|
||||
def initialize(exercise: nil)
|
||||
@exercise = exercise
|
||||
end
|
||||
@ -20,75 +22,63 @@ module ProformaService
|
||||
title: @exercise.title,
|
||||
description: @exercise.description,
|
||||
internal_description: @exercise.instructions,
|
||||
|
||||
# proglang: proglang,
|
||||
files: task_files,
|
||||
# tests: tests,
|
||||
# uuid: @exercise.uuid,
|
||||
tests: tests,
|
||||
uuid: uuid,
|
||||
# parent_uuid: parent_uuid,
|
||||
# language: primary_description.language,
|
||||
# model_solutions: model_solutions
|
||||
language: DEFAULT_LANGUAGE,
|
||||
model_solutions: model_solutions
|
||||
}.compact
|
||||
)
|
||||
end
|
||||
|
||||
def parent_uuid
|
||||
@exercise.clone_relations.first&.origin&.uuid
|
||||
end
|
||||
|
||||
def primary_description
|
||||
@exercise.descriptions.select(&:primary?).first
|
||||
end
|
||||
|
||||
def proglang
|
||||
{name: @exercise.execution_environment.language, version: @exercise.execution_environment.version}
|
||||
def uuid
|
||||
@exercise.update(uuid: SecureRandom.uuid) if @exercise.uuid.nil?
|
||||
@exercise.uuid
|
||||
end
|
||||
|
||||
def model_solutions
|
||||
@exercise.exercise_files.filter { |file| file.role == 'Reference Implementation' }.map do |file|
|
||||
@exercise.files.filter { |file| file.role == 'reference_implementation' }.map do |file|
|
||||
Proforma::ModelSolution.new(
|
||||
id: "ms-#{file.id}",
|
||||
files: [
|
||||
Proforma::TaskFile.new(
|
||||
id: file.id,
|
||||
content: file.content,
|
||||
filename: file.full_file_name,
|
||||
used_by_grader: false,
|
||||
usage_by_lms: 'display',
|
||||
visible: 'delayed',
|
||||
binary: false,
|
||||
internal_description: file.role
|
||||
)
|
||||
]
|
||||
files: model_solution_file(file)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def model_solution_file(file)
|
||||
[
|
||||
task_file(file).tap do |ms_file|
|
||||
ms_file.used_by_grader = false
|
||||
ms_file.usage_by_lms = 'display'
|
||||
ms_file.visible = 'delayed'
|
||||
end
|
||||
]
|
||||
end
|
||||
|
||||
def tests
|
||||
@exercise.tests.map do |test|
|
||||
@exercise.files.filter { |file| file.role == 'teacher_defined_test' }.map do |file|
|
||||
Proforma::Test.new(
|
||||
id: test.id,
|
||||
title: test.exercise_file.name,
|
||||
files: test_file(test.exercise_file),
|
||||
id: file.id,
|
||||
title: file.name,
|
||||
files: test_file(file),
|
||||
meta_data: {
|
||||
'feedback-message' => test.feedback_message,
|
||||
'testing-framework' => test.testing_framework&.name,
|
||||
'testing-framework-version' => test.testing_framework&.version
|
||||
'feedback-message' => file.feedback_message
|
||||
# 'testing-framework' => test.testing_framework&.name,
|
||||
# 'testing-framework-version' => test.testing_framework&.version
|
||||
}.compact
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_file(file)
|
||||
[Proforma::TaskFile.new(
|
||||
id: file.id,
|
||||
content: file.content,
|
||||
filename: file.full_file_name,
|
||||
used_by_grader: true,
|
||||
visible: file.hidden ? 'no' : 'yes',
|
||||
binary: false,
|
||||
internal_description: file.role || 'Teacher-defined Test'
|
||||
)]
|
||||
[
|
||||
task_file(file).tap do |t_file|
|
||||
t_file.used_by_grader = true
|
||||
t_file.internal_description = 'teacher_defined_test'
|
||||
end
|
||||
]
|
||||
end
|
||||
|
||||
def task_files
|
||||
@ -121,9 +111,5 @@ module ProformaService
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
def attachment_content(file)
|
||||
Paperclip.io_adapters.for(file.attachment).read
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -21,7 +21,8 @@ module ProformaService
|
||||
title: @task.title,
|
||||
description: @task.description,
|
||||
instructions: @task.internal_description,
|
||||
files: files
|
||||
files: files,
|
||||
uuid: @task.uuid
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -46,6 +46,7 @@ h1 = Exercise.model_name.human(count: 2)
|
||||
li = link_to(t('activerecord.models.user_exercise_feedback.other'), feedback_exercise_path(exercise), class: 'dropdown-item') if policy(exercise).feedback?
|
||||
li = link_to(t('shared.destroy'), exercise, data: {confirm: t('shared.confirm_destroy')}, method: :delete, class: 'dropdown-item') if policy(exercise).destroy?
|
||||
li = link_to(t('.clone'), clone_exercise_path(exercise), data: {confirm: t('shared.confirm_destroy')}, method: :post, class: 'dropdown-item') if policy(exercise).clone?
|
||||
li = link_to(t('exercises.export_codeharbor'), push_proforma_xml_exercise_path(exercise), data: {confirm: 'PUSHPUSH?'}, method: :post, class: 'dropdown-item') if policy(exercise).push_proforma_xml?
|
||||
|
||||
= render('shared/pagination', collection: @exercises)
|
||||
p = render('shared/new_button', model: Exercise)
|
||||
|
@ -20,6 +20,7 @@ h1
|
||||
= row(label: 'exercise.allow_file_creation', value: @exercise.allow_file_creation?)
|
||||
= row(label: 'exercise.allow_auto_completion', value: @exercise.allow_auto_completion?)
|
||||
= row(label: 'exercise.difficulty', value: @exercise.expected_difficulty)
|
||||
= row(label: 'exercise.uuid', value: @exercise.uuid)
|
||||
= row(label: 'exercise.tags', value: @exercise.exercise_tags.map{|et| "#{et.tag.name} (#{et.factor})"}.sort.join(", "))
|
||||
= row(label: 'exercise.embedding_parameters', class: 'mb-4') do
|
||||
= content_tag(:input, nil, class: 'form-control mb-4', readonly: true, value: embedding_parameters(@exercise))
|
||||
|
@ -44,6 +44,7 @@ en:
|
||||
allow_file_creation: "Allow file creation"
|
||||
difficulty: Difficulty
|
||||
token: "Exercise Token"
|
||||
uuid: UUID
|
||||
proxy_exercise:
|
||||
title: Title
|
||||
files_count: Exercises Count
|
||||
@ -315,6 +316,7 @@ en:
|
||||
request_for_comments_sent: "Request for comments sent."
|
||||
editor_file_tree:
|
||||
file_root: Files
|
||||
export_codeharbor: Export to Codeharbor
|
||||
file_form:
|
||||
hints:
|
||||
feedback_message: This message is used as a hint for failing tests.
|
||||
|
@ -81,6 +81,7 @@ Rails.application.routes.draw do
|
||||
post :search
|
||||
get :statistics
|
||||
get :feedback
|
||||
post :push_proforma_xml
|
||||
get :reload
|
||||
post :submit
|
||||
get 'study_group_dashboard/:study_group_id', to: 'exercises#study_group_dashboard'
|
||||
|
5
db/migrate/20190830142809_add_uuid_to_exercise.rb
Normal file
5
db/migrate/20190830142809_add_uuid_to_exercise.rb
Normal file
@ -0,0 +1,5 @@
|
||||
class AddUuidToExercise < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :exercises, :uuid, :uuid
|
||||
end
|
||||
end
|
@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2019_08_18_104954) do
|
||||
ActiveRecord::Schema.define(version: 2019_08_30_142809) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@ -153,6 +153,7 @@ ActiveRecord::Schema.define(version: 2019_08_18_104954) do
|
||||
t.boolean "allow_file_creation"
|
||||
t.boolean "allow_auto_completion", default: false
|
||||
t.integer "expected_difficulty", default: 1
|
||||
t.uuid "uuid"
|
||||
t.index ["id"], name: "index_exercises_on_id"
|
||||
end
|
||||
|
||||
|
Reference in New Issue
Block a user