diff --git a/app/api/chemotion/attachable_api.rb b/app/api/chemotion/attachable_api.rb index 714fe71a91..facfeb907c 100644 --- a/app/api/chemotion/attachable_api.rb +++ b/app/api/chemotion/attachable_api.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +# rubocop:disable Rails/SkipsModelValidations + module Chemotion class AttachableAPI < Grape::API resource :attachable do @@ -7,12 +9,16 @@ class AttachableAPI < Grape::API optional :files, type: Array[File], desc: 'files', default: [] optional :attachable_type, type: String, desc: 'attachable_type' optional :attachable_id, type: Integer, desc: 'attachable id' + optional :attfilesIdentifier, type: Array[String], desc: 'file identifier' optional :del_files, type: Array[Integer], desc: 'del file id', default: [] end after_validation do case params[:attachable_type] when 'ResearchPlan' - error!('401 Unauthorized', 401) unless ElementPolicy.new(current_user, ResearchPlan.find_by(id: params[:attachable_id])).update? + error!('401 Unauthorized', 401) unless ElementPolicy.new( + current_user, + ResearchPlan.find_by(id: params[:attachable_id]), + ).update? end end @@ -20,13 +26,15 @@ class AttachableAPI < Grape::API post 'update_attachments_attachable' do attachable_type = params[:attachable_type] attachable_id = params[:attachable_id] + if params.fetch(:files, []).any? attach_ary = [] rp_attach_ary = [] - params[:files].each do |file| + params[:files].each_with_index do |file, index| next unless (tempfile = file[:tempfile]) a = Attachment.new( + identifier: params[:attfilesIdentifier][index], bucket: file[:container_id], filename: file[:filename], file_path: file[:tempfile], @@ -34,8 +42,9 @@ class AttachableAPI < Grape::API created_for: current_user.id, content_type: file[:type], attachable_type: attachable_type, - attachable_id: attachable_id + attachable_id: attachable_id, ) + begin a.save! attach_ary.push(a.id) @@ -45,12 +54,14 @@ class AttachableAPI < Grape::API tempfile.unlink end end - - TransferThumbnailToPublicJob.set(queue: "transfer_thumbnail_to_public_#{current_user.id}").perform_later(rp_attach_ary) if rp_attach_ary.any? end - Attachment.where('id IN (?) AND attachable_type = (?)', params[:del_files].map!(&:to_i), attachable_type).update_all(attachable_id: nil) if params[:del_files].any? + if params[:del_files].any? + Attachment.where('id IN (?) AND attachable_type = (?)', params[:del_files].map!(&:to_i), + attachable_type).update_all(attachable_id: nil) + end true end end end end +# rubocop:enable Rails/SkipsModelValidations diff --git a/app/packs/src/fetchers/AttachmentFetcher.js b/app/packs/src/fetchers/AttachmentFetcher.js index db77521f3a..0390b7464a 100644 --- a/app/packs/src/fetchers/AttachmentFetcher.js +++ b/app/packs/src/fetchers/AttachmentFetcher.js @@ -156,10 +156,12 @@ export default class AttachmentFetcher { static updateAttachables(files, attachableType, attachableId, dels) { const data = new FormData(); files.forEach(file => { + data.append('attfilesIdentifier[]', file.id); data.append('files[]', file.file, file.name); }); data.append('attachable_type', attachableType); data.append('attachable_id', attachableId); + dels.forEach(f => { data.append('del_files[]', f.id); }); diff --git a/app/packs/src/fetchers/GenericElsFetcher.js b/app/packs/src/fetchers/GenericElsFetcher.js index ba1876b35e..6c8b92b3ee 100644 --- a/app/packs/src/fetchers/GenericElsFetcher.js +++ b/app/packs/src/fetchers/GenericElsFetcher.js @@ -88,25 +88,11 @@ export default class GenericElsFetcher extends GenericBaseFetcher { }); data.append('elInfo', JSON.stringify(elMap)); } - if ( - hasAttach === true - && element.attachments - && element.attachments.length > 0 - ) { - const newFiles = (element.attachments || []).filter( - (a) => a.is_new && !a.is_deleted - ); - const delFiles = (element.attachments || []).filter( - (a) => !a.is_new && a.is_deleted - ); - (newFiles || []).forEach((file) => { - data.append('attfiles[]', file.file, file.name); - data.append('attfilesIdentifier[]', file.id); - }); - (delFiles || []).forEach((f) => { - data.append('delfiles[]', f.id); - }); + + if (GenericElsFetcher.shouldUploadAttachments(hasAttach, element)) { + GenericElsFetcher.prepareAttachmentParam(element, data); } + (element.segments || []).forEach((segment) => { segMap[segment.segment_klass_id] = { type: 'SegmentProps', @@ -218,4 +204,27 @@ export default class GenericElsFetcher extends GenericBaseFetcher { static createRepo(params) { return this.execData(params, 'create_repo_klass'); } + + static prepareAttachmentParam(element, data) { + const newFiles = (element.attachments || []).filter( + (a) => a.is_new && !a.is_deleted + ); + const delFiles = (element.attachments || []).filter( + (a) => !a.is_new && a.is_deleted + ); + (newFiles || []).forEach((file) => { + data.append('attfiles[]', file.file, file.name); + data.append('attfilesIdentifier[]', file.id); + }); + (delFiles || []).forEach((f) => { + data.append('delfiles[]', f.id); + }); + } + + static shouldUploadAttachments(hasAttach, element) { + return hasAttach === true + && element.attachments + && element.attachments.length > 0 + && element.type !== 'research_plan'; + } } diff --git a/app/packs/src/fetchers/ResearchPlansFetcher.js b/app/packs/src/fetchers/ResearchPlansFetcher.js index f0e8dc21fd..768ea17057 100644 --- a/app/packs/src/fetchers/ResearchPlansFetcher.js +++ b/app/packs/src/fetchers/ResearchPlansFetcher.js @@ -32,6 +32,7 @@ export default class ResearchPlansFetcher { static create(researchPlan) { researchPlan.convertTemporaryImageFieldsInBody(); + const promise = fetch('/api/v1/research_plans/', { credentials: 'same-origin', method: 'post', @@ -40,10 +41,18 @@ export default class ResearchPlansFetcher { 'Content-Type': 'application/json' }, body: JSON.stringify(researchPlan.serialize()) - }).then((response) => response.json()).then((json) => GenericElsFetcher.uploadGenericFiles(researchPlan, json.research_plan.id, 'ResearchPlan', true) - .then(() => this.fetchById(json.research_plan.id))).catch((errorMessage) => { - console.log(errorMessage); - }); + }) + .then((response) => response.json()) + .then((json) => AttachmentFetcher.updateAttachables( + researchPlan.getNewAttachments(), + 'ResearchPlan', + json.research_plan.id, + researchPlan.getMarkedAsDeletedAttachments() + )().then(() => GenericElsFetcher.uploadGenericFiles(researchPlan, json.research_plan.id, 'ResearchPlan', true) + .then(() => this.fetchById(json.research_plan.id)))) + .catch((errorMessage) => { + console.log(errorMessage); + }); return promise; } @@ -59,13 +68,16 @@ export default class ResearchPlansFetcher { 'Content-Type': 'application/json' }, body: JSON.stringify(researchPlan.serialize()) - }).then( response => response.json()) - .then((json) =>{ return GenericElsFetcher.uploadGenericFiles(researchPlan, json.research_plan.id, 'ResearchPlan', true)}) - .then(() => { - return ResearchPlansFetcher.updateAnnotations(researchPlan) }) - .then(() =>{ - return this.fetchById(researchPlan.id)} ) - .catch((errorMessage) => {console.log(errorMessage);}); + }).then((response) => response.json()) + .then((json) => AttachmentFetcher.updateAttachables( + researchPlan.getNewAttachments(), + 'ResearchPlan', + json.research_plan.id, + researchPlan.getMarkedAsDeletedAttachments() + )().then(() => GenericElsFetcher.uploadGenericFiles(researchPlan, json.research_plan.id, 'ResearchPlan', true) + .then(() => ResearchPlansFetcher.updateAnnotations(researchPlan)) + .then(() => this.fetchById(researchPlan.id)))) + .catch((errorMessage) => { console.log(errorMessage); }); if (containerFiles.length > 0) { const tasks = []; @@ -258,28 +270,28 @@ export default class ResearchPlansFetcher { static updateAnnotations(researchPlan) { return Promise.all( [ - ResearchPlansFetcher.updateAnnotationsOfAttachments(researchPlan), - BaseFetcher.updateAnnotationsInContainer(researchPlan,[]) - ]); - } - - static updateAnnotationsOfAttachments(researchPlan){ + ResearchPlansFetcher.updateAnnotationsOfAttachments(researchPlan), + BaseFetcher.updateAnnotationsInContainer(researchPlan, []) + ] + ); + } - const updateTasks=[]; + static updateAnnotationsOfAttachments(researchPlan) { + const updateTasks = []; researchPlan.attachments - .filter((attach => attach.hasOwnProperty('updatedAnnotation'))) - .forEach(attach => { - let data = new FormData(); + .filter(((attach) => attach.hasOwnProperty('updatedAnnotation'))) + .forEach((attach) => { + const data = new FormData(); data.append('updated_svg_string', attach.updatedAnnotation); - updateTasks.push(fetch('/api/v1/attachments/' + attach.id + '/annotation', { + updateTasks.push(fetch(`/api/v1/attachments/${attach.id}/annotation`, { credentials: 'same-origin', method: 'post', body: data }) - .catch((errorMessage) => { - console.log(errorMessage); - })); - }) + .catch((errorMessage) => { + console.log(errorMessage); + })); + }); return Promise.all(updateTasks); } diff --git a/app/packs/src/fetchers/WellplatesFetcher.js b/app/packs/src/fetchers/WellplatesFetcher.js index 8c271c6f4d..a7e37ed1b2 100644 --- a/app/packs/src/fetchers/WellplatesFetcher.js +++ b/app/packs/src/fetchers/WellplatesFetcher.js @@ -88,7 +88,9 @@ export default class WellplatesFetcher { 'Content-Type': 'application/json' }, body: JSON.stringify(wellplate.serialize()) - }).then((response) => response.json()).then((json) => { + }) + .then((response) => response.json()) + .then((json) => { if (files.length <= 0) { return new Wellplate(json.wellplate); } diff --git a/app/packs/src/models/ResearchPlan.js b/app/packs/src/models/ResearchPlan.js index b59b0813e6..1830cf43a9 100644 --- a/app/packs/src/models/ResearchPlan.js +++ b/app/packs/src/models/ResearchPlan.js @@ -198,7 +198,7 @@ export default class ResearchPlan extends Element { return this._wellplates || []; } - upsertAttachments(attachmentsToAdd=[]) { + upsertAttachments(attachmentsToAdd = []) { const idsOfAttachmentsInResearchPlan = this.attachments.map( (attachmentInResearchPlan) => attachmentInResearchPlan.identifier ); @@ -252,8 +252,19 @@ export default class ResearchPlan extends Element { delete value.old_value; }); } - getAttachmentByIdentifier(identifier){ - return this.attachments - .filter((attachment)=>attachment.identifier===identifier)[0]; + + getAttachmentByIdentifier(identifier) { + return this.attachments + .filter((attachment) => attachment.identifier === identifier)[0]; + } + + getNewAttachments() { + return this.attachments + .filter((attachment) => attachment.is_new === true && !attachment.is_deleted); + } + + getMarkedAsDeletedAttachments() { + return this.attachments + .filter((attachment) => attachment.is_deleted === true && !attachment.is_new); } } diff --git a/spec/javascripts/packs/src/models/ResearchPlan.spec.js b/spec/javascripts/packs/src/models/ResearchPlan.spec.js index 1fc3ac81ca..f1e716f019 100644 --- a/spec/javascripts/packs/src/models/ResearchPlan.spec.js +++ b/spec/javascripts/packs/src/models/ResearchPlan.spec.js @@ -1,6 +1,9 @@ import Attachment from 'src/models/Attachment'; import ResearchPlan from 'src/models/ResearchPlan'; import expect from 'expect'; +import { + describe, it +} from 'mocha'; describe('ResearchPlan', () => { const researchPlan = ResearchPlan.buildEmpty(); @@ -180,4 +183,46 @@ describe('ResearchPlan', () => { expect(researchPlan.body).toEqual([permanentBodyField, expected]); }); }); + + describe('.getNewAttachments', () => { + describe('.with two new attachments but one is already deleted, one was already there', () => { + const attachmentNewAndDeleted = new Attachment(); + const attachmentNew = new Attachment(); + const attachmentPresent = new Attachment(); + researchPlan.attachments = [attachmentNewAndDeleted, attachmentNew, attachmentPresent]; + attachmentNewAndDeleted.is_new = true; + attachmentNewAndDeleted.is_deleted = true; + + attachmentNew.is_new = true; + attachmentPresent.is_deleted = false; + + attachmentPresent.is_new = false; + attachmentPresent.is_deleted = false; + + it('one attachment was found', () => { + expect(researchPlan.getNewAttachments().length).toEqual(1); + }); + }); + }); + + describe('.getMarkedAsDeletedAttachments', () => { + describe('.with two new attachments but one is already deleted, one was already there', () => { + const attachmentNewAndDeleted = new Attachment(); + const attachmentNew = new Attachment(); + const attachmentPresent = new Attachment(); + researchPlan.attachments = [attachmentNewAndDeleted, attachmentNew, attachmentPresent]; + attachmentNewAndDeleted.is_new = true; + attachmentNewAndDeleted.is_deleted = true; + + attachmentNew.is_new = true; + attachmentPresent.is_deleted = false; + + attachmentPresent.is_new = false; + attachmentPresent.is_deleted = false; + + it('one attachment was found', () => { + expect(researchPlan.getNewAttachments().length).toEqual(1); + }); + }); + }); });