From 321220012f2b1562da60c9b05fc4ba212d7b6f4d Mon Sep 17 00:00:00 2001 From: Andy Scherzinger Date: Wed, 4 Nov 2026 16:50:33 +0100 Subject: [PATCH] fix(migration): skip answers of deleted questions on import Deleted questions are not exported, their answers are. Importing such an answer failed, as no imported question belongs to it, and stopped the import of the remaining forms. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Andy Scherzinger --- lib/FormsMigrator.php | 4 ++++ tests/Unit/FormsMigratorTest.php | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/lib/FormsMigrator.php b/lib/FormsMigrator.php index b0fc92855..303d42a1d 100644 --- a/lib/FormsMigrator.php +++ b/lib/FormsMigrator.php @@ -203,6 +203,10 @@ public function import(IUser $user, IImportSource $importSource, OutputInterface $this->submissionMapper->insert($submission); foreach ($submissionData['answers'] as $answerData) { + if (!array_key_exists($answerData['questionId'], $questionIdMap)) { + continue; + } + $answer = new Answer(); $answer->setSubmissionId($submission->getId()); $answer->setQuestionId($questionIdMap[$answerData['questionId']]); diff --git a/tests/Unit/FormsMigratorTest.php b/tests/Unit/FormsMigratorTest.php index 10d6c4e78..3d01cb962 100644 --- a/tests/Unit/FormsMigratorTest.php +++ b/tests/Unit/FormsMigratorTest.php @@ -309,6 +309,31 @@ public function testImport(string $inputJson, int $expectedOpens) { $this->formsMigrator->import($user, $importSource, $output); } + public function testImportSkipsAnswersOfQuestionsNotExported(): void { + $inputJson = '[{"title":"Link","description":"","created":1646251830,"access":{"permitAllUsers":false,"showToAllUsers":false},"expires":0,"state":0,"isAnonymous":false,"submitMultiple":false,"allowEditSubmissions":false,"showExpiration":false,"lastUpdated":123456789,' + . '"questions":[{"id":14,"order":1,"type":"short","isRequired":false,"text":"Name?","description":"","extraSettings":{},"options":[]}],' + . '"submissions":[{"userId":"anyUser@localhost","timestamp":1651354059,"answers":[{"questionId":14,"text":"Ann"},{"questionId":13,"text":"Answer of a deleted question"}]}]}]'; + + $user = $this->createMock(IUser::class); + $user->method('getUID')->willReturn('someUser'); + $importSource = $this->createMock(IImportSource::class); + $importSource->method('getMigratorVersion')->willReturn(1); + $importSource->method('getFileContents')->willReturn($inputJson); + $this->questionMapper->method('insert')->willReturnCallback(function ($question) { + $question->setId(100); + return $question; + }); + + $this->answerMapper->expects($this->once()) + ->method('insert') + ->willReturnCallback(function ($answer) { + $this->assertSame(100, $answer->getQuestionId()); + return $answer; + }); + + $this->formsMigrator->import($user, $importSource, $this->createMock(OutputInterface::class)); + } + public function testImport_NoVersion() { $user = $this->createMock(IUser::class); $importSource = $this->createMock(IImportSource::class);