enable export to codeharbor

This commit is contained in:
Karol
2019-09-02 19:03:50 +02:00
parent c006bc3dc8
commit 3c65565b8c
13 changed files with 104 additions and 61 deletions

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -21,7 +21,8 @@ module ProformaService
title: @task.title,
description: @task.description,
instructions: @task.internal_description,
files: files
files: files,
uuid: @task.uuid
)
end

View File

@ -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)

View File

@ -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))

View File

@ -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.

View File

@ -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'

View File

@ -0,0 +1,5 @@
class AddUuidToExercise < ActiveRecord::Migration[5.2]
def change
add_column :exercises, :uuid, :uuid
end
end

View File

@ -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