diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index b76ff56f5..457cb9b3a 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -11,7 +11,6 @@ use OCA\Forms\Db\Form; use OCA\Forms\Db\FormMapper; use OCA\Forms\Db\ShareMapper; -use OCA\Forms\Db\SubmissionMapper; use OCA\Forms\Service\ConfigService; use OCA\Forms\Service\FormsService; use OCP\Accounts\IAccountManager; @@ -47,7 +46,6 @@ public function __construct( IRequest $request, private readonly FormMapper $formMapper, private readonly ShareMapper $shareMapper, - private readonly SubmissionMapper $submissionMapper, private readonly ConfigService $configService, private readonly FormsService $formsService, private readonly IAccountManager $accountManager, @@ -67,7 +65,7 @@ public function __construct( #[NoAdminRequired()] #[NoCSRFRequired()] #[FrontpageRoute(verb: 'GET', url: '/')] - public function index(?string $hash = null, ?int $submissionId = null): TemplateResponse { + public function index(?string $hash = null): TemplateResponse { // Ensure the Comments client is available and load comments resources $this->commentsManager->load(); Util::addScript($this->appName, 'forms-main', 'comments'); @@ -87,15 +85,6 @@ public function index(?string $hash = null, ?int $submissionId = null): Template } } - if (isset($submissionId)) { - try { - $submission = $this->submissionMapper->findById($submissionId); - $this->initialState->provideInitialState('submissionId', $submission->id); - } catch (DoesNotExistException) { - // Ignore exception and just don't set the initialState value - } - } - return new TemplateResponse($this->appName, self::TEMPLATE_MAIN, [ 'id-app-content' => '#app-content-vue', 'id-app-navigation' => '#app-navigation-vue', @@ -129,10 +118,7 @@ public function resultsViews(string $hash): TemplateResponse { #[NoCSRFRequired()] #[FrontpageRoute(verb: 'GET', url: '/{hash}/submit/{submissionId}', requirements: ['hash' => '[a-zA-Z0-9]{16,}', 'submissionId' => '\d+'])] public function submitViewWithSubmission(string $hash, int $submissionId): TemplateResponse { - $form = $this->formMapper->findByHash($hash); - $canUserEditSubmission = $this->formsService->canDeleteResults($form); - - return $canUserEditSubmission ? $this->index($hash, $submissionId) : $this->index($hash); + return $this->index($hash); } /** diff --git a/src/views/Submit.vue b/src/views/Submit.vue index 9439c8142..baafeca74 100644 --- a/src/views/Submit.vue +++ b/src/views/Submit.vue @@ -562,9 +562,7 @@ export default defineComponent({ const routeSubmissionId = Array.isArray(rawSubmissionId) ? rawSubmissionId[0] : rawSubmissionId - const id = - routeSubmissionId || loadState(formsAppName, 'submissionId', null) - return id ? parseInt(String(id), 10) : null + return routeSubmissionId ? parseInt(String(routeSubmissionId), 10) : null }) /** @@ -636,6 +634,35 @@ export default defineComponent({ ) } + /** + * Replace the stored draft with all current answers (e.g. after loading a submission) + */ + function saveAllAnswersToLocalStorage(): void { + if (!props.isLoggedIn) { + return + } + const state: StoredAnswersMap = {} + for (const question of validQuestions.value) { + const value = answers.value[question.id] + if ( + value === undefined + || (Array.isArray(value) + ? value.length === 0 + : Object.keys(value).length === 0) + ) { + continue + } + state[`${question.id}`] = { + value, + type: answerTypes[question.type].component.name ?? '', + } + } + localStorage.setItem( + `nextcloud_forms_${props.publicView ? props.shareHash : props.hash}`, + JSON.stringify(state), + ) + } + /** * Deletes a non-existing field from local storage */ @@ -743,6 +770,7 @@ export default defineComponent({ } answers.value = loaded + saveAllAnswersToLocalStorage() } catch (error) { logger.error('Error while loading response', { error }) showError( @@ -1014,6 +1042,18 @@ export default defineComponent({ }, ) + watch(submissionId, async (): Promise => { + if (props.publicView || !props.isLoggedIn) { + return + } + resetData() + if (submissionId.value) { + await fetchSubmission() + } else { + initFromLocalStorage() + } + }) + // Navigation guards only work inside the routed Forms app, not the public submit entry. if (!props.publicView) { onBeforeRouteUpdate(async () => { diff --git a/tests/Unit/Controller/PageControllerTest.php b/tests/Unit/Controller/PageControllerTest.php index cd845cbc7..f1a21e942 100644 --- a/tests/Unit/Controller/PageControllerTest.php +++ b/tests/Unit/Controller/PageControllerTest.php @@ -11,7 +11,6 @@ use OCA\Forms\Controller\PageController; use OCA\Forms\Db\FormMapper; use OCA\Forms\Db\ShareMapper; -use OCA\Forms\Db\SubmissionMapper; use OCA\Forms\Service\ConfigService; use OCA\Forms\Service\FormsService; use OCP\Accounts\IAccountManager; @@ -33,7 +32,6 @@ class PageControllerTest extends TestCase { private IRequest|MockObject $request; private FormMapper|MockObject $formMapper; private ShareMapper|MockObject $shareMapper; - private SubmissionMapper|MockObject $submissionMapper; private ConfigService|MockObject $configService; private FormsService|MockObject $formsService; private IAccountManager|MockObject $accountManager; @@ -50,7 +48,6 @@ public function setUp(): void { $this->request = $this->createMock(IRequest::class); $this->formMapper = $this->createMock(FormMapper::class); $this->shareMapper = $this->createMock(ShareMapper::class); - $this->submissionMapper = $this->createMock(SubmissionMapper::class); $this->configService = $this->createMock(ConfigService::class); $this->formsService = $this->createMock(FormsService::class); $this->accountManager = $this->createMock(IAccountManager::class); @@ -66,7 +63,6 @@ public function setUp(): void { $this->request, $this->formMapper, $this->shareMapper, - $this->submissionMapper, $this->configService, $this->formsService, $this->accountManager,