diff --git a/app/controllers/code_ocean/files_controller.rb b/app/controllers/code_ocean/files_controller.rb index 3c255ffa..74c1932f 100644 --- a/app/controllers/code_ocean/files_controller.rb +++ b/app/controllers/code_ocean/files_controller.rb @@ -14,6 +14,21 @@ module CodeOcean create_and_respond(object: @file, path: proc { implement_exercise_path(@file.context.exercise, tab: 2) }) end + def create_and_respond(options = {}) + @object = options[:object] + respond_to do |format| + 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) + else + filename = (@object.path || '') + '/' + (@object.name || '') + (@object.file_type.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 + end + end + def destroy @file = CodeOcean::File.find(params[:id]) authorize! diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 69d1f46f..0304abb4 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -119,7 +119,7 @@ class ExercisesController < ApplicationController private :user_by_code_harbor_token def exercise_params - params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :team_id, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name) + params[:exercise].permit(:description, :execution_environment_id, :file_id, :instructions, :public, :hide_file_tree, :allow_file_creation, :team_id, :title, files_attributes: file_attributes).merge(user_id: current_user.id, user_type: current_user.class.name) end private :exercise_params diff --git a/app/models/code_ocean/file.rb b/app/models/code_ocean/file.rb index 48ec97d0..7b00cbdd 100644 --- a/app/models/code_ocean/file.rb +++ b/app/models/code_ocean/file.rb @@ -2,6 +2,17 @@ require File.expand_path('../../../uploaders/file_uploader', __FILE__) require File.expand_path('../../../../lib/active_model/validations/boolean_presence_validator', __FILE__) module CodeOcean + + class FileNameValidator < ActiveModel::Validator + def validate(record) + existing_files = File.where(name: record.name, path: record.path, file_type_id: record.file_type_id, + context_id: record.context_id, context: record.context).to_a + unless existing_files.empty? + record.errors[:base] << 'Duplicate' + end + end + end + class File < ActiveRecord::Base include DefaultValues @@ -44,6 +55,8 @@ module CodeOcean validates :weight, if: :teacher_defined_test?, numericality: true, presence: true validates :weight, absence: true, unless: :teacher_defined_test? + validates_with FileNameValidator, fields: [:name, :path, :file_type_id] + ROLES.each do |role| define_method("#{role}?") { self.role == role } end diff --git a/app/views/exercises/_editor_file_tree.html.slim b/app/views/exercises/_editor_file_tree.html.slim index 8ca349d4..c23158b9 100644 --- a/app/views/exercises/_editor_file_tree.html.slim +++ b/app/views/exercises/_editor_file_tree.html.slim @@ -2,8 +2,9 @@ hr -/= render('editor_button', classes: 'btn-block btn-primary btn-sm', data: {:'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: t('exercises.editor.create_file')) -/= render('editor_button', classes: 'btn-block btn-warning btn-sm', data: {:'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy')}, icon: 'fa fa-times', id: 'destroy-file', label: t('exercises.editor.destroy_file')) -= render('editor_button', classes: 'btn-block btn-primary btn-sm', icon: 'fa fa-download', id: 'download', label: t('exercises.editor.download')) +- if @exercise.allow_file_creation? + = render('editor_button', classes: 'btn-block btn-primary btn-sm', data: {:'data-cause' => 'file'}, icon: 'fa fa-plus', id: 'create-file', label: t('exercises.editor.create_file')) + = render('editor_button', classes: 'btn-block btn-warning btn-sm', data: {:'data-cause' => 'file', :'data-message-confirm' => t('shared.confirm_destroy')}, icon: 'fa fa-times', id: 'destroy-file', label: t('exercises.editor.destroy_file')) + = render('shared/modal', id: 'modal-file', template: 'code_ocean/files/_form', title: t('exercises.editor.create_file')) -= render('shared/modal', id: 'modal-file', template: 'code_ocean/files/_form', title: t('exercises.editor.create_file')) += render('editor_button', classes: 'btn-block btn-primary btn-sm', icon: 'fa fa-download', id: 'download', label: t('exercises.editor.download')) diff --git a/app/views/exercises/_form.html.slim b/app/views/exercises/_form.html.slim index 1995c8d8..f0f69f7a 100644 --- a/app/views/exercises/_form.html.slim +++ b/app/views/exercises/_form.html.slim @@ -28,6 +28,10 @@ label = f.check_box(:hide_file_tree) = t('activerecord.attributes.exercise.hide_file_tree') + .checkbox + label + = f.check_box(:allow_file_creation) + = t('activerecord.attributes.exercise.allow_file_creation') h2 = t('activerecord.attributes.exercise.files') ul#files.list-unstyled.panel-group = f.fields_for :files do |files_form| diff --git a/app/views/exercises/show.html.slim b/app/views/exercises/show.html.slim index 2181acf2..fc28272a 100644 --- a/app/views/exercises/show.html.slim +++ b/app/views/exercises/show.html.slim @@ -16,6 +16,7 @@ h1 = row(label: 'exercise.maximum_score', value: @exercise.maximum_score) = row(label: 'exercise.public', value: @exercise.public?) = row(label: 'exercise.hide_file_tree', value: @exercise.hide_file_tree?) += row(label: 'exercise.allow_file_creation', value: @exercise.allow_file_creation?) = row(label: 'exercise.embedding_parameters') do = content_tag(:input, nil, class: 'form-control', readonly: true, value: embedding_parameters(@exercise)) diff --git a/config/locales/de.yml b/config/locales/de.yml index a93a98db..e7d78943 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -38,6 +38,7 @@ de: team_id: Team title: Titel user: Autor + allow_file_creation: "Dateierstellung erlauben" external_user: consumer: Konsument email: E-Mail @@ -292,6 +293,8 @@ de: teacher_defined_test: Test als Bewertungsgrundlage user_defined_file: Benutzerdefinierte Datei user_defined_test: Benutzerdefinierter Test + error: + filename: "Die Datei konnte nicht gespeichert werden, da eine Datei mit dem Namen '%{name}' bereits existiert." hints: form: hints: diff --git a/config/locales/en.yml b/config/locales/en.yml index b835a721..f2470fc8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -38,6 +38,7 @@ en: team_id: Team title: Title user: Author + allow_file_creation: "Allow file creation" external_user: consumer: Consumer email: Email @@ -292,6 +293,8 @@ en: teacher_defined_test: Test for Assessment user_defined_file: User-defined File user_defined_test: User-defined Test + error: + filename: "The file could not be saved, because another file with the name '%{name}' already exists." hints: form: hints: diff --git a/db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb b/db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb new file mode 100644 index 00000000..ade1bb26 --- /dev/null +++ b/db/migrate/20160510145341_add_allow_file_creation_to_exercises.rb @@ -0,0 +1,5 @@ +class AddAllowFileCreationToExercises < ActiveRecord::Migration + def change + add_column :exercises, :allow_file_creation, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index eadfd44e..bcf1a675 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160426114951) do +ActiveRecord::Schema.define(version: 20160510145341) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -89,6 +89,7 @@ ActiveRecord::Schema.define(version: 20160426114951) do t.string "token" t.integer "team_id" t.boolean "hide_file_tree" + t.boolean "allow_file_creation" end add_index "exercises", ["execution_environment_id"], name: "test3", using: :btree