add check_uuid_url to codeharbor_link

This commit is contained in:
Karol
2019-10-20 16:20:04 +02:00
parent 7e7be4721a
commit 9512fe4a79
14 changed files with 51 additions and 85 deletions

View File

@ -28,17 +28,8 @@ $(document).on('turbolinks:load', function() {
return replace(Array(32).join('x')); return replace(Array(32).join('x'));
}); });
$('.generate-api_key').on('click', function () {
$('.generate-client-id').on('click', function () { $('.api_key').val(generateRandomHex32())
$('.client-id').val(generateUUID());
});
$('.generate-client-secret').on('click', function () {
$('.client-secret').val(generateRandomHex32());
});
$('.generate-oauth2-token').on('click', function () {
$('.oauth2-token').val(generateRandomHex32())
}); });
} }
} }

View File

@ -261,18 +261,16 @@ $(document).on('turbolinks:load', function() {
var $messageDiv = $exerciseDiv.children('.export-message'); var $messageDiv = $exerciseDiv.children('.export-message');
var $actionsDiv = $exerciseDiv.children('.export-exercise-actions'); var $actionsDiv = $exerciseDiv.children('.export-exercise-actions');
$messageDiv.html('requesting status'); $messageDiv.removeClass('export-failure');
$actionsDiv.html('spinning');
$messageDiv.html('<%= I18n.t('exercises.export_codeharbor.checking_codeharbor') %>');
$actionsDiv.html('<div class="spinner-border"></div>');
return $.ajax({ return $.ajax({
type: 'POST', type: 'POST',
url: '/exercises/' + exerciseID + '/export_external_check', url: '/exercises/' + exerciseID + '/export_external_check',
dataType: 'json', dataType: 'json',
success: function(response) { success: function(response) {
if (response.error) {
$messageDiv.html(response.error);
$actionsDiv.html('Retry?');
}
$messageDiv.html(response.message); $messageDiv.html(response.message);
return $actionsDiv.html(response.actions); return $actionsDiv.html(response.actions);
}, },
@ -380,7 +378,6 @@ $(document).on('turbolinks:load', function() {
observeExecutionEnvironment(); observeExecutionEnvironment();
observeUnpublishedState(); observeUnpublishedState();
overrideTextareaTabBehavior(); overrideTextareaTabBehavior();
} else if ($('#files.jstree').isPresent()) { } else if ($('#files.jstree').isPresent()) {
var fileTypeSelect = $('#code_ocean_file_file_type_id'); var fileTypeSelect = $('#code_ocean_file_file_type_id');
fileTypeSelect.on("change", function() {updateFileTemplates(fileTypeSelect.val())}); fileTypeSelect.on("change", function() {updateFileTemplates(fileTypeSelect.val())});

View File

@ -179,8 +179,11 @@ a.file-heading {
#export-modal { #export-modal {
.modal-content { .modal-content {
min-height: unset; min-height: 300px;
height: 300px; }
.modal-body {
overflow: auto;
} }
} }

View File

@ -5,7 +5,8 @@ class CodeharborLinksController < ApplicationController
before_action :set_codeharbor_link, only: %i[show edit update destroy] before_action :set_codeharbor_link, only: %i[show edit update destroy]
def new def new
@codeharbor_link = CodeharborLink.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')
authorize! authorize!
end end
@ -42,6 +43,6 @@ class CodeharborLinksController < ApplicationController
end end
def codeharbor_link_params def codeharbor_link_params
params.require(:codeharbor_link).permit(:push_url, :oauth2token, :client_id, :client_secret) params.require(:codeharbor_link).permit(:push_url, :check_uuid_url, :api_key)
end end
end end

View File

@ -7,7 +7,7 @@ class ExercisesController < ApplicationController
before_action :handle_file_uploads, only: [:create, :update] before_action :handle_file_uploads, only: [:create, :update]
before_action :set_execution_environments, only: [:create, :edit, :new, :update] before_action :set_execution_environments, only: [:create, :edit, :new, :update]
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, :export_external_check, :export_external_confirm] before_action :set_exercise_and_authorize, only: MEMBER_ACTIONS + [:clone, :implement, :working_times, :intervention, :search, :run, :statistics, :submit, :reload, :feedback, :study_group_dashboard, :export_external_check, :export_external_confirm]
before_action :set_external_user_and_authorize, only: [:statistics] before_action :set_external_user_and_authorize, only: [:statistics]
before_action :set_file_types, only: [:create, :edit, :new, :update] before_action :set_file_types, only: [:create, :edit, :new, :update]
before_action :set_course_token, only: [:implement] before_action :set_course_token, only: [:implement]
@ -107,54 +107,37 @@ class ExercisesController < ApplicationController
@feedbacks = @exercise.user_exercise_feedbacks.paginate(page: params[:page]) @feedbacks = @exercise.user_exercise_feedbacks.paginate(page: params[:page])
end end
def push_proforma_xml
error = ExerciseService::PushExternal.call(
zip: ProformaService::ExportTask.call(exercise: @exercise),
codeharbor_link: current_user.codeharbor_link
)
if error.nil?
redirect_to exercises_path, notice: t('exercises.export_codeharbor.success')
else
redirect_to exercises_path, alert: t('exercises.export_codeharbor.fail')
end
end
def export_external_check def export_external_check
@codeharbor_link = current_user.codeharbor_link @codeharbor_link = current_user.codeharbor_link
url = 'http://localhost:3001/import_uuid_check' conn = Faraday.new(url: @codeharbor_link.check_uuid_url) do |faraday|
conn = Faraday.new(url: url) do |faraday|
faraday.options[:open_timeout] = 5 faraday.options[:open_timeout] = 5
faraday.options[:timeout] = 5 faraday.options[:timeout] = 5
faraday.adapter Faraday.default_adapter faraday.adapter Faraday.default_adapter
end end
error = false codeharbor_check = begin
response_hash = {} response = conn.post do |req|
message = '' req.headers['Content-Type'] = 'application/json'
begin req.headers['Authorization'] = 'Bearer ' + @codeharbor_link.api_key
response = conn.post do |req| req.body = {uuid: @exercise.uuid}.to_json
req.headers['Content-Type'] = 'application/json' end
req.headers['Authorization'] = 'Bearer ' + @codeharbor_link.api_key response_hash = JSON.parse(response.body, symbolize_names: true)
req.body = {uuid: @exercise.uuid}.to_json
end {error: false}.merge(response_hash.slice(:message, :exercise_found, :update_right))
response_hash = JSON.parse(response.body, symbolize_names: true) rescue Faraday::Error => e
message = response_hash[:message] {error: true, message: t('exercises.export_codeharbor.error', message: e.message)}
rescue Faraday::Error => e end
message = t('exercises.export_codeharbor.error', message: e.message)
error = true
end
render json: { render json: {
message: message, message: codeharbor_check[:message],
actions: render_to_string( actions: render_to_string(
partial: 'export_actions', partial: 'export_actions',
locals: { locals: {
exercise: @exercise, exercise: @exercise,
exercise_found: response_hash[:exercise_found], exercise_found: codeharbor_check[:exercise_found],
update_right: response_hash[:update_right], update_right: codeharbor_check[:update_right],
error: error, error: codeharbor_check[:error],
exported: false exported: false
} }
) )
@ -179,15 +162,12 @@ class ExercisesController < ApplicationController
message: t('exercises.export_codeharbor.successfully_exported', id: @exercise.id, title: @exercise.title), 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, notice: t('controllers.exercise.push_external_notice', account_link: account_link.readable)
else else
# logger.debug(error)
render json: { render json: {
status: 'fail', status: 'fail',
message: t('exercises.export_codeharbor.export_failed', id: @exercise.id, title: @exercise.title, error: error), 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})
} }
# redirect_to @exercise, alert: t('controllers.account_links.not_working', account_link: account_link.readable)
end end
end end

View File

@ -1,11 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
class CodeharborLink < ApplicationRecord class CodeharborLink < ApplicationRecord
validates :oauth2token, presence: true validates :push_url, presence: true
validates :check_uuid_url, presence: true
validates :api_key, presence: true
belongs_to :user, foreign_key: :user_id, class_name: 'InternalUser' belongs_to :user, foreign_key: :user_id, class_name: 'InternalUser'
def to_s def to_s
oauth2token id.to_s
end end
end end

View File

@ -7,7 +7,7 @@ class ExercisePolicy < AdminOrAuthorPolicy
define_method(action) { admin? || teacher? } define_method(action) { admin? || teacher? }
end end
[:clone?, :destroy?, :edit?, :statistics?, :update?, :feedback?, :push_proforma_xml?, :export_external_check?, :export_external_confirm?].each do |action| [:clone?, :destroy?, :edit?, :statistics?, :update?, :feedback?, :export_external_check?, :export_external_confirm?].each do |action|
define_method(action) { admin? || author? } define_method(action) { admin? || author? }
end end

View File

@ -2,7 +2,6 @@
module ExerciseService module ExerciseService
class PushExternal < ServiceBase class PushExternal < ServiceBase
CODEHARBOR_PUSH_LINK = Rails.env.production? ? 'https://codeharbor.openhpi.de/import_exercise' : 'http://localhost:3001/import_exercise'
def initialize(zip:, codeharbor_link:) def initialize(zip:, codeharbor_link:)
@zip = zip @zip = zip
@codeharbor_link = codeharbor_link @codeharbor_link = codeharbor_link
@ -11,7 +10,7 @@ module ExerciseService
def execute def execute
body = @zip.string body = @zip.string
begin begin
conn = Faraday.new(url: CODEHARBOR_PUSH_LINK) do |faraday| conn = Faraday.new(url: @codeharbor_link.push_url) do |faraday|
faraday.adapter Faraday.default_adapter faraday.adapter Faraday.default_adapter
end end

View File

@ -4,23 +4,14 @@
= f.label(:push_url) = f.label(:push_url)
= f.text_field :push_url, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.push_url'), class: 'form-control' = f.text_field :push_url, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.push_url'), class: 'form-control'
.form-group .form-group
= f.label(:oauth2token) = f.label(:check_uuid_url)
= f.text_field :check_uuid_url, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.check_uuid_url'), class: 'form-control'
.form-group
= f.label(:api_key)
.input-group .input-group
= f.text_field(:oauth2token, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.token'), class: 'form-control oauth2-token') = f.text_field(:api_key, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.token'), class: 'form-control api_key')
.input-group-btn .input-group-btn
= button_tag t('codeharbor_link.generate'), type: 'button', class: 'generate-oauth2-token btn btn-default' = button_tag t('codeharbor_link.generate'), type: 'button', class: 'generate-api_key btn btn-default'
.field-element.form-group
= f.label(:client_id)
.input-group
= f.text_field(:client_id, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.client_id'), class: 'form-control client-id')
.input-group-btn
= button_tag t('codeharbor_link.generate'), type: 'button', class: 'generate-client-id btn btn-default'
.field-element.form-group
= f.label(:client_secret)
.input-group
= f.text_field(:client_secret, data: {toggle: 'tooltip', placement: 'bottom'}, title: t('codeharbor_link.info.client_secret'), class: 'form-control client-secret')
.input-group-btn
= button_tag t('codeharbor_link.generate'), type: 'button', class: 'generate-client-secret btn btn-default'
.actions .actions
= render('shared/submit_button', f: f, object: @codeharbor_link) = render('shared/submit_button', f: f, object: @codeharbor_link)
- if @codeharbor_link.persisted? - if @codeharbor_link.persisted?

View File

@ -46,7 +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('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('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('.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.label'), '', class: 'dropdown-item export-start', data: {'exercise-id' => exercise.id}) if policy(exercise).push_proforma_xml? li = link_to(t('exercises.export_codeharbor.label'), '', class: 'dropdown-item export-start', data: {'exercise-id' => exercise.id}) if policy(exercise).export_external_confirm?
= render('shared/pagination', collection: @exercises) = render('shared/pagination', collection: @exercises)
p = render('shared/new_button', model: Exercise) p = render('shared/new_button', model: Exercise)

View File

@ -246,7 +246,9 @@ en:
generate: Generate generate: Generate
info: info:
push_url: | push_url: |
The address on CodeHarbor side your exercise can be exported to. If you don't know what to write here, ask an admin. The url from Codeharbor where your exercise can be exported to. If you don't know what to write here, ask an admin.
check_uuid_url: |
The url from Codeharbor where we can check if the exercise already exists. If you don't know what to write here, ask an admin.
name: | name: |
Can be anything to Identify your account link. Can be anything to Identify your account link.
token: | token: |
@ -323,13 +325,12 @@ en:
exercise_found: A corresponding exercise has been found on Codeocean. You can either <ul><li>Create a new exercise as a duplicate of this one on Codeharbor and push it to Codeocean, using the "Create new" button.</li><li>Overwrite the exercise on Codeocean, by pushing all changes. Only use "Overwrite" for bugfixes or very small changes - it will alter and may break published exercises.</li></ul> exercise_found: A corresponding exercise has been found on Codeocean. You can either <ul><li>Create a new exercise as a duplicate of this one on Codeharbor and push it to Codeocean, using the "Create new" button.</li><li>Overwrite the exercise on Codeocean, by pushing all changes. Only use "Overwrite" for bugfixes or very small changes - it will alter and may break published exercises.</li></ul>
exercise_found_no_right: A corresponding exercise has been found on Codeocean, but you don't have the rights to edit it. You can only <ul><li>Create a new exercise as a duplicate of this one on Codeharbor and push it to Codeocean, using the "Create new" button.</li></ul> exercise_found_no_right: A corresponding exercise has been found on Codeocean, but you don't have the rights to edit it. You can only <ul><li>Create a new exercise as a duplicate of this one on Codeharbor and push it to Codeocean, using the "Create new" button.</li></ul>
export_codeharbor: export_codeharbor:
fail: Failed to push the exercise to CodeHarbor.
label: Export to Codeharbor label: Export to Codeharbor
success: Successfully pushed the exercise to CodeHarbor.
dialogtitle: Export to Codeharbor dialogtitle: Export to Codeharbor
successfully_exported: 'Exercise has successfully been exported.<br>ID: %{id}<br>Title: %{title}' successfully_exported: 'Exercise has successfully been exported.<br>ID: %{id}<br>Title: %{title}'
export_failed: 'Export has failed.<br>ID: %{id}<br>Title: %{title}<br><br>Error: %{error}' export_failed: 'Export has failed.<br>ID: %{id}<br>Title: %{title}<br><br>Error: %{error}'
error: 'An error occurred while contacting Codeharbor<br>Error: %{message}' error: 'An error occurred while contacting Codeharbor<br>Error: %{message}'
checking_codeharbor: Checking whether exercise exists on Codeharbor.
file_form: file_form:
hints: hints:
feedback_message: This message is used as a hint for failing tests. feedback_message: This message is used as a hint for failing tests.

View File

@ -85,7 +85,6 @@ Rails.application.routes.draw do
get :reload get :reload
post :submit post :submit
get 'study_group_dashboard/:study_group_id', to: 'exercises#study_group_dashboard' get 'study_group_dashboard/:study_group_id', to: 'exercises#study_group_dashboard'
post :push_proforma_xml
post :export_external_check post :export_external_check
post :export_external_confirm post :export_external_confirm
end end

View File

@ -1,6 +1,7 @@
class AddPushUrlRenameOauth2tokenInCodeharborLinks < ActiveRecord::Migration[5.2] class AddPushUrlRenameOauth2tokenInCodeharborLinks < ActiveRecord::Migration[5.2]
def change def change
add_column :codeharbor_links, :push_url, :string add_column :codeharbor_links, :push_url, :string
add_column :codeharbor_links, :check_uuid_url, :string
rename_column :codeharbor_links, :oauth2token, :api_key rename_column :codeharbor_links, :oauth2token, :api_key
end end
end end

View File

@ -34,6 +34,7 @@ ActiveRecord::Schema.define(version: 2019_10_08_163045) do
t.datetime "updated_at" t.datetime "updated_at"
t.integer "user_id" t.integer "user_id"
t.string "push_url" t.string "push_url"
t.string "check_uuid_url"
t.index ["user_id"], name: "index_codeharbor_links_on_user_id" t.index ["user_id"], name: "index_codeharbor_links_on_user_id"
end end