From 087e4de493e66fc94f55991ce313317f6481089d Mon Sep 17 00:00:00 2001 From: Farai Mutambara <71100224+mutambaraf@users.noreply.github.com> Date: Wed, 13 Aug 2025 15:45:58 +0100 Subject: [PATCH 1/4] hotfix: api token download for pdfs (#1155) --- apps/backend/src/factory/pdf/proposal.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/backend/src/factory/pdf/proposal.ts b/apps/backend/src/factory/pdf/proposal.ts index d5222eadd7..5376bb7a88 100644 --- a/apps/backend/src/factory/pdf/proposal.ts +++ b/apps/backend/src/factory/pdf/proposal.ts @@ -79,14 +79,13 @@ const getTechnicalReviewHumanReadableStatus = ( }; const getSampleQuestionarySteps = async ( - questionaryId: number, - user: UserWithRole | null + questionaryId: number ): Promise => { + const questionaryDataSource = container.resolve( + Tokens.QuestionaryDataSource + ); const questionarySteps = - await baseContext.queries.questionary.getQuestionarySteps( - user, - questionaryId - ); + await questionaryDataSource.getQuestionarySteps(questionaryId); if (!questionarySteps) { throw new Error( `Questionary steps for Questionary ID '${questionaryId}' not found, or the user has insufficient rights` @@ -577,7 +576,7 @@ export const collectProposalPDFDataTokenAccess = async ( undefined, sample, await getQuestionary(sample.questionaryId), - await getSampleQuestionarySteps(sample.questionaryId, null) + await getSampleQuestionarySteps(sample.questionaryId) ) ) ) @@ -612,7 +611,7 @@ export const collectProposalPDFDataTokenAccess = async ( undefined, genericTemplate, await getQuestionary(genericTemplate.questionaryId), - await getSampleQuestionarySteps(genericTemplate.questionaryId, null) + await getSampleQuestionarySteps(genericTemplate.questionaryId) ) ) ) From 0e788fd71bcdf289436a45e44bd6cddb5c5bb781 Mon Sep 17 00:00:00 2001 From: Thomas Cottee Meldrum Date: Mon, 13 Oct 2025 12:01:29 +0100 Subject: [PATCH 2/4] fix: proposal instrument assignment on clone --- .../src/mutations/ProposalMutations.ts | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/apps/backend/src/mutations/ProposalMutations.ts b/apps/backend/src/mutations/ProposalMutations.ts index 4c7b04e1be..afdadd51ca 100644 --- a/apps/backend/src/mutations/ProposalMutations.ts +++ b/apps/backend/src/mutations/ProposalMutations.ts @@ -840,6 +840,30 @@ export default class ProposalMutations { true ); + // TODO: Check if we need to also clone the technical review when cloning the proposal. + clonedProposal = await this.proposalDataSource.update({ + primaryKey: clonedProposal.primaryKey, + title: `Copy of ${clonedProposal.title}`, + abstract: clonedProposal.abstract, + proposerId: sourceProposal.proposerId, + statusId: 1, + created: new Date(), + updated: new Date(), + proposalId: clonedProposal.proposalId, + finalStatus: ProposalEndStatus.UNSET, + callId: callId, + questionaryId: clonedQuestionary.questionaryId, + commentForUser: '', + commentForManagement: '', + notified: false, + submitted: false, + referenceNumberSequence: 0, + managementDecisionSubmitted: false, + submittedDate: null, + experimentSequence: null, + fileId: null, + }); + const sourceProposalInstrumentId = await this.instrumentDataSource.getInstrumentsByProposalPk( sourceProposal.primaryKey @@ -867,30 +891,6 @@ export default class ProposalMutations { } } - // TODO: Check if we need to also clone the technical review when cloning the proposal. - clonedProposal = await this.proposalDataSource.update({ - primaryKey: clonedProposal.primaryKey, - title: `Copy of ${clonedProposal.title}`, - abstract: clonedProposal.abstract, - proposerId: sourceProposal.proposerId, - statusId: 1, - created: new Date(), - updated: new Date(), - proposalId: clonedProposal.proposalId, - finalStatus: ProposalEndStatus.UNSET, - callId: callId, - questionaryId: clonedQuestionary.questionaryId, - commentForUser: '', - commentForManagement: '', - notified: false, - submitted: false, - referenceNumberSequence: 0, - managementDecisionSubmitted: false, - submittedDate: null, - experimentSequence: null, - fileId: null, - }); - const proposalUsers = await this.userDataSource.getProposalUsers( sourceProposal.primaryKey ); From 49b799cc57b080f5044f6ae1105736646621be85 Mon Sep 17 00:00:00 2001 From: Thomas Cottee Meldrum Date: Mon, 13 Oct 2025 13:00:42 +0100 Subject: [PATCH 3/4] fix: assign proposals fap on clone --- .../src/mutations/ProposalMutations.ts | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/backend/src/mutations/ProposalMutations.ts b/apps/backend/src/mutations/ProposalMutations.ts index afdadd51ca..66203d7c6a 100644 --- a/apps/backend/src/mutations/ProposalMutations.ts +++ b/apps/backend/src/mutations/ProposalMutations.ts @@ -46,6 +46,7 @@ import { WorkflowEngineProposalType } from '../workflowEngine/proposal'; import { ProposalAuthorization } from './../auth/ProposalAuthorization'; import { CallDataSource } from './../datasources/CallDataSource'; import { CloneUtils } from './../utils/CloneUtils'; +import FapMutations from './FapMutations'; import InstrumentMutations from './InstrumentMutations'; @injectable() @@ -871,14 +872,18 @@ export default class ProposalMutations { if (sourceProposalInstrumentId.length > 0) { const instrumentMutations = container.resolve(InstrumentMutations); + const fapMutations = container.resolve(FapMutations); try { - instrumentMutations.assignProposalsToInstrumentsInternal(agent, { - instrumentIds: sourceProposalInstrumentId.map( - (instrument) => instrument.id - ), - proposalPks: [clonedProposal.primaryKey], - }); + await instrumentMutations.assignProposalsToInstrumentsInternal( + agent, + { + instrumentIds: sourceProposalInstrumentId.map( + (instrument) => instrument.id + ), + proposalPks: [clonedProposal.primaryKey], + } + ); } catch (error) { logger.logWarn( 'Could not assign cloned proposals to the same instruments', @@ -889,6 +894,24 @@ export default class ProposalMutations { } ); } + + try { + await fapMutations.assignProposalsToFapsUsingCallInstrumentsInternal( + null, + { + instrumentIds: sourceProposalInstrumentId.map( + (instrument) => instrument.id + ), + proposalPks: [clonedProposal.primaryKey], + } + ); + } catch (error) { + logger.logWarn('Could not assign cloned proposals to faps', { + error, + clonedProposal, + sourceProposal, + }); + } } const proposalUsers = await this.userDataSource.getProposalUsers( From a4217ddae4a86e007f450842dd3af733d29d3b44 Mon Sep 17 00:00:00 2001 From: Thomas Cottee Meldrum Date: Mon, 13 Oct 2025 13:41:49 +0100 Subject: [PATCH 4/4] fix: cloning tests --- apps/e2e/cypress/e2e/proposals.cy.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/e2e/cypress/e2e/proposals.cy.ts b/apps/e2e/cypress/e2e/proposals.cy.ts index 44f124ea19..32adf63e92 100644 --- a/apps/e2e/cypress/e2e/proposals.cy.ts +++ b/apps/e2e/cypress/e2e/proposals.cy.ts @@ -611,11 +611,6 @@ context('Proposal tests', () => { }); it('Should be able clone proposal to another call. Cloned proposals should be assigned the source proposals instruments', () => { - cy.createCall({ - ...newCall, - proposalWorkflowId: createdWorkflowId, - }); - // Create an ended call to test if it is not available for cloning. cy.createCall({ ...newCall, @@ -637,6 +632,16 @@ context('Proposal tests', () => { instrumentIds: [result.createInstrument.id], proposalPks: [createdProposalPk], }); + + cy.createCall({ + ...newCall, + proposalWorkflowId: createdWorkflowId, + }).then((call) => { + cy.assignInstrumentToCall({ + callId: call.createCall.id, + instrumentFapIds: [{ instrumentId: result.createInstrument.id }], + }); + }); } });