diff --git a/backend/app/controllers/materials_controller.rb b/backend/app/controllers/materials_controller.rb index 023a557..77d6402 100644 --- a/backend/app/controllers/materials_controller.rb +++ b/backend/app/controllers/materials_controller.rb @@ -54,21 +54,27 @@ class MaterialsController < ApplicationController block = MaterialImportBlockMatcher.match_for_sha256(file_sha256) return render_material_import_block(block) if block + uploaded_blob = build_uploaded_material_blob!(file, file_sha256) material = nil - Material.transaction do - tag_name = TagName.find_undiscard_or_create_by!(name: tag_name_raw) - tag = tag_name.tag - tag = Tag.create!(tag_name:, category: :material) unless tag - material = Material.new(tag:, url:, - created_by_user: current_user, - updated_by_user: current_user) - material.file.attach(file) if file - apply_file_sha256!(material, file_sha256) - material.save! - upsert_export_paths!(material) - MaterialVersionRecorder.record!(material:, event_type: :create, - created_by_user: current_user) + begin + Material.transaction do + tag_name = TagName.find_undiscard_or_create_by!(name: tag_name_raw) + tag = tag_name.tag + tag = Tag.create!(tag_name:, category: :material) unless tag + + material = Material.new(tag:, url:, + created_by_user: current_user, + updated_by_user: current_user) + material.file.attach(uploaded_blob) if uploaded_blob + material.save! + upsert_export_paths!(material) + MaterialVersionRecorder.record!(material:, event_type: :create, + created_by_user: current_user) + end + rescue StandardError + uploaded_blob&.purge_later + raise end if material @@ -97,19 +103,30 @@ class MaterialsController < ApplicationController block = MaterialImportBlockMatcher.match_for_sha256(file_sha256) return render_material_import_block(block) if block - Material.transaction do - MaterialVersionRecorder.ensure_snapshot!(material, created_by_user: current_user) - tag_name = TagName.find_undiscard_or_create_by!(name: tag_name_raw) - tag = tag_name.tag - tag = Tag.create!(tag_name:, category: :material) unless tag + uploaded_blob = build_uploaded_material_blob!(file, file_sha256) - material.update!(tag:, url:, updated_by_user: current_user) - material.file.attach(file) if file - apply_file_sha256!(material, file_sha256) - material.file.detach if params.key?(:url) && url.present? && file.blank? - upsert_export_paths!(material) - MaterialVersionRecorder.record!(material:, event_type: :update, - created_by_user: current_user) + begin + Material.transaction do + MaterialVersionRecorder.ensure_snapshot!(material, created_by_user: current_user) + tag_name = TagName.find_undiscard_or_create_by!(name: tag_name_raw) + tag = tag_name.tag + tag = Tag.create!(tag_name:, category: :material) unless tag + + material.assign_attributes(tag:, url:, updated_by_user: current_user) + if uploaded_blob + material.file.attach(uploaded_blob) + clear_file_suppression!(material) + elsif params.key?(:url) && url.present? && file.blank? + material.file.detach + end + material.save! + upsert_export_paths!(material) + MaterialVersionRecorder.record!(material:, event_type: :update, + created_by_user: current_user) + end + rescue StandardError + uploaded_blob&.purge_later + raise end render json: MaterialRepr.base(material, host: request.base_url) @@ -220,13 +237,31 @@ class MaterialsController < ApplicationController status: :unprocessable_entity end - def apply_file_sha256! material, file_sha256 - return if file_sha256.blank? - return unless material.file.attached? + def build_uploaded_material_blob! file, file_sha256 + return nil unless file - blob = material.file.blob - blob.metadata['sha256'] = file_sha256 - blob.save! if blob.changed? + file.tempfile.rewind + + blob = ActiveStorage::Blob.create_and_upload!( + io: file.tempfile, + filename: file.original_filename, + content_type: file.content_type, + ) + + if file_sha256.present? + blob.metadata['sha256'] = file_sha256 + blob.save! if blob.changed? + end + + blob + ensure + file.tempfile.rewind if file&.tempfile + end + + def clear_file_suppression! material + material.file_suppressed_at = nil + material.file_suppressed_by_user = nil + material.file_suppression_reason = nil end def purge_material_file_snapshot material