From c828ee5f3c602a8d2df3c19bc7b63b929b3fa49a Mon Sep 17 00:00:00 2001 From: Anne Jan Brouwer Date: Wed, 1 May 2024 09:50:26 +0200 Subject: [PATCH] Update to v1.4.57 --- .db_requirements | 2 +- .env | 4 + .env.ci | 57 +- .env.test | 16 +- .eslintrc.js | 3 +- .github/CODEOWNERS | 3 + .github/dependabot.yml | 18 + .github/workflows/ci.yml | 124 + .github/workflows/daily-e2e-acc-robotrun.yml | 38 + .github/workflows/daily-e2e-tst-robotrun.yml | 41 + .github/workflows/migration-check.yml | 85 + .github/workflows/package.yml | 51 + .github/workflows/robotframeworkci.yml | 144 + .gitignore | 1 + .irealisatie | 7 + .markdownlint.json | 3 + .vscode/settings.json | 6 + Taskfile.dist.yml | 36 +- assets/img/admin/icons.svg | 12 +- assets/img/chevron-down.svg | 2 +- assets/img/public/icons.svg | 5 - assets/js/admin/clickable-row.test.ts | 5 +- assets/js/admin/clickable-row.ts | 2 +- assets/js/admin/dossier/documents-status.ts | 8 +- assets/js/admin/print.test.ts | 5 +- assets/js/admin/utils/file/file-system.ts | 4 +- assets/js/admin/utils/file/file.test.ts | 7 +- assets/js/admin/utils/file/file.ts | 14 +- assets/js/admin/utils/file/upload.ts | 76 +- assets/js/admin/visibility-toggler.test.ts | 2 +- assets/js/admin/vue/component/Alert.vue | 8 +- assets/js/admin/vue/component/Collapsible.vue | 57 + .../decision-attachments/AttachmentForm.vue | 120 - .../admin/vue/component/file/MimeTypeIcon.vue | 2 +- .../file/upload/AlreadyUploadedFiles.vue | 31 + .../component/file/upload/InvalidFiles.vue | 19 +- .../component/file/upload/SelectedFile.vue | 129 +- .../component/file/upload/SelectedFiles.vue | 20 +- .../vue/component/file/upload/UploadArea.vue | 157 +- .../component/file/upload/UploadVisual.vue | 40 +- .../js/admin/vue/component/form/Combobox.vue | 316 + .../vue/component/form/ErrorMessages.vue | 33 + assets/js/admin/vue/component/form/Form.vue | 24 +- .../js/admin/vue/component/form/FormHelp.vue | 4 +- .../js/admin/vue/component/form/FormLabel.vue | 7 +- .../admin/vue/component/form/InputErrors.vue | 19 +- .../js/admin/vue/component/form/InputFile.vue | 79 +- .../admin/vue/component/form/InputSelect.vue | 33 +- .../js/admin/vue/component/form/InputText.vue | 35 +- .../vue/component/form/MultiCombobox.vue | 200 + .../admin/vue/component/form/MultiSelect.vue | 200 + .../vue/component/form/RemovableSelect.vue | 186 + .../component/form/SubmitValidationErrors.vue | 30 + .../AttachmentsList.vue | 37 +- .../CovenantUploadForm.vue | 179 + .../InputDocumentDate.vue | 27 + .../InputDocumentFile.vue | 36 + .../InputDocumentLanguages.vue | 29 + .../InputDocumentName.vue | 26 + .../InputDocumentTypes.vue | 36 + .../publication-attachments/InputGrounds.vue | 34 + .../InputReference.vue | 20 + .../PublicationAttachmentsForm.vue | 194 + .../UploadedAttachment.vue | 35 +- .../helper/document-types.ts | 74 + .../publication-attachments/helper/index.ts | 1 + assets/js/admin/vue/composables/form-store.ts | 45 +- assets/js/admin/vue/composables/index.ts | 1 + .../js/admin/vue/composables/input-store.ts | 52 +- .../vue/composables/multi-input-store.ts | 106 + .../admin/vue/controllers/ConvenantUpload.vue | 153 + .../vue/controllers/DecisionAttachments.vue | 130 - .../controllers/MultiComboboxController.vue | 20 + .../controllers/PublicationAttachments.vue | 147 + .../vue/controllers/UploadAreaController.vue | 18 + assets/js/admin/vue/controllers/Uploads.vue | 23 - assets/js/admin/vue/form/interface.ts | 14 +- assets/js/admin/vue/form/validator-message.ts | 4 + assets/js/admin/vue/form/validator.ts | 43 +- .../test/component/Alert/Alert.vue.test.ts | 65 + .../vue/test/component/Icon/Icon.vue.test.ts | 58 + assets/js/admin/vue/vue.d.ts | 5 + assets/js/component/icon.test.ts | 2 +- .../public/search-results/helpers/params.ts | 6 +- assets/js/utils/__mocks__/browser.ts | 13 +- assets/js/utils/animation.test.ts | 6 +- assets/js/utils/debounce.test.ts | 25 +- assets/js/utils/element.test.ts | 2 +- assets/js/utils/element.ts | 25 +- assets/js/utils/focus.test.ts | 4 +- assets/js/utils/id.test.ts | 4 +- assets/js/utils/js-enabled.test.ts | 2 +- assets/js/utils/mocks.ts | 4 +- assets/js/utils/number.ts | 2 + assets/js/utils/on/before-unload.test.ts | 4 +- assets/js/utils/on/dom-ready.test.ts | 8 +- assets/js/utils/on/focus-in.test.ts | 4 +- assets/js/utils/on/focus-out.test.ts | 4 +- assets/js/utils/on/key-down.test.ts | 4 +- assets/js/utils/on/one-of-keys-down.test.ts | 4 +- assets/js/utils/string.ts | 1 + assets/styles/admin/base.css | 5 + assets/styles/admin/components.css | 3 + assets/styles/admin/components/combobox.css | 41 + assets/styles/admin/components/details.css | 9 + assets/styles/admin/components/form.css | 5 + assets/styles/admin/components/link-list.css | 24 + assets/styles/admin/components/table.css | 12 +- assets/styles/public/components/table.css | 4 + bin/auth-package-managers | 10 +- compose.yml | 6 + composer.json | 40 +- composer.lock | 2616 +-- config/bundles.php | 3 + config/elastic/mapping-v16.json | 2 +- config/packages/api_platform.yaml | 26 + config/packages/auth_matrix.yaml | 37 +- config/packages/doctrine.yaml | 6 + config/packages/flysystem.yaml | 10 +- config/packages/framework.yaml | 5 + config/packages/messenger.yaml | 8 +- config/packages/oneup_uploader.yaml | 28 + config/packages/twig.yaml | 1 + config/packages/workflow.php | 12 + config/packages/zenstruck_foundry.yaml | 11 + config/routes.yaml | 12 +- config/routes/api_platform.yaml | 4 + config/services.yaml | 49 +- docker/Dockerfile | 12 +- docs/access-roles.md | 88 +- docs/commands.md | 11 + docs/definition-of-done.md | 19 + docs/doctrine.md | 24 +- docs/dossier-types.md | 102 + docs/environment-settings.md | 13 + docs/install.md | 41 +- docs/logging.md | 22 +- docs/technical.md | 30 + docs/test-use-cases.md | 94 + docs/test.md | 140 +- docs/translations.md | 39 + docs/update.md | 6 +- docs/usage.md | 10 +- jest.config.ts | 212 - migrations/Version20240207084512.php | 36 + migrations/Version20240318193318.php | 34 + migrations/Version20240320124455.php | 28 + migrations/Version20240320135010.php | 44 + migrations/Version20240409003630.php | 29 + migrations/Version20240409140944.php | 29 + migrations/Version20240409144556.php | 29 + package-lock.json | 13800 +++++++--------- package.json | 18 +- phpstan-baseline.neon | 95 +- phpstan.dist.neon | 4 + phpunit.xml | 26 +- pyproject.toml | 60 + sonar-project.properties | 29 + .../CovenantAttachmentCreateDto.php | 59 + .../CovenantAttachmentDto.php | 117 + .../CovenantAttachmentProcessor.php | 119 + .../CovenantAttachmentProvider.php | 54 + .../CovenantAttachmentUpdateDto.php | 68 + .../CovenantDocumentCreateDto.php | 51 + .../CovenantDocument/CovenantDocumentDto.php | 97 + .../CovenantDocumentProcessor.php | 108 + .../CovenantDocumentProvider.php | 35 + .../CovenantDocumentUpdateDto.php | 47 + .../DecisionAttachmentCreateDto.php | 59 + .../DecisionAttachmentDto.php | 117 + .../DecisionAttachmentProcessor.php | 119 + .../DecisionAttachmentProvider.php | 54 + .../DecisionAttachmentUpdateDto.php | 68 + src/Api/Admin/Dossier/DossierReferenceDto.php | 27 + src/Command/CleanSheet.php | 6 +- src/Command/Cron/DossierPublisher.php | 58 - src/Command/Cron/DossierPublisherCommand.php | 59 + src/Command/Ingest/IngestDocument.php | 60 - src/Command/Ingest/IngestDossier.php | 38 +- src/Command/SqlDump.php | 2 +- src/Command/TransConvert.php | 74 - src/Command/UploadDocument.php | 59 - .../Admin/CustomDropzoneController.php | 91 + .../Covenant/ContentStepController.php | 175 + .../Covenant/DetailsStepController.php | 155 + .../Dossier/Covenant/DownloadController.php | 57 + .../Covenant/PublicationStepController.php | 98 + .../Admin/Dossier/DossierActionController.php | 108 + .../DossierAdministrationController.php | 10 +- .../Dossier/DossierAuthorizationTrait.php | 36 - .../Dossier/DossierConceptController.php | 344 - .../Admin/Dossier/DossierController.php | 151 +- .../Admin/Dossier/DossierEditController.php | 430 - .../Admin/Dossier/DownloadController.php | 44 +- .../WooDecision/DecisionStepController.php | 182 + .../WooDecision/DetailsStepController.php | 143 + .../DocumentActionController.php | 65 +- .../{ => WooDecision}/DocumentController.php | 42 +- .../DocumentsConceptStepController.php | 106 + .../DocumentsEditStepController.php | 184 + .../WooDecision/DocumentsStepHelper.php | 60 + .../WooDecision/DownloadController.php | 39 + .../WooDecision/PublicationStepController.php | 91 + src/Controller/Admin/ElasticController.php | 19 +- .../InquiryAdmininistrationController.php | 5 - src/Controller/Admin/InquiryController.php | 7 +- src/Controller/Admin/UploaderController.php | 24 + src/Controller/Admin/UserController.php | 7 +- src/Controller/CovenantController.php | 160 + src/Controller/DocumentController.php | 13 +- src/Controller/InquiryController.php | 2 +- src/Controller/LegacyDossierController.php | 12 +- .../LocalizedTemplateController.php | 48 - src/Controller/SearchController.php | 6 +- ...ntroller.php => WooDecisionController.php} | 91 +- .../Ingest/Covenant/CovenantIngester.php | 28 + src/Domain/Ingest/DossierIngester.php | 29 + src/Domain/Ingest/IngestDossierHandler.php | 31 + .../Ingest}/IngestDossierMessage.php | 2 +- src/Domain/Ingest/IngestException.php | 27 + .../WooDecision/WooDecisionIngester.php | 38 + .../Attachment/AbstractAttachment.php | 101 + .../AttachmentExceptionInterface.php | 9 + .../Attachment/AttachmentLanguage.php | 46 + .../Attachment/AttachmentLanguageFactory.php | 30 + .../Publication/Attachment/AttachmentType.php | 116 + .../Attachment/AttachmentTypeBranch.php | 67 + .../AttachmentTypeBranchException.php | 13 + .../Attachment/AttachmentTypeFactory.php | 186 + .../Attachment/EntityWithAttachments.php | 30 + .../Publication/Attachment/HasAttachments.php | 46 + .../Attachment/RuntimeAttachmentException.php | 16 + .../Publication/Dossier/AbstractDossier.php | 298 + .../Dossier/AbstractDossierRepository.php | 67 + .../Dossier/Admin/DossierFilterParameters.php | 22 + .../Dossier/Admin/DossierListingService.php | 91 + .../Dossier/Admin/DossierQueryConditions.php | 32 + .../Dossier/Admin/DossierSearchService.php | 51 + .../Dossier/Command/DeleteDossierCommand.php | 28 + .../Dossier/DossierDeleteHelper.php | 51 + .../Publication/Dossier/DossierFactory.php | 28 + .../Publication/Dossier/DossierPublisher.php | 45 + .../Publication/Dossier/DossierStatus.php} | 20 +- .../Dossier/Event/AbstractCovenantEvent.php | 15 + .../Dossier/Handler/DeleteDossierHandler.php | 48 + .../Dossier/Step/StepActionHelper.php | 149 + .../Dossier/Step/StepCompletionValidator.php | 30 + .../Dossier/Step/StepDefinitionInterface.php | 18 + .../Dossier/Step/StepException.php | 19 + .../Publication/Dossier/Step}/StepName.php | 3 +- .../Command/AbstractCovenantCommand.php | 15 + .../CreateCovenantAttachmentCommand.php | 27 + .../Command/CreateCovenantCommand.php | 9 + .../Command/CreateCovenantDocumentCommand.php | 25 + .../DeleteCovenantAttachmentCommand.php | 16 + .../Command/DeleteCovenantDocumentCommand.php | 15 + .../UpdateCovenantAttachmentCommand.php | 28 + .../Command/UpdateCovenantContentCommand.php | 9 + .../Command/UpdateCovenantDetailsCommand.php | 9 + .../Command/UpdateCovenantDocumentCommand.php | 25 + .../UpdateCovenantPublicationCommand.php | 9 + .../Dossier/Type/Covenant/Covenant.php | 97 + .../Type/Covenant/CovenantAttachment.php | 44 + .../Covenant/CovenantAttachmentRepository.php | 113 + .../Dossier/Type/Covenant/CovenantConfig.php | 66 + .../Type/Covenant/CovenantDeleteStrategy.php | 26 + .../Type/Covenant/CovenantDocument.php | 43 + .../Covenant/CovenantDocumentRepository.php | 68 + .../Type/Covenant/CovenantWorkflow.php | 82 + .../Event/CovenantAttachmentDeletedEvent.php | 16 + .../Event/CovenantAttachmentUpdatedEvent.php | 15 + .../Covenant/Event/CovenantCreatedEvent.php | 11 + .../Event/CovenantDocumentDeletedEvent.php | 17 + .../Event/CovenantDocumentUpdatedEvent.php | 15 + .../Covenant/Event/CovenantUpdatedEvent.php | 11 + .../CovenantAttachmentNotFoundException.php | 13 + .../CreateCovenantAttachmentHandler.php | 70 + .../DeleteCovenantAttachmentHandler.php | 48 + .../UpdateCovenantAttachmentHandler.php | 104 + ...CovenantDocumentAlreadyExistsException.php | 13 + .../CovenantDocumentNotFoundException.php | 13 + .../CreateCovenantDocumentHandler.php | 73 + .../DeleteCovenantDocumentHandler.php | 48 + .../UpdateCovenantDocumentHandler.php | 96 + .../Handler/CreateCovenantHandler.php | 37 + .../Handler/UpdateCovenantContentHandler.php | 38 + .../Handler/UpdateCovenantDetailsHandler.php | 38 + .../UpdateCovenantPublicationHandler.php | 50 + .../Covenant/Steps/ContentStepDefinition.php | 38 + .../Covenant/Steps/DetailsStepDefinition.php | 38 + .../Steps/PublicationStepDefinition.php | 38 + .../Type/DossierDeleteStrategyInterface.php | 12 + .../Publication/Dossier/Type/DossierType.php | 29 + .../Type/DossierTypeConfigInterface.php | 30 + .../Dossier/Type/DossierTypeException.php | 18 + .../Dossier/Type/DossierTypeManager.php | 81 + .../Dossier/Type/DossierTypeWithPreview.php | 14 + .../CreateDecisionAttachmentCommand.php | 27 + .../DeleteDecisionAttachmentCommand.php | 16 + .../UpdateDecisionAttachmentCommand.php | 28 + .../Command/WithDrawAllDocumentsCommand.php | 34 + .../Command/WithDrawDocumentCommand.php | 37 + .../Event/AllDocumentsWithDrawnEvent.php | 18 + .../Event/DecisionAttachmentCreatedEvent.php | 15 + .../Event/DecisionAttachmentDeletedEvent.php | 17 + .../Event/DecisionAttachmentUpdatedEvent.php | 15 + .../Event/DocumentWithDrawnEvent.php | 18 + .../CreateDecisionAttachmentHandler.php | 70 + .../DecisionAttachmentNotFoundException.php | 13 + .../DeleteDecisionAttachmentHandler.php | 48 + .../UpdateDecisionAttachmentHandler.php | 104 + .../Handler/WithDrawAllDocumentsHandler.php | 47 + .../Handler/WithDrawDocumentHandler.php | 65 + .../Steps/DecisionStepDefinition.php | 38 + .../Steps/DetailsStepDefinition.php | 38 + .../Steps/DocumentsStepDefinition.php | 44 + .../Steps/PublicationStepDefinition.php | 33 + .../Dossier/Type/WooDecision/WooDecision.php | 18 + .../Type/WooDecision/WooDecisionConfig.php | 76 + .../WooDecision/WooDecisionDeleteStrategy.php | 41 + .../Type/WooDecision/WooDecisionWorkflow.php | 121 + .../Dossier/Type/WorkflowConfigHelper.php | 28 + .../Dossier/Workflow/DossierMarkingStore.php | 40 + .../Workflow/DossierStatusTransition.php | 22 + .../Workflow/DossierWorkflowException.php | 53 + .../Workflow/DossierWorkflowManager.php | 87 + .../Workflow/Guard/PublishAsPreviewGuard.php | 44 + .../Dossier/Workflow/Guard/PublishGuard.php | 37 + .../Dossier/Workflow/Guard/ScheduleGuard.php | 34 + .../DecisionAttachmentCreatedHandler.php | 35 + .../DecisionAttachmentDeletedHandler.php | 32 + .../DecisionAttachmentUpdatedHandler.php | 35 + .../Document/AllDocumentsWithDrawnHandler.php | 26 + .../Document/DocumentWithDrawnHandler.php | 26 + .../Search/Index/AbstractDossierMapper.php | 49 + .../Search/Index/Covenant/CovenantMapper.php | 26 + src/Domain/Search/Index/DossierIndexer.php | 45 + src/Domain/Search/Index/ElasticDocument.php | 28 + .../Search/Index/ElasticDocumentType.php | 33 + .../Search/Index/IndexDossierHandler.php | 44 + .../Search/Index/IndexDossierMessage.php | 32 + src/Domain/Search/Index/IndexException.php | 18 + .../Index/WooDecision/DocumentMapper.php | 73 + .../Index/WooDecision/WooDecisionMapper.php | 37 + .../Result/Covenant/CovenantResultMapper.php | 50 + .../Search/Result/HighlightMapperTrait.php | 28 + src/Domain/Search/Result/MainTypeEntry.php | 38 + .../Search/Result/ResultEntryInterface.php | 15 + src/Domain/Search/Result/ResultFactory.php | 32 + .../Search/Result/SubTypeEntry.php} | 9 +- .../WooDecision/DocumentResultMapper.php | 51 + .../WooDecision/WooDecisionResultMapper.php | 51 + src/Entity/DecisionAttachment.php | 41 +- src/Entity/DecisionAttachmentType.php | 13 - src/Entity/Document.php | 67 - src/Entity/Dossier.php | 374 +- src/Entity/EntityWithId.php | 12 - src/Entity/FileInfo.php | 2 + src/Entity/IngestLog.php | 104 - src/Entity/PublicationItem.php | 2 + src/Entity/RawInventory.php | 2 + .../AuthMatrixEnsureSubscriber.php | 8 +- src/EventSubscriber/SitemapSubscriber.php | 2 +- src/EventSubscriber/UploaderSubscriber.php | 58 + src/Exception/DocumentWorkflowException.php | 27 + src/Exception/UploaderServiceException.php | 35 + src/Form/ChoiceLoader/EntityChoiceLoader.php | 87 - src/Form/DepartmentType.php | 4 +- src/Form/Document/WithdrawFormType.php | 2 +- src/Form/Dossier/AbstractDossierStepType.php | 7 +- src/Form/Dossier/Covenant/ContentFormType.php | 93 + src/Form/Dossier/Covenant/DetailsType.php | 248 + src/Form/Dossier/Covenant/DocumentType.php | 28 + src/Form/Dossier/Covenant/PublishType.php | 48 + src/Form/Dossier/DeleteFormType.php | 4 +- src/Form/Dossier/DocumentPrefixType.php | 11 +- src/Form/Dossier/SearchFormType.php | 35 +- .../{ => WooDecision}/DecisionType.php | 35 +- .../Dossier/{ => WooDecision}/DetailsType.php | 44 +- .../{ => WooDecision}/DocumentUploadType.php | 2 +- .../{ => WooDecision}/InventoryType.php | 2 +- .../Dossier/{ => WooDecision}/PublishType.php | 2 +- .../TranslatableFormErrorMapper.php | 6 +- src/Form/Elastic/ActivateIndexType.php | 2 +- src/Form/Elastic/DeleteIndexType.php | 2 +- src/Form/Elastic/RolloverParametersType.php | 3 +- src/Form/Inquiry/InquiryFilterFormType.php | 6 +- src/Form/User/ChangePasswordType.php | 14 +- src/Form/User/UserCreateFormType.php | 18 +- src/Form/User/UserInfoFormType.php | 12 +- src/Form/YearMonthType.php | 26 +- src/Message/AbstractDossierMessage.php | 4 +- src/Message/RemoveDossierMessage.php | 9 - src/Message/UpdateDossierMessage.php | 9 - src/MessageHandler/IngestDossierHandler.php | 57 - src/MessageHandler/IngestDossiersHandler.php | 4 +- src/MessageHandler/RemoveDossierHandler.php | 71 - src/MessageHandler/UpdateDossierHandler.php | 54 - src/Repository/AbstractDossierRepository.php | 43 + src/Repository/CovenantRepository.php | 86 + .../DecisionAttachmentRepository.php | 102 + src/Repository/DepartmentRepository.php | 14 + src/Repository/DocumentRepository.php | 14 +- src/Repository/DossierRepository.php | 102 +- src/Repository/IngestLogRepository.php | 43 - src/Repository/InquiryRepository.php | 22 +- src/Repository/WooDecisionRepository.php | 46 + src/Roles.php | 20 +- src/Service/DocumentService.php | 56 +- .../DocumentWorkflow/DocumentWorkflow.php | 11 - src/Service/DossierService.php | 193 +- .../DossierWizard/DossierWizardHelper.php | 147 + .../DossierWizardStatus.php} | 67 +- .../StepStatus.php | 4 +- .../DossierWizard/WizardStatusFactory.php | 72 + .../DossierWorkflow/DossierWorkflow.php | 131 - .../DossierWorkflow/Step/DecisionStep.php | 33 - .../DossierWorkflow/Step/DetailsStep.php | 34 - .../DossierWorkflow/Step/DocumentsStep.php | 37 - .../DossierWorkflow/Step/PublicationStep.php | 32 - .../DossierWorkflow/Step/StepInterface.php | 19 - .../DossierWorkflow/WorkflowStatusFactory.php | 69 - src/Service/Elastic/CollectorClient.php | 4 +- src/Service/Elastic/ElasticDocumentMapper.php | 117 - src/Service/Elastic/ElasticService.php | 33 +- src/Service/FakeDataGenerator.php | 16 +- src/Service/FileProcessService.php | 4 +- src/Service/FileUploader.php | 2 +- src/Service/FixtureService.php | 7 +- src/Service/HistoryService.php | 4 +- src/Service/Ingest/IngestLogger.php | 72 - src/Service/Ingest/IngestService.php | 5 +- .../Inventory/InventoryRunProcessor.php | 8 +- src/Service/Inventory/InventoryUpdater.php | 5 +- src/Service/Search/Model/Config.php | 5 +- src/Service/Search/Model/FacetKey.php | 4 + .../Aggregation/TypeAggregationStrategy.php | 50 + .../Condition/ContentAccessConditions.php | 78 +- .../Query/Condition/SearchTermConditions.php | 12 +- .../Query/Facet/HasFacetDefinitions.php | 30 +- ... => MainTypesAndNestedMainTypesFilter.php} | 19 +- ...OnlyFilter.php => MainTypesOnlyFilter.php} | 13 +- ...rOnlyFilter.php => SubTypesOnlyFilter.php} | 13 +- .../Search/Result/AggregationMapper.php | 4 +- src/Service/Search/Result/Dossier.php | 35 - src/Service/Search/Result/Result.php | 7 +- src/Service/Search/Result/ResultEntry.php | 17 - .../Search/Result/ResultTransformer.php | 90 +- src/Service/Security/AuthMatrixVoter.php | 37 +- .../Authorization/AuthorizationMatrix.php | 54 +- .../AuthorizationMatrixException.php | 18 + .../AuthorizationMatrixFilter.php | 12 + .../Storage/DocumentStorageService.php | 4 +- src/Service/Uploader/FilesystemStorage.php | 72 + src/Service/Uploader/UploadGroupId.php | 13 + src/Service/Uploader/UploaderNamer.php | 37 + src/Service/Uploader/UploaderService.php | 120 + .../Extractor/DecisionContentExtractor.php | 16 +- .../Extractor/DocumentContentExtractor.php | 19 +- .../Pdf/Extractor/PageContentExtractor.php | 18 +- .../Worker/Pdf/Extractor/PageExtractor.php | 10 +- .../Pdf/Extractor/PagecountExtractor.php | 16 +- .../Pdf/Extractor/ThumbnailExtractor.php | 10 +- src/Service/Worker/PdfProcessor.php | 6 - src/Twig/Components/Date.php | 13 + .../Components/Public/DownloadFileButton.php | 1 + src/Twig/Runtime/WooExtensionRuntime.php | 7 +- src/Utils.php | 23 +- src/Validator/CommonList.php | 2 +- src/Validator/NotTheSamePassword.php | 2 +- src/ViewModel/Attachment.php | 32 + src/ViewModel/Covenant.php | 22 + src/ViewModel/CovenantSearchEntry.php | 21 + src/ViewModel/Dossier.php | 32 - src/ViewModel/Factory/ApplicationMode.php | 11 + .../Factory/AttachmentViewFactory.php | 135 + src/ViewModel/Factory/CovenantViewFactory.php | 34 + src/ViewModel/Factory/DocumentViewFactory.php | 2 +- src/ViewModel/Factory/DossierViewFactory.php | 25 - src/ViewModel/Factory/GroundViewFactory.php | 33 + .../Factory/WooDecisionViewFactory.php | 63 + src/ViewModel/WooDecision.php | 54 + symfony.lock | 51 + templates/admin.html.twig | 58 +- templates/admin/departments/create.html.twig | 2 +- templates/admin/departments/edit.html.twig | 2 +- templates/admin/departments/index.html.twig | 6 +- templates/admin/document_macros.html.twig | 4 +- .../dossier/administration/details.html.twig | 2 +- .../dossier/administration/index.html.twig | 2 +- .../dossier/concept/document-list.html.twig | 5 - .../covenant/content/concept.html.twig | 23 + .../content/edit.html.twig} | 2 +- .../dossier/covenant/content/form.html.twig | 55 + .../covenant/details/concept.html.twig | 42 + .../dossier/covenant/details/edit.html.twig | 31 + .../publication-confirmation.html.twig | 35 + .../publication/concept.html.twig} | 6 +- .../publication/edit.html.twig} | 0 .../admin/dossier/covenant/view.html.twig | 208 + templates/admin/dossier/create.html.twig | 30 + .../admin/dossier/{edit => }/delete.html.twig | 6 +- .../admin/dossier/form/publish.html.twig | 1 - templates/admin/dossier/index.html.twig | 52 +- templates/admin/dossier/search.html.twig | 18 +- .../admin/dossier/snippets/filter.html.twig | 21 +- .../decision/concept.html.twig} | 6 +- .../woo-decision/decision/edit.html.twig | 13 + .../decision/form.html.twig} | 17 +- .../details/concept.html.twig} | 6 +- .../woo-decision/details/edit.html.twig | 13 + .../details/form.html.twig} | 0 .../document/details.html.twig | 6 +- .../document/replace.html.twig | 0 .../status-uploads-processing.html.twig | 0 .../status-uploads-remaining.html.twig | 0 .../document/withdraw.html.twig | 0 .../documents/concept.html.twig} | 6 +- .../documents/edit.html.twig} | 10 +- .../documents/form.html.twig} | 4 +- .../documents}/processrun.html.twig | 8 +- .../documents/replace-inventory.html.twig} | 2 +- .../publication-confirmation.html.twig | 37 + .../publication/concept.html.twig | 17 + .../publication/edit.html.twig} | 2 +- .../dossier/{ => woo-decision}/view.html.twig | 72 +- .../withdraw-all-documents.html.twig} | 2 +- .../{concept => }/workflow-styles.html.twig | 0 .../dossier/{concept => }/workflow.html.twig | 0 templates/admin/elastic/create.html.twig | 2 +- templates/admin/elastic/details.html.twig | 34 +- templates/admin/elastic/index.html.twig | 45 +- templates/admin/elastic/live.html.twig | 20 +- .../inquiry/administration/index.html.twig | 2 +- templates/admin/inquiry/index.html.twig | 16 +- templates/admin/organisation/create.html.twig | 12 +- templates/admin/organisation/edit.html.twig | 8 +- templates/admin/organisation/index.html.twig | 12 +- .../admin/static/accessibility.html.twig | 29 +- templates/admin/static/contact.html.twig | 16 +- templates/admin/static/privacy.html.twig | 2 +- templates/admin/stats/index.html.twig | 8 +- templates/admin/user/create.html.twig | 2 +- templates/admin/user/created.html.twig | 16 +- templates/admin/user/credentials.html.twig | 34 +- templates/admin/user/edit.html.twig | 44 +- templates/admin/user/index.html.twig | 16 +- templates/base.html.twig | 44 +- templates/batchdownload/batch.html.twig | 17 +- .../TwigBundle/Exception/error.html.twig | 4 +- .../TwigBundle/Exception/error404.html.twig | 4 +- .../Admin/DossierDocuments.html.twig | 8 +- .../components/Admin/DownloadFile.html.twig | 5 + templates/components/Admin/IconLink.html.twig | 2 +- .../components/Admin/InputErrors.html.twig | 36 +- templates/components/Date.html.twig | 1 + .../Public/DownloadFileButton.html.twig | 3 +- .../Public/DownloadFilesForm.html.twig | 2 +- .../components/Public/SearchForm.html.twig | 6 +- templates/covenant/attachments.html.twig | 36 + .../covenant/covenant-attachment.html.twig | 144 + .../covenant/covenant-document.html.twig | 142 + templates/covenant/details.html.twig | 33 + templates/document/details.html.twig | 34 +- templates/document/snippets/about.html.twig | 37 +- .../document/snippets/background.html.twig | 50 +- .../document/snippets/carousel.html.twig | 14 +- .../document/snippets/download.html.twig | 5 +- .../document/snippets/notifications.html.twig | 46 +- .../document/snippets/referred-by.html.twig | 4 - templates/document/snippets/viewer.html.twig | 7 +- templates/document_macros.html.twig | 52 +- .../dossier/decision-attachment.html.twig | 57 + templates/dossier/details.html.twig | 47 +- .../dossier/snippets/about-covenant.html.twig | 49 + templates/dossier/snippets/about.html.twig | 70 +- .../dossier/snippets/documents.html.twig | 12 +- .../dossier/snippets/notifications.html.twig | 4 +- templates/dossier/snippets/summary.html.twig | 6 +- templates/facet_macros.html.twig | 12 +- templates/forms/admin_form_theme.html.twig | 23 +- templates/home/index.html.twig | 2 +- templates/home/snippets/browse.html.twig | 12 +- templates/home/snippets/info.html.twig | 28 +- templates/home/snippets/intro.html.twig | 8 +- .../home/snippets/recent-documents.html.twig | 16 +- templates/inquiry/index.html.twig | 2 +- .../inquiry/snippets/documents.html.twig | 2 +- templates/inquiry/snippets/dossiers.html.twig | 8 +- templates/inquiry/snippets/info.html.twig | 12 +- .../inquiry/snippets/notifications.html.twig | 4 +- .../navigation/breadcrumbs.admin.html.twig | 2 +- templates/navigation/breadcrumbs.html.twig | 14 +- .../pagination/pagination.admin.html.twig | 6 +- templates/pagination/pagination.html.twig | 6 +- templates/search/browse-facets.html.twig | 14 +- templates/search/entries.html.twig | 55 +- templates/search/entries/covenant.html.twig | 45 + templates/search/entries/document.html.twig | 10 +- templates/search/entries/dossier.html.twig | 10 +- templates/search/facet.html.twig | 15 +- templates/search/result-failure.html.twig | 12 +- templates/search/result.html.twig | 14 +- templates/security/login.html.twig | 16 +- templates/security/login_2fa.html.twig | 18 +- templates/security/profile.html.twig | 22 +- templates/static/about.html.twig | 18 +- templates/static/accessibility.html.twig | 29 +- templates/static/contact.html.twig | 18 +- templates/static/cookies.html.twig | 39 +- templates/static/copyright.html.twig | 16 +- templates/static/privacy.html.twig | 66 +- tests/Factory/DepartmentFactory.php | 85 + tests/Factory/DocumentFactory.php | 117 + tests/Factory/FileInfoFactory.php | 72 + tests/Factory/OrganisationFactory.php | 87 + .../Covenant/CovenantAttachmentFactory.php | 93 + .../Type/Covenant/CovenantDocumentFactory.php | 95 + .../Dossier/Type/Covenant/CovenantFactory.php | 70 + .../WooDecision/DecisionAttachmentFactory.php | 95 + .../Type/WooDecision/WooDecisionFactory.php | 127 + tests/Factory/UserFactory.php | 111 + tests/Faker/FakerFactory.php | 31 + tests/Faker/GroundsFakerProvider.php | 61 + tests/Fixtures/000-inventory-001.xlsx | Bin 16502 -> 16742 bytes tests/Fixtures/001-inquiry.json | 20 - tests/Fixtures/README.md | 30 +- tests/Functional/.gitkeep | 0 .../Api/Admin/CovenantAttachmentTest.php | 709 + .../Api/Admin/CovenantDocumentTest.php | 256 + .../Api/Admin/DecisionAttachmentTest.php | 709 + .../Api/Admin/UploaderControllerTest.php | 74 + .../CovenantAttachmentRepositoryTest.php | 56 + .../CovenantDocumentRepositoryTest.php | 54 + tests/Integration/IntegrationTestTrait.php | 39 + .../Repository/CovenantRepositoryTest.php | 41 + .../DecisionAttachmentRepositoryTest.php | 62 + .../Repository/WooDecisionRepositoryTest.php | 64 + .../Services/Search/ConfigFactoryTest.php | 21 + .../WooDecision/DocumentsStepHelperTest.php | 85 + .../Ingest/Covenant/CovenantIngesterTest.php | 46 + .../Domain/Ingest/DossierIngesterTest.php | 65 + .../Ingest/IngestDossierHandlerTest.php | 62 + .../WooDecision/WooDecisionIngesterTest.php | 77 + .../AttachmentLanguageFactoryTest.php | 25 + .../Attachment/AttachmentLanguageTest.php | 78 + .../Attachment/AttachmentTypeBranchTest.php | 185 + .../Attachment/AttachmentTypeFactoryTest.php | 57 + .../Attachment/AttachmentTypeTest.php | 80 + .../Attachment/HasAttachmentsTest.php | 75 + ...nguageFactoryTest__testMakeAsArray__1.json | 12 + ...ttachmentLanguageTest__testToArray__1.json | 12 + ...ryTest__testMakeAsArrayWithExclude__1.json | 370 + ...ntTypeFactoryTest__testMakeAsArray__1.json | 375 + ...AttachmentTypeFactoryTest__testMake__1.yml | 43 + .../AttachmentTypeTest__testToArray__1.json | 287 + .../Admin/DossierListingServiceTest.php | 238 + .../Admin/DossierSearchServiceTest.php | 74 + .../Dossier/DossierDeleteHelperTest.php | 82 + .../Dossier/DossierPublisherTest.php | 86 + .../Handler/DeleteDossierHandlerTest.php | 84 + .../Dossier/Step/StepActionHelperTest.php | 256 + .../Step/StepCompletionValidatorTest.php | 52 + .../Covenant/CovenantDeleteStrategyTest.php | 56 + .../CreateCovenantDocumentHandlerTest.php | 190 + .../DeleteCovenantDocumentHandlerTest.php | 135 + .../UpdateCovenantDocumentHandlerTest.php | 200 + .../Handler/CreateCovenantHandlerTest.php | 81 + .../UpdateCovenantContentHandlerTest.php | 82 + .../UpdateCovenantDetailsHandlerTest.php | 82 + .../UpdateCovenantPublicationHandlerTest.php | 120 + .../Dossier/Type/DossierTypeManagerTest.php | 111 + .../WithDrawAllDocumentsCommandTest.php | 37 + .../Command/WithDrawDocumentCommandTest.php | 39 + .../DocumentsStepDefinitionTest.php | 46 + .../WithDrawAllDocumentsHandlerTest.php | 83 + .../Handler/WithDrawDocumentHandlerTest.php | 130 + .../PublicationStepDefinitionTest.php | 45 + .../WooDecisionDeleteStrategyTest.php | 86 + .../Workflow/DossierWorkflowManagerTest.php | 131 + .../AllDocumentsWithdrawnHandlerTest.php | 50 + .../DecisionAttachmentCreatedHandlerTest.php | 107 + .../DecisionAttachmentDeletedHandlerTest.php | 75 + .../DecisionAttachmentUpdatedHandlerTest.php | 107 + .../Handler/DocumentWithdrawnHandlerTest.php | 50 + .../Index/AbstractDossierMapperTest.php | 83 + .../Index/Covenant/CovenantMapperTest.php | 46 + .../Search/Index/DossierIndexerTest.php | 83 + .../Search/Index/IndexDossierHandlerTest.php | 75 + .../Index/WooDecision/DocumentMapperTest.php | 110 + .../WooDecision/WooDecisionMapperTest.php | 63 + .../Covenant/CovenantResultMapperTest.php | 70 + .../Search/Result/ResultFactoryTest.php | 69 + .../WooDecision/DocumentResultMapperTest.php | 76 + .../WooDecisionResultMapperTest.php | 71 + tests/Unit/Entity/DocumentTest.php | 73 - tests/Unit/Enum/DepartmentTest.php | 10 +- .../Unit/Service/BatchDownloadServiceTest.php | 10 +- tests/Unit/Service/DateRangeConverterTest.php | 9 +- tests/Unit/Service/DocumentServiceTest.php | 43 - tests/Unit/Service/DossierServiceTest.php | 258 +- .../DossierWizard/DossierWizardHelperTest.php | 223 + .../DossierWizard/DossierWizardStatusTest.php | 44 + .../Elastic/ElasticDocumentMapperTest.php | 76 - .../Encryption/EncryptionServiceTest.php | 4 +- tests/Unit/Service/FileProcessServiceTest.php | 25 +- .../Service/FileReader/ColumnMappingTest.php | 6 +- .../Unit/Service/FileReader/CsvReaderTest.php | 16 +- .../Service/FileReader/ExcelReaderTest.php | 16 +- .../Unit/Service/FileReader/HeaderMapTest.php | 6 +- .../Unit/Service/Ingest/IngestServiceTest.php | 20 +- .../Service/Inquiry/InquiryServiceTest.php | 48 +- .../Inventory/DocumentComparatorTest.php | 6 +- .../Service/Inventory/DocumentNumberTest.php | 7 +- .../Service/Inventory/DocumentUpdaterTest.php | 4 +- .../Inventory/InquiryChangesetTest.php | 2 +- .../Inventory/InventoryChangesetTest.php | 34 +- .../Inventory/InventoryDataHelperTest.php | 6 +- .../Service/Inventory/InventoryReaderTest.php | 70 +- .../Inventory/InventoryRunProcessorTest.php | 3 + .../Inventory/InventorySanitizerTest.php | 2 +- .../Inventory/InventoryServiceTest.php | 6 +- .../Unit/Service/Search/ConfigFactoryTest.php | 7 +- .../Query/Facet/Input/DateFacetInputTest.php | 30 +- .../Facet/Input/FacetInputFactoryTest.php | 9 +- .../Input/StringValuesFacetInputTest.php | 16 +- .../FacetInputFactoryTest__testCreate__1.yml | 6 +- ...utFactoryTest__testFromParameterBag__1.yml | 6 +- .../Search/Query/QueryGeneratorTest.php | 569 +- ...__testCreateQueryWithComplexConfig__1.json | 843 + ...stCreateQueryWithDossierOnlyConfig__1.json | 62 + ...__testCreateQueryWithMinimalConfig__1.json | 95 + .../Search/Result/AggregationMapperTest.php | 9 +- .../Service/Security/AuthMatrixVoterTest.php | 117 +- .../Authorization/AuthorizationMatrixTest.php | 84 +- .../AuthorizationRequestStoreTest.php | 8 +- .../Authorization/ConfigFactoryTest.php | 12 +- .../Security/Authorization/EntryTest.php | 16 +- .../Security/OrganisationSwitcherTest.php | 12 +- .../Service/Storage/DocumentStorageTest.php | 49 +- .../Service/Uploader/UploaderServiceTest.php | 422 + tests/Unit/SourceTypeTest.php | 7 +- .../Twig/Runtime/WooExtensionRuntimeTest.php | 15 +- tests/Unit/UnitTestCase.php | 33 + .../ValueObject/DossierUploadStatusTest.php | 12 +- .../ViewModel/CovenantSearchEntryTest.php | 43 + .../Factory/AttachmentViewFactoryTest.php | 190 + .../Factory/CovenantViewFactoryTest.php | 39 + .../Factory/DocumentViewFactoryTest.php | 26 + .../Factory/GroundViewFactoryTest.php | 18 + .../Factory/WooDecisionViewFactoryTest.php | 202 + ...ndViewFactoryTest__testMakeAsArray__1.json | 70 + tests/Unit/ViewModel/WooDecisionTest.php | 98 + tests/robot_framework/Dockerfile | 4 +- tests/robot_framework/E2E_ACC.robot | 479 +- tests/robot_framework/E2E_CI.robot | 786 +- tests/robot_framework/E2E_TST.robot | 85 +- tests/robot_framework/Taskfile.dist.yml | 58 +- tests/robot_framework/keywords.resource | 561 - tests/robot_framework/requirements.txt | 4 +- .../robot_framework/resources/Admin.resource | 31 + .../resources/DecisionDossiers.resource | 259 + .../resources/Generic.resource | 22 + .../resources/Inquiries.resource | 28 + .../robot_framework/resources/Public.resource | 33 + .../robot_framework/resources/Setup.resource | 88 + .../resources/UserManagement.resource | 21 + .../tests/UserManagement.robot | 133 + translations/attachment+intl-icu.nl.yaml | 73 + translations/messages+intl-icu.nl.yaml | 1147 +- translations/validators.nl.yaml | 20 +- tsconfig.json | 2 +- vitest.config.ts | 20 + webpack.config.js | 2 +- 774 files changed, 39345 insertions(+), 17572 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/daily-e2e-acc-robotrun.yml create mode 100644 .github/workflows/daily-e2e-tst-robotrun.yml create mode 100644 .github/workflows/migration-check.yml create mode 100644 .github/workflows/package.yml create mode 100644 .github/workflows/robotframeworkci.yml create mode 100644 .irealisatie create mode 100644 .vscode/settings.json create mode 100644 assets/js/admin/vue/component/Collapsible.vue delete mode 100644 assets/js/admin/vue/component/decision-attachments/AttachmentForm.vue create mode 100644 assets/js/admin/vue/component/file/upload/AlreadyUploadedFiles.vue create mode 100644 assets/js/admin/vue/component/form/Combobox.vue create mode 100644 assets/js/admin/vue/component/form/ErrorMessages.vue create mode 100644 assets/js/admin/vue/component/form/MultiCombobox.vue create mode 100644 assets/js/admin/vue/component/form/MultiSelect.vue create mode 100644 assets/js/admin/vue/component/form/RemovableSelect.vue create mode 100644 assets/js/admin/vue/component/form/SubmitValidationErrors.vue rename assets/js/admin/vue/component/{decision-attachments => publication-attachments}/AttachmentsList.vue (57%) create mode 100644 assets/js/admin/vue/component/publication-attachments/CovenantUploadForm.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/InputDocumentDate.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/InputDocumentFile.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/InputDocumentLanguages.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/InputDocumentName.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/InputDocumentTypes.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/InputGrounds.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/InputReference.vue create mode 100644 assets/js/admin/vue/component/publication-attachments/PublicationAttachmentsForm.vue rename assets/js/admin/vue/component/{decision-attachments => publication-attachments}/UploadedAttachment.vue (70%) create mode 100644 assets/js/admin/vue/component/publication-attachments/helper/document-types.ts create mode 100644 assets/js/admin/vue/component/publication-attachments/helper/index.ts create mode 100644 assets/js/admin/vue/composables/multi-input-store.ts create mode 100644 assets/js/admin/vue/controllers/ConvenantUpload.vue delete mode 100644 assets/js/admin/vue/controllers/DecisionAttachments.vue create mode 100644 assets/js/admin/vue/controllers/MultiComboboxController.vue create mode 100644 assets/js/admin/vue/controllers/PublicationAttachments.vue create mode 100644 assets/js/admin/vue/controllers/UploadAreaController.vue delete mode 100644 assets/js/admin/vue/controllers/Uploads.vue create mode 100644 assets/js/admin/vue/test/component/Alert/Alert.vue.test.ts create mode 100644 assets/js/admin/vue/test/component/Icon/Icon.vue.test.ts create mode 100644 assets/js/admin/vue/vue.d.ts create mode 100644 assets/styles/admin/components/combobox.css create mode 100644 assets/styles/admin/components/details.css create mode 100644 assets/styles/admin/components/link-list.css create mode 100644 config/packages/api_platform.yaml create mode 100644 config/packages/oneup_uploader.yaml create mode 100644 config/packages/workflow.php create mode 100644 config/packages/zenstruck_foundry.yaml create mode 100644 config/routes/api_platform.yaml create mode 100644 docs/definition-of-done.md create mode 100644 docs/dossier-types.md create mode 100644 docs/test-use-cases.md create mode 100644 docs/translations.md delete mode 100644 jest.config.ts create mode 100644 migrations/Version20240207084512.php create mode 100644 migrations/Version20240318193318.php create mode 100644 migrations/Version20240320124455.php create mode 100644 migrations/Version20240320135010.php create mode 100644 migrations/Version20240409003630.php create mode 100644 migrations/Version20240409140944.php create mode 100644 migrations/Version20240409144556.php create mode 100644 pyproject.toml create mode 100644 sonar-project.properties create mode 100644 src/Api/Admin/CovenantAttachment/CovenantAttachmentCreateDto.php create mode 100644 src/Api/Admin/CovenantAttachment/CovenantAttachmentDto.php create mode 100644 src/Api/Admin/CovenantAttachment/CovenantAttachmentProcessor.php create mode 100644 src/Api/Admin/CovenantAttachment/CovenantAttachmentProvider.php create mode 100644 src/Api/Admin/CovenantAttachment/CovenantAttachmentUpdateDto.php create mode 100644 src/Api/Admin/CovenantDocument/CovenantDocumentCreateDto.php create mode 100644 src/Api/Admin/CovenantDocument/CovenantDocumentDto.php create mode 100644 src/Api/Admin/CovenantDocument/CovenantDocumentProcessor.php create mode 100644 src/Api/Admin/CovenantDocument/CovenantDocumentProvider.php create mode 100644 src/Api/Admin/CovenantDocument/CovenantDocumentUpdateDto.php create mode 100644 src/Api/Admin/DecisionAttachment/DecisionAttachmentCreateDto.php create mode 100644 src/Api/Admin/DecisionAttachment/DecisionAttachmentDto.php create mode 100644 src/Api/Admin/DecisionAttachment/DecisionAttachmentProcessor.php create mode 100644 src/Api/Admin/DecisionAttachment/DecisionAttachmentProvider.php create mode 100644 src/Api/Admin/DecisionAttachment/DecisionAttachmentUpdateDto.php create mode 100644 src/Api/Admin/Dossier/DossierReferenceDto.php delete mode 100644 src/Command/Cron/DossierPublisher.php create mode 100644 src/Command/Cron/DossierPublisherCommand.php delete mode 100644 src/Command/Ingest/IngestDocument.php delete mode 100644 src/Command/TransConvert.php delete mode 100644 src/Command/UploadDocument.php create mode 100644 src/Controller/Admin/CustomDropzoneController.php create mode 100644 src/Controller/Admin/Dossier/Covenant/ContentStepController.php create mode 100644 src/Controller/Admin/Dossier/Covenant/DetailsStepController.php create mode 100644 src/Controller/Admin/Dossier/Covenant/DownloadController.php create mode 100644 src/Controller/Admin/Dossier/Covenant/PublicationStepController.php create mode 100644 src/Controller/Admin/Dossier/DossierActionController.php delete mode 100644 src/Controller/Admin/Dossier/DossierAuthorizationTrait.php delete mode 100644 src/Controller/Admin/Dossier/DossierConceptController.php delete mode 100644 src/Controller/Admin/Dossier/DossierEditController.php create mode 100644 src/Controller/Admin/Dossier/WooDecision/DecisionStepController.php create mode 100644 src/Controller/Admin/Dossier/WooDecision/DetailsStepController.php rename src/Controller/Admin/Dossier/{ => WooDecision}/DocumentActionController.php (75%) rename src/Controller/Admin/Dossier/{ => WooDecision}/DocumentController.php (74%) create mode 100644 src/Controller/Admin/Dossier/WooDecision/DocumentsConceptStepController.php create mode 100644 src/Controller/Admin/Dossier/WooDecision/DocumentsEditStepController.php create mode 100644 src/Controller/Admin/Dossier/WooDecision/DocumentsStepHelper.php create mode 100644 src/Controller/Admin/Dossier/WooDecision/DownloadController.php create mode 100644 src/Controller/Admin/Dossier/WooDecision/PublicationStepController.php create mode 100644 src/Controller/Admin/UploaderController.php create mode 100644 src/Controller/CovenantController.php delete mode 100644 src/Controller/LocalizedTemplateController.php rename src/Controller/{DossierController.php => WooDecisionController.php} (68%) create mode 100644 src/Domain/Ingest/Covenant/CovenantIngester.php create mode 100644 src/Domain/Ingest/DossierIngester.php create mode 100644 src/Domain/Ingest/IngestDossierHandler.php rename src/{Message => Domain/Ingest}/IngestDossierMessage.php (93%) create mode 100644 src/Domain/Ingest/IngestException.php create mode 100644 src/Domain/Ingest/WooDecision/WooDecisionIngester.php create mode 100644 src/Domain/Publication/Attachment/AbstractAttachment.php create mode 100644 src/Domain/Publication/Attachment/AttachmentExceptionInterface.php create mode 100644 src/Domain/Publication/Attachment/AttachmentLanguage.php create mode 100644 src/Domain/Publication/Attachment/AttachmentLanguageFactory.php create mode 100644 src/Domain/Publication/Attachment/AttachmentType.php create mode 100644 src/Domain/Publication/Attachment/AttachmentTypeBranch.php create mode 100644 src/Domain/Publication/Attachment/AttachmentTypeBranchException.php create mode 100644 src/Domain/Publication/Attachment/AttachmentTypeFactory.php create mode 100644 src/Domain/Publication/Attachment/EntityWithAttachments.php create mode 100644 src/Domain/Publication/Attachment/HasAttachments.php create mode 100644 src/Domain/Publication/Attachment/RuntimeAttachmentException.php create mode 100644 src/Domain/Publication/Dossier/AbstractDossier.php create mode 100644 src/Domain/Publication/Dossier/AbstractDossierRepository.php create mode 100644 src/Domain/Publication/Dossier/Admin/DossierFilterParameters.php create mode 100644 src/Domain/Publication/Dossier/Admin/DossierListingService.php create mode 100644 src/Domain/Publication/Dossier/Admin/DossierQueryConditions.php create mode 100644 src/Domain/Publication/Dossier/Admin/DossierSearchService.php create mode 100644 src/Domain/Publication/Dossier/Command/DeleteDossierCommand.php create mode 100644 src/Domain/Publication/Dossier/DossierDeleteHelper.php create mode 100644 src/Domain/Publication/Dossier/DossierFactory.php create mode 100644 src/Domain/Publication/Dossier/DossierPublisher.php rename src/{Enum/PublicationStatus.php => Domain/Publication/Dossier/DossierStatus.php} (83%) create mode 100644 src/Domain/Publication/Dossier/Event/AbstractCovenantEvent.php create mode 100644 src/Domain/Publication/Dossier/Handler/DeleteDossierHandler.php create mode 100644 src/Domain/Publication/Dossier/Step/StepActionHelper.php create mode 100644 src/Domain/Publication/Dossier/Step/StepCompletionValidator.php create mode 100644 src/Domain/Publication/Dossier/Step/StepDefinitionInterface.php create mode 100644 src/Domain/Publication/Dossier/Step/StepException.php rename src/{Service/DossierWorkflow => Domain/Publication/Dossier/Step}/StepName.php (71%) create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/AbstractCovenantCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/CreateCovenantAttachmentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/CreateCovenantCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/CreateCovenantDocumentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/DeleteCovenantAttachmentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/DeleteCovenantDocumentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/UpdateCovenantAttachmentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/UpdateCovenantContentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/UpdateCovenantDetailsCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/UpdateCovenantDocumentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Command/UpdateCovenantPublicationCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Covenant.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/CovenantAttachment.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/CovenantAttachmentRepository.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/CovenantConfig.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/CovenantDeleteStrategy.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/CovenantDocument.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/CovenantDocumentRepository.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/CovenantWorkflow.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Event/CovenantAttachmentDeletedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Event/CovenantAttachmentUpdatedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Event/CovenantCreatedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Event/CovenantDocumentDeletedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Event/CovenantDocumentUpdatedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Event/CovenantUpdatedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantAttachment/CovenantAttachmentNotFoundException.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantAttachment/CreateCovenantAttachmentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantAttachment/DeleteCovenantAttachmentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantAttachment/UpdateCovenantAttachmentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/CovenantDocumentAlreadyExistsException.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/CovenantDocumentNotFoundException.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/CreateCovenantDocumentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/DeleteCovenantDocumentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/UpdateCovenantDocumentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/CreateCovenantHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/UpdateCovenantContentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/UpdateCovenantDetailsHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Handler/UpdateCovenantPublicationHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Steps/ContentStepDefinition.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Steps/DetailsStepDefinition.php create mode 100644 src/Domain/Publication/Dossier/Type/Covenant/Steps/PublicationStepDefinition.php create mode 100644 src/Domain/Publication/Dossier/Type/DossierDeleteStrategyInterface.php create mode 100644 src/Domain/Publication/Dossier/Type/DossierType.php create mode 100644 src/Domain/Publication/Dossier/Type/DossierTypeConfigInterface.php create mode 100644 src/Domain/Publication/Dossier/Type/DossierTypeException.php create mode 100644 src/Domain/Publication/Dossier/Type/DossierTypeManager.php create mode 100644 src/Domain/Publication/Dossier/Type/DossierTypeWithPreview.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Command/CreateDecisionAttachmentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Command/DeleteDecisionAttachmentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Command/UpdateDecisionAttachmentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Command/WithDrawAllDocumentsCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Command/WithDrawDocumentCommand.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Event/AllDocumentsWithDrawnEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Event/DecisionAttachmentCreatedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Event/DecisionAttachmentDeletedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Event/DecisionAttachmentUpdatedEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Event/DocumentWithDrawnEvent.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Handler/CreateDecisionAttachmentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Handler/DecisionAttachmentNotFoundException.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Handler/DeleteDecisionAttachmentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Handler/UpdateDecisionAttachmentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Handler/WithDrawAllDocumentsHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Handler/WithDrawDocumentHandler.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Steps/DecisionStepDefinition.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Steps/DetailsStepDefinition.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Steps/DocumentsStepDefinition.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/Steps/PublicationStepDefinition.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/WooDecision.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/WooDecisionConfig.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/WooDecisionDeleteStrategy.php create mode 100644 src/Domain/Publication/Dossier/Type/WooDecision/WooDecisionWorkflow.php create mode 100644 src/Domain/Publication/Dossier/Type/WorkflowConfigHelper.php create mode 100644 src/Domain/Publication/Dossier/Workflow/DossierMarkingStore.php create mode 100644 src/Domain/Publication/Dossier/Workflow/DossierStatusTransition.php create mode 100644 src/Domain/Publication/Dossier/Workflow/DossierWorkflowException.php create mode 100644 src/Domain/Publication/Dossier/Workflow/DossierWorkflowManager.php create mode 100644 src/Domain/Publication/Dossier/Workflow/Guard/PublishAsPreviewGuard.php create mode 100644 src/Domain/Publication/Dossier/Workflow/Guard/PublishGuard.php create mode 100644 src/Domain/Publication/Dossier/Workflow/Guard/ScheduleGuard.php create mode 100644 src/Domain/Publication/History/Handler/DecisionAttachment/DecisionAttachmentCreatedHandler.php create mode 100644 src/Domain/Publication/History/Handler/DecisionAttachment/DecisionAttachmentDeletedHandler.php create mode 100644 src/Domain/Publication/History/Handler/DecisionAttachment/DecisionAttachmentUpdatedHandler.php create mode 100644 src/Domain/Publication/History/Handler/Document/AllDocumentsWithDrawnHandler.php create mode 100644 src/Domain/Publication/History/Handler/Document/DocumentWithDrawnHandler.php create mode 100644 src/Domain/Search/Index/AbstractDossierMapper.php create mode 100644 src/Domain/Search/Index/Covenant/CovenantMapper.php create mode 100644 src/Domain/Search/Index/DossierIndexer.php create mode 100644 src/Domain/Search/Index/ElasticDocument.php create mode 100644 src/Domain/Search/Index/ElasticDocumentType.php create mode 100644 src/Domain/Search/Index/IndexDossierHandler.php create mode 100644 src/Domain/Search/Index/IndexDossierMessage.php create mode 100644 src/Domain/Search/Index/IndexException.php create mode 100644 src/Domain/Search/Index/WooDecision/DocumentMapper.php create mode 100644 src/Domain/Search/Index/WooDecision/WooDecisionMapper.php create mode 100644 src/Domain/Search/Result/Covenant/CovenantResultMapper.php create mode 100644 src/Domain/Search/Result/HighlightMapperTrait.php create mode 100644 src/Domain/Search/Result/MainTypeEntry.php create mode 100644 src/Domain/Search/Result/ResultEntryInterface.php create mode 100644 src/Domain/Search/Result/ResultFactory.php rename src/{Service/Search/Result/Document.php => Domain/Search/Result/SubTypeEntry.php} (75%) create mode 100644 src/Domain/Search/Result/WooDecision/DocumentResultMapper.php create mode 100644 src/Domain/Search/Result/WooDecision/WooDecisionResultMapper.php delete mode 100644 src/Entity/DecisionAttachmentType.php delete mode 100644 src/Entity/EntityWithId.php delete mode 100644 src/Entity/IngestLog.php create mode 100644 src/EventSubscriber/UploaderSubscriber.php create mode 100644 src/Exception/DocumentWorkflowException.php create mode 100644 src/Exception/UploaderServiceException.php delete mode 100644 src/Form/ChoiceLoader/EntityChoiceLoader.php create mode 100644 src/Form/Dossier/Covenant/ContentFormType.php create mode 100644 src/Form/Dossier/Covenant/DetailsType.php create mode 100644 src/Form/Dossier/Covenant/DocumentType.php create mode 100644 src/Form/Dossier/Covenant/PublishType.php rename src/Form/Dossier/{ => WooDecision}/DecisionType.php (85%) rename src/Form/Dossier/{ => WooDecision}/DetailsType.php (87%) rename src/Form/Dossier/{ => WooDecision}/DocumentUploadType.php (97%) rename src/Form/Dossier/{ => WooDecision}/InventoryType.php (97%) rename src/Form/Dossier/{ => WooDecision}/PublishType.php (98%) rename src/Form/Dossier/{ => WooDecision}/TranslatableFormErrorMapper.php (94%) delete mode 100644 src/Message/RemoveDossierMessage.php delete mode 100644 src/Message/UpdateDossierMessage.php delete mode 100644 src/MessageHandler/IngestDossierHandler.php delete mode 100644 src/MessageHandler/RemoveDossierHandler.php delete mode 100644 src/MessageHandler/UpdateDossierHandler.php create mode 100644 src/Repository/AbstractDossierRepository.php create mode 100644 src/Repository/CovenantRepository.php create mode 100644 src/Repository/DecisionAttachmentRepository.php delete mode 100644 src/Repository/IngestLogRepository.php create mode 100644 src/Repository/WooDecisionRepository.php create mode 100644 src/Service/DossierWizard/DossierWizardHelper.php rename src/Service/{DossierWorkflow/DossierWorkflowStatus.php => DossierWizard/DossierWizardStatus.php} (60%) rename src/Service/{DossierWorkflow => DossierWizard}/StepStatus.php (92%) create mode 100644 src/Service/DossierWizard/WizardStatusFactory.php delete mode 100644 src/Service/DossierWorkflow/DossierWorkflow.php delete mode 100644 src/Service/DossierWorkflow/Step/DecisionStep.php delete mode 100644 src/Service/DossierWorkflow/Step/DetailsStep.php delete mode 100644 src/Service/DossierWorkflow/Step/DocumentsStep.php delete mode 100644 src/Service/DossierWorkflow/Step/PublicationStep.php delete mode 100644 src/Service/DossierWorkflow/Step/StepInterface.php delete mode 100644 src/Service/DossierWorkflow/WorkflowStatusFactory.php delete mode 100644 src/Service/Elastic/ElasticDocumentMapper.php delete mode 100644 src/Service/Ingest/IngestLogger.php create mode 100644 src/Service/Search/Query/Aggregation/TypeAggregationStrategy.php rename src/Service/Search/Query/Filter/{DossierAndNestedDossierFilter.php => MainTypesAndNestedMainTypesFilter.php} (68%) rename src/Service/Search/Query/Filter/{DocumentOnlyFilter.php => MainTypesOnlyFilter.php} (58%) rename src/Service/Search/Query/Filter/{DossierOnlyFilter.php => SubTypesOnlyFilter.php} (63%) delete mode 100644 src/Service/Search/Result/Dossier.php delete mode 100644 src/Service/Search/Result/ResultEntry.php create mode 100644 src/Service/Security/Authorization/AuthorizationMatrixException.php create mode 100644 src/Service/Security/Authorization/AuthorizationMatrixFilter.php create mode 100644 src/Service/Uploader/FilesystemStorage.php create mode 100644 src/Service/Uploader/UploadGroupId.php create mode 100644 src/Service/Uploader/UploaderNamer.php create mode 100644 src/Service/Uploader/UploaderService.php create mode 100644 src/Twig/Components/Date.php create mode 100644 src/ViewModel/Attachment.php create mode 100644 src/ViewModel/Covenant.php create mode 100644 src/ViewModel/CovenantSearchEntry.php delete mode 100644 src/ViewModel/Dossier.php create mode 100644 src/ViewModel/Factory/ApplicationMode.php create mode 100644 src/ViewModel/Factory/AttachmentViewFactory.php create mode 100644 src/ViewModel/Factory/CovenantViewFactory.php delete mode 100644 src/ViewModel/Factory/DossierViewFactory.php create mode 100644 src/ViewModel/Factory/GroundViewFactory.php create mode 100644 src/ViewModel/Factory/WooDecisionViewFactory.php create mode 100644 src/ViewModel/WooDecision.php delete mode 100644 templates/admin/dossier/concept/document-list.html.twig create mode 100644 templates/admin/dossier/covenant/content/concept.html.twig rename templates/admin/dossier/{edit/decision.html.twig => covenant/content/edit.html.twig} (80%) create mode 100644 templates/admin/dossier/covenant/content/form.html.twig create mode 100644 templates/admin/dossier/covenant/details/concept.html.twig create mode 100644 templates/admin/dossier/covenant/details/edit.html.twig create mode 100644 templates/admin/dossier/covenant/publication-confirmation.html.twig rename templates/admin/dossier/{concept/publish.html.twig => covenant/publication/concept.html.twig} (59%) rename templates/admin/dossier/{edit/withdraw-all-documents.html.twig => covenant/publication/edit.html.twig} (100%) create mode 100644 templates/admin/dossier/covenant/view.html.twig create mode 100644 templates/admin/dossier/create.html.twig rename templates/admin/dossier/{edit => }/delete.html.twig (59%) delete mode 100644 templates/admin/dossier/form/publish.html.twig rename templates/admin/dossier/{concept/decision.html.twig => woo-decision/decision/concept.html.twig} (59%) create mode 100644 templates/admin/dossier/woo-decision/decision/edit.html.twig rename templates/admin/dossier/{form/decision.html.twig => woo-decision/decision/form.html.twig} (75%) rename templates/admin/dossier/{concept/details.html.twig => woo-decision/details/concept.html.twig} (70%) create mode 100644 templates/admin/dossier/woo-decision/details/edit.html.twig rename templates/admin/dossier/{form/details.html.twig => woo-decision/details/form.html.twig} (100%) rename templates/admin/dossier/{ => woo-decision}/document/details.html.twig (90%) rename templates/admin/dossier/{ => woo-decision}/document/replace.html.twig (100%) rename templates/admin/dossier/{ => woo-decision}/document/status-uploads-processing.html.twig (100%) rename templates/admin/dossier/{ => woo-decision}/document/status-uploads-remaining.html.twig (100%) rename templates/admin/dossier/{ => woo-decision}/document/withdraw.html.twig (100%) rename templates/admin/dossier/{concept/documents.html.twig => woo-decision/documents/concept.html.twig} (69%) rename templates/admin/dossier/{edit/documents.html.twig => woo-decision/documents/edit.html.twig} (88%) rename templates/admin/dossier/{form/documents.html.twig => woo-decision/documents/form.html.twig} (89%) rename templates/admin/dossier/{form => woo-decision/documents}/processrun.html.twig (86%) rename templates/admin/dossier/{edit/inventory.html.twig => woo-decision/documents/replace-inventory.html.twig} (81%) create mode 100644 templates/admin/dossier/woo-decision/publication-confirmation.html.twig create mode 100644 templates/admin/dossier/woo-decision/publication/concept.html.twig rename templates/admin/dossier/{edit/details.html.twig => woo-decision/publication/edit.html.twig} (82%) rename templates/admin/dossier/{ => woo-decision}/view.html.twig (80%) rename templates/admin/dossier/{edit/publication.html.twig => woo-decision/withdraw-all-documents.html.twig} (82%) rename templates/admin/dossier/{concept => }/workflow-styles.html.twig (100%) rename templates/admin/dossier/{concept => }/workflow.html.twig (100%) create mode 100644 templates/components/Admin/DownloadFile.html.twig create mode 100644 templates/components/Date.html.twig create mode 100644 templates/covenant/attachments.html.twig create mode 100644 templates/covenant/covenant-attachment.html.twig create mode 100644 templates/covenant/covenant-document.html.twig create mode 100644 templates/covenant/details.html.twig delete mode 100644 templates/document/snippets/referred-by.html.twig create mode 100644 templates/dossier/decision-attachment.html.twig create mode 100644 templates/dossier/snippets/about-covenant.html.twig create mode 100644 templates/search/entries/covenant.html.twig create mode 100644 tests/Factory/DepartmentFactory.php create mode 100644 tests/Factory/DocumentFactory.php create mode 100644 tests/Factory/FileInfoFactory.php create mode 100644 tests/Factory/OrganisationFactory.php create mode 100644 tests/Factory/Publication/Dossier/Type/Covenant/CovenantAttachmentFactory.php create mode 100644 tests/Factory/Publication/Dossier/Type/Covenant/CovenantDocumentFactory.php create mode 100644 tests/Factory/Publication/Dossier/Type/Covenant/CovenantFactory.php create mode 100644 tests/Factory/Publication/Dossier/Type/WooDecision/DecisionAttachmentFactory.php create mode 100644 tests/Factory/Publication/Dossier/Type/WooDecision/WooDecisionFactory.php create mode 100644 tests/Factory/UserFactory.php create mode 100644 tests/Faker/FakerFactory.php create mode 100644 tests/Faker/GroundsFakerProvider.php delete mode 100644 tests/Functional/.gitkeep create mode 100644 tests/Integration/Api/Admin/CovenantAttachmentTest.php create mode 100644 tests/Integration/Api/Admin/CovenantDocumentTest.php create mode 100644 tests/Integration/Api/Admin/DecisionAttachmentTest.php create mode 100644 tests/Integration/Api/Admin/UploaderControllerTest.php create mode 100644 tests/Integration/Domain/Publication/Dossier/Type/Covenant/CovenantAttachmentRepositoryTest.php create mode 100644 tests/Integration/Domain/Publication/Dossier/Type/Covenant/CovenantDocumentRepositoryTest.php create mode 100644 tests/Integration/IntegrationTestTrait.php create mode 100644 tests/Integration/Repository/CovenantRepositoryTest.php create mode 100644 tests/Integration/Repository/DecisionAttachmentRepositoryTest.php create mode 100644 tests/Integration/Repository/WooDecisionRepositoryTest.php create mode 100644 tests/Integration/Services/Search/ConfigFactoryTest.php create mode 100644 tests/Unit/Controller/Admin/Dossier/WooDecision/DocumentsStepHelperTest.php create mode 100644 tests/Unit/Domain/Ingest/Covenant/CovenantIngesterTest.php create mode 100644 tests/Unit/Domain/Ingest/DossierIngesterTest.php create mode 100644 tests/Unit/Domain/Ingest/IngestDossierHandlerTest.php create mode 100644 tests/Unit/Domain/Ingest/WooDecision/WooDecisionIngesterTest.php create mode 100644 tests/Unit/Domain/Publication/Attachment/AttachmentLanguageFactoryTest.php create mode 100644 tests/Unit/Domain/Publication/Attachment/AttachmentLanguageTest.php create mode 100644 tests/Unit/Domain/Publication/Attachment/AttachmentTypeBranchTest.php create mode 100644 tests/Unit/Domain/Publication/Attachment/AttachmentTypeFactoryTest.php create mode 100644 tests/Unit/Domain/Publication/Attachment/AttachmentTypeTest.php create mode 100644 tests/Unit/Domain/Publication/Attachment/HasAttachmentsTest.php create mode 100644 tests/Unit/Domain/Publication/Attachment/__snapshots__/AttachmentLanguageFactoryTest__testMakeAsArray__1.json create mode 100644 tests/Unit/Domain/Publication/Attachment/__snapshots__/AttachmentLanguageTest__testToArray__1.json create mode 100644 tests/Unit/Domain/Publication/Attachment/__snapshots__/AttachmentTypeFactoryTest__testMakeAsArrayWithExclude__1.json create mode 100644 tests/Unit/Domain/Publication/Attachment/__snapshots__/AttachmentTypeFactoryTest__testMakeAsArray__1.json create mode 100644 tests/Unit/Domain/Publication/Attachment/__snapshots__/AttachmentTypeFactoryTest__testMake__1.yml create mode 100644 tests/Unit/Domain/Publication/Attachment/__snapshots__/AttachmentTypeTest__testToArray__1.json create mode 100644 tests/Unit/Domain/Publication/Dossier/Admin/DossierListingServiceTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Admin/DossierSearchServiceTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/DossierDeleteHelperTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/DossierPublisherTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Handler/DeleteDossierHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Step/StepActionHelperTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Step/StepCompletionValidatorTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/CovenantDeleteStrategyTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/CreateCovenantDocumentHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/DeleteCovenantDocumentHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/Handler/CovenantDocument/UpdateCovenantDocumentHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/Handler/CreateCovenantHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/Handler/UpdateCovenantContentHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/Handler/UpdateCovenantDetailsHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/Covenant/Handler/UpdateCovenantPublicationHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/DossierTypeManagerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/WooDecision/Command/WithDrawAllDocumentsCommandTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/WooDecision/Command/WithDrawDocumentCommandTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/WooDecision/DocumentsStepDefinitionTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/WooDecision/Handler/WithDrawAllDocumentsHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/WooDecision/Handler/WithDrawDocumentHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/WooDecision/PublicationStepDefinitionTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Type/WooDecision/WooDecisionDeleteStrategyTest.php create mode 100644 tests/Unit/Domain/Publication/Dossier/Workflow/DossierWorkflowManagerTest.php create mode 100644 tests/Unit/Domain/Publication/History/Handler/AllDocumentsWithdrawnHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/History/Handler/DecisionAttachmentCreatedHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/History/Handler/DecisionAttachmentDeletedHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/History/Handler/DecisionAttachmentUpdatedHandlerTest.php create mode 100644 tests/Unit/Domain/Publication/History/Handler/DocumentWithdrawnHandlerTest.php create mode 100644 tests/Unit/Domain/Search/Index/AbstractDossierMapperTest.php create mode 100644 tests/Unit/Domain/Search/Index/Covenant/CovenantMapperTest.php create mode 100644 tests/Unit/Domain/Search/Index/DossierIndexerTest.php create mode 100644 tests/Unit/Domain/Search/Index/IndexDossierHandlerTest.php create mode 100644 tests/Unit/Domain/Search/Index/WooDecision/DocumentMapperTest.php create mode 100644 tests/Unit/Domain/Search/Index/WooDecision/WooDecisionMapperTest.php create mode 100644 tests/Unit/Domain/Search/Result/Covenant/CovenantResultMapperTest.php create mode 100644 tests/Unit/Domain/Search/Result/ResultFactoryTest.php create mode 100644 tests/Unit/Domain/Search/Result/WooDecision/DocumentResultMapperTest.php create mode 100644 tests/Unit/Domain/Search/Result/WooDecision/WooDecisionResultMapperTest.php delete mode 100644 tests/Unit/Entity/DocumentTest.php create mode 100644 tests/Unit/Service/DossierWizard/DossierWizardHelperTest.php create mode 100644 tests/Unit/Service/DossierWizard/DossierWizardStatusTest.php delete mode 100644 tests/Unit/Service/Elastic/ElasticDocumentMapperTest.php create mode 100644 tests/Unit/Service/Search/Query/__snapshots__/QueryGeneratorTest__testCreateQueryWithComplexConfig__1.json create mode 100644 tests/Unit/Service/Search/Query/__snapshots__/QueryGeneratorTest__testCreateQueryWithDossierOnlyConfig__1.json create mode 100644 tests/Unit/Service/Search/Query/__snapshots__/QueryGeneratorTest__testCreateQueryWithMinimalConfig__1.json create mode 100644 tests/Unit/Service/Uploader/UploaderServiceTest.php create mode 100644 tests/Unit/ViewModel/CovenantSearchEntryTest.php create mode 100644 tests/Unit/ViewModel/Factory/AttachmentViewFactoryTest.php create mode 100644 tests/Unit/ViewModel/Factory/CovenantViewFactoryTest.php create mode 100644 tests/Unit/ViewModel/Factory/DocumentViewFactoryTest.php create mode 100644 tests/Unit/ViewModel/Factory/GroundViewFactoryTest.php create mode 100644 tests/Unit/ViewModel/Factory/WooDecisionViewFactoryTest.php create mode 100644 tests/Unit/ViewModel/Factory/__snapshots__/GroundViewFactoryTest__testMakeAsArray__1.json create mode 100644 tests/Unit/ViewModel/WooDecisionTest.php delete mode 100644 tests/robot_framework/keywords.resource create mode 100644 tests/robot_framework/resources/Admin.resource create mode 100644 tests/robot_framework/resources/DecisionDossiers.resource create mode 100644 tests/robot_framework/resources/Generic.resource create mode 100644 tests/robot_framework/resources/Inquiries.resource create mode 100644 tests/robot_framework/resources/Public.resource create mode 100644 tests/robot_framework/resources/Setup.resource create mode 100644 tests/robot_framework/resources/UserManagement.resource create mode 100644 tests/robot_framework/tests/UserManagement.robot create mode 100644 translations/attachment+intl-icu.nl.yaml create mode 100644 vitest.config.ts diff --git a/.db_requirements b/.db_requirements index 3535fd644..b0e0c6b57 100644 --- a/.db_requirements +++ b/.db_requirements @@ -1 +1 @@ -v0.1.33 +v0.1.37 diff --git a/.env b/.env index b21dbfe6a..9c1ee3e76 100644 --- a/.env +++ b/.env @@ -3,6 +3,7 @@ # ----------------------------------------------------- ###> symfony/framework-bundle ### APP_ENV=dev +APP_SECRET=32f3c49be690d4c5f499093ae7dd3a7d ###< symfony/framework-bundle ### APP_DEBUG=true @@ -12,6 +13,7 @@ APP_DEBUG=true # ----------------------------------------------------- # Unique secret for creating signatures (rememberme, CSRF etc) +APP_SECRET=32f3c49be690d4c5f499093ae7dd3a7d # Database at-rest encryption key (generated with "php bin/console generate:database-key") DATABASE_ENCRYPTION_KEY= @@ -120,3 +122,5 @@ AUDITLOG_RABBITMQ_ROUTING_KEY=auditlog AUDITLOG_FILE_ENCRYPTED=false AUDITLOG_FILE_LOG_PII=false AUDITLOG_FILE_PATH=%kernel.logs_dir%/audit.log + +HAS_FEATURE_VERWERKINGSREGISTER_LINK=false diff --git a/.env.ci b/.env.ci index be9e7664b..f21f9e89e 100644 --- a/.env.ci +++ b/.env.ci @@ -1,53 +1,22 @@ # This env file is used for CI testing. -APP_ENV=dev +# define your env variables for the test env here +KERNEL_CLASS='App\Kernel' APP_SECRET=32f3c49be690d4c5f499093ae7dd3a7d - -SITE_NAME=open.minvws.nl +SYMFONY_DEPRECATIONS_HELPER=999999 +PANTHER_APP_ENV=panther +PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots DATABASE_URL="postgresql://postgres:postgres@localhost:5432/postgres?serverVersion=14&charset=utf8" -HIGH_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/high -INGESTOR_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/ingestor -ESUPDATER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/es_updates -GLOBAL_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/global - -ELASTICSEARCH_HOST=http://localhost:9200 -ELASTICSEARCH_USER= -ELASTICSEARCH_PASS= -ELASTICSEARCH_MTLS_CERT_PATH= -ELASTICSEARCH_MTLS_KEY_PATH= -ELASTICSEARCH_MTLS_CA_PATH= - -TIKA_HOST=http://localhost:9998 - -REDIS_URL=redis://localhost:6379 -REDIS_TLS_CAFILE= -REDIS_TLS_LOCAL_CERT= -REDIS_TLS_LOCAL_PK= - -COOKIE_NAME=WOOPID - -TOTP_ISSUER=localhost - -APP_MODE=BOTH -PUBLIC_BASE_URL=http://localhost:8000 - - -STORAGE_DOCUMENT_ADAPTER=local -STORAGE_THUMBNAIL_ADAPTER=local -STORAGE_BATCH_ADAPTER=local - -PIWIK_ANALYTICS_ID=0 +HIGH_TRANSPORT_DSN=in-memory:// +INGESTOR_TRANSPORT_DSN=in-memory:// +ESUPDATER_TRANSPORT_DSN=in-memory:// +GLOBAL_TRANSPORT_DSN=in-memory:// -#------------------------------------------------------ -# audit logger variables -AUDITLOG_ENCRYPTION_PUB_KEY= -AUDITLOG_ENCRYPTION_PRIV_KEY= +RABBITMQ_URL=amqp://guest:guest@localhost:5672 -AUDITLOG_PSR_ENCRYPTED=false -AUDITLOG_DOCTRINE_ENCRYPTED=false -AUDITLOG_RABBITMQ_ENCRYPTED=false -AUDITLOG_FILE_ENCRYPTED=false -AUDITLOG_FILE_PATH=%kernel.logs_dir%/audit.log +# The key to encrypt fields in the database. Generate with "bin/console generate:database-key" +DATABASE_ENCRYPTION_KEY=314005005c42fb6849aa5d7ca12faba81643c03e71e3a590e1436a882e9fff8135237d39d99652bc7f35a39c87bd370fa4745276126b145b3d2e34f2c3ea105d424893ae82f92347393860d4fa9836fdb1933525e7de765a379bed5777402bc10cc6be46 +# SYMFONY_DEPRECATIONS_HELPER="disabled=1" diff --git a/.env.test b/.env.test index 9e7162f0b..db383d25e 100644 --- a/.env.test +++ b/.env.test @@ -1,6 +1,20 @@ # define your env variables for the test env here KERNEL_CLASS='App\Kernel' -APP_SECRET='$ecretf0rt3st' +APP_SECRET=32f3c49be690d4c5f499093ae7dd3a7d SYMFONY_DEPRECATIONS_HELPER=999999 PANTHER_APP_ENV=panther PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots + +DATABASE_URL="postgresql://postgres:postgres@postgres:5432/postgres?serverVersion=14&charset=utf8" + +HIGH_TRANSPORT_DSN=in-memory:// +INGESTOR_TRANSPORT_DSN=in-memory:// +ESUPDATER_TRANSPORT_DSN=in-memory:// +GLOBAL_TRANSPORT_DSN=in-memory:// + +RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672 + +# The key to encrypt fields in the database. Generate with "bin/console generate:database-key" +DATABASE_ENCRYPTION_KEY=314005005c42fb6849aa5d7ca12faba81643c03e71e3a590e1436a882e9fff8135237d39d99652bc7f35a39c87bd370fa4745276126b145b3d2e34f2c3ea105d424893ae82f92347393860d4fa9836fdb1933525e7de765a379bed5777402bc10cc6be46 +# SYMFONY_DEPRECATIONS_HELPER="disabled=1" + diff --git a/.eslintrc.js b/.eslintrc.js index ca8759674..8129535ca 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -31,6 +31,7 @@ module.exports = { '@typescript-eslint/lines-between-class-members': 'off', '@typescript-eslint/no-use-before-define': 'off', 'class-methods-use-this': 'off', + 'import/no-extraneous-dependencies': 'off', 'import/extensions': [ 'error', 'never', @@ -64,7 +65,7 @@ module.exports = { '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-var-requires': 'off', 'global-require': 'off', - 'import/no-extraneous-dependencies': 'off', + 'import/extensions': 'off', }, }, ], diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..c029b51f4 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,3 @@ +* @minvws/rdo-woo-codeowners + +/tests/robot_framework @minvws/rdo-robotframework-codeowners diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..116606f41 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..f9bfe1f46 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,124 @@ +name: Continuous Integration + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + +env: + NODE_VERSION: 18 + PHP_VERSION: 8.2 + +jobs: + validate: + name: 'Build & validate' + runs-on: 'ubuntu-22.04' + services: + postgres: + image: postgres:14.10-bookworm + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres_test + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + rabbitmq: + image: rabbitmq:3 + ports: + - 5672:5672 + options: --health-cmd "rabbitmqctl node_health_check" --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: 'npm' + registry-url: 'https://npm.pkg.github.com' + - name: Install npm dependencies + run: | + echo "//npm.pkg.github.com/:_authToken=$NODE_AUTH_TOKEN" >> ~/.npmrc + npm ci --ignore-scripts + env: + NODE_AUTH_TOKEN: ${{ secrets.REPO_READ_ONLY_TOKEN }} + - name: 'Linting: javascript' + if: always() + run: | + npm run jslint + sed -i 's@'$GITHUB_WORKSPACE'@/github/workspace@g' reports/eslint.json + - name: 'Linting: Markdown' + uses: DavidAnson/markdownlint-cli2-action@v16 + if: always() + with: + globs: | + **/*.md + !node_modules + !vendor + - name: 'Linting: REUSE' + uses: fsfe/reuse-action@v3 + if: always() + - name: 'Unit tests: front-end' + if: always() + run: npm test + - name: Install PHP + uses: shivammathur/setup-php@master + if: always() + with: + php-version: ${{ env.PHP_VERSION }} + extensions: zip, pgsql, pcov + - name: 'Composer install' + if: always() + env: + COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.REPO_READ_ONLY_TOKEN }}"}}' + run: composer install --no-interaction --no-scripts --no-progress --prefer-dist --no-ansi + - name: Build npm + if: always() + run: npm run build + - name: 'Linting: PHP CodeSniffer' + if: always() + run: vendor/bin/phpcs + - name: 'Linting: PHP CS Fixer' + if: always() + run: vendor/bin/php-cs-fixer fix --dry-run --diff --verbose + - name: 'Linting: PHPmd' + if: always() + run: vendor/bin/phpmd src/ text ruleset.phpmd.xml + - name: Copy .env.ci to .env.local + if: always() + run: cp .env.ci .env.test.local + - name: Clear and warmup cache + if: always() + id: cache_warmup + env: + APP_ENV: prod + APP_DEBUG: false + run: | + bin/console cache:clear + bin/console cache:warmup + - name: 'Linting: Twig' + if: success() || steps.cache_warmup.conclusion == 'success' + run: bin/console lint:twig templates + - name: 'Linting: Translations' + if: success() || steps.cache_warmup.conclusion == 'success' + run: bin/console lint:yaml translations + - name: 'Static Code Analysis: PHPStan' + if: success() || steps.cache_warmup.conclusion == 'success' + run: vendor/bin/phpstan analyse --error-format=json > reports/phpstan.json + - name: Migrate Test DB + if: always() + run: bin/console doctrine:schema:create --no-interaction --env=test + - name: 'Unit tests: PHP' + if: always() + run: php -dpcov.enabled=1 -dpcov.directory=. bin/phpunit -d --without-creating-snapshots --log-junit=reports/report-phpunit.xml --coverage-clover=reports/coverage-phpunit.xml + - name: 'Static Code Analysis: SonarCloud' + if: always() + uses: SonarSource/sonarcloud-github-action@master + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/daily-e2e-acc-robotrun.yml b/.github/workflows/daily-e2e-acc-robotrun.yml new file mode 100644 index 000000000..dafc9f5b4 --- /dev/null +++ b/.github/workflows/daily-e2e-acc-robotrun.yml @@ -0,0 +1,38 @@ +name: E2E Tests - Acceptance +on: + schedule: + - cron: '0 0 * * *' # This cron schedule runs the workflow every day at midnight UTC + workflow_dispatch: + +jobs: + e2e-robot-tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Install python dependencies + run: | + python -m pip install --upgrade pip + pip install -r tests/robot_framework/requirements.txt --use-deprecated=legacy-resolver + rfbrowser init + - name: Execute Robot Framework tests + env: + OTP_SECRET_WOO: ${{ secrets.OTP_SECRET_WOO }} + USERNAME_WOO_STAGING: ${{ secrets.USERNAME_WOO_STAGING }} + PASSWORD_WOO_STAGING: ${{ secrets.PASSWORD_WOO_STAGING }} + run: | + python -m robot -d tests/robot_framework/results -x outputxunit.xml -i E2E_ACC -e LOGS -v headless:true tests/robot_framework + - name: Upload test results + uses: actions/upload-artifact@v4 + if: always() + with: + name: reports + path: tests/robot_framework/results + - name: Publish test results + uses: minvws/nl-rdo-github-action-robotframework-test-summary@v0.2.0 + if: always() + with: + output_file: 'tests/robot_framework/results/output.xml' + endpoints: 'https://web.acc.woo.rdobeheer.nl' + username: '${{ secrets.USERNAME_WOO_STAGING }}' + password: '${{ secrets.PASSWORD_WOO_STAGING }}' diff --git a/.github/workflows/daily-e2e-tst-robotrun.yml b/.github/workflows/daily-e2e-tst-robotrun.yml new file mode 100644 index 000000000..7488dbf32 --- /dev/null +++ b/.github/workflows/daily-e2e-tst-robotrun.yml @@ -0,0 +1,41 @@ +name: E2E Tests - Test +on: + schedule: + - cron: '0 0 * * *' # This cron schedule runs the workflow every day at midnight UTC + workflow_dispatch: + +jobs: + e2e-robot-tests: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Install python dependencies + run: | + python -m pip install --upgrade pip + pip install -r tests/robot_framework/requirements.txt --use-deprecated=legacy-resolver + rfbrowser init + - name: Execute Robot Framework tests + env: + OTP_SECRET_WOO: ${{ secrets.OTP_SECRET_WOO }} + USERNAME_WOO_TEST: ${{ secrets.USERNAME_WOO_TEST }} + PASSWORD_WOO_TEST: ${{ secrets.PASSWORD_WOO_TEST }} + EMAIL_WOO_TEST_BALIE: ${{ secrets.EMAIL_WOO_TEST_BALIE }} + PASSWORD_WOO_TEST_BALIE: ${{ secrets.PASSWORD_WOO_TEST_BALIE }} + SECRET_WOO_TEST_BALIE: ${{ secrets.SECRET_WOO_TEST_BALIE }} + run: | + python -m robot -d tests/robot_framework/results -x outputxunit.xml -i E2E_TST -e LOGS -v headless:true tests/robot_framework + - name: Upload test results + uses: actions/upload-artifact@v4 + if: always() + with: + name: reports + path: tests/robot_framework/results + - name: Publish test results + uses: minvws/nl-rdo-github-action-robotframework-test-summary@v0.2.0 + if: always() + with: + output_file: 'tests/robot_framework/results/output.xml' + endpoints: 'https://web.test.woo.rdobeheer.nl' + username: '${{ secrets.USERNAME_WOO_TEST }}' + password: '${{ secrets.PASSWORD_WOO_TEST }}' diff --git a/.github/workflows/migration-check.yml b/.github/workflows/migration-check.yml new file mode 100644 index 000000000..0b83f6091 --- /dev/null +++ b/.github/workflows/migration-check.yml @@ -0,0 +1,85 @@ +name: Check for missing migrations + +on: + pull_request: + branches: + - main + - develop + - release/** + - hotfix/** + - feature/** + +jobs: + sync: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - name: Checkout db + uses: actions/checkout@v4 + with: + repository: minvws/nl-rdo-databases + ref: 'main' + token: ${{ secrets.repo_read_only_token }} + path: './database' + + - name: check for missing migrations + id: migration_check + run: | + # Run the script and store the output + set +e + OUT="$(sh .github/scripts/check-missing-migrations.sh)" + RETVAL=$? + set -e + + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64 | tr -dc 'a-zA-Z0-9') + { + echo "output<<$EOF" + echo "$OUT" + echo "$EOF" + if [[ $RETVAL -eq 1 ]] ; then + echo "missing_migrations=true" + else + echo "missing_migrations=false" + fi + } >> "$GITHUB_OUTPUT" + + - name: debug it + run: | + echo ${{ steps }} + echo $GITHUB_OUTPUT + echo $GITHUB_STATE + + # Find the comment + - name: Find Comment + uses: peter-evans/find-comment@v3 + id: fc + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: Missing Database Migrations + + # Create a comment when migrations are missing in the db repo + - name: Create comment + if: contains(steps.migration_check.outputs.missing_migrations, 'true') + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.fc.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + edit-mode: replace + body: | + ## 🦙🦙 Missing Database Migrations detected + ``` + ${{ steps.migration_check.outputs.output }} + ``` + 👨‍💻 Please run `php bin/console woopie:sql:dump` to create the SQL migrations files, and add them to the database repository to get rid of this message. + + # Remove comment if no missing migrations + - if: ${{ contains(steps.git.outputs.missing_migrations, 'false') && steps.fc.outputs.comment-id != '' }} + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.deleteComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: ${{ steps.fc.outputs.comment-id }} + }) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml new file mode 100644 index 000000000..16bcc3878 --- /dev/null +++ b/.github/workflows/package.yml @@ -0,0 +1,51 @@ +name: Create release package + +on: + push: + tags: + - v* + +jobs: + build: + runs-on: ubuntu-22.04 + steps: + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - uses: actions/checkout@v4 + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + registry-url: 'https://npm.pkg.github.com' + - name: Install npm dependencies + run: | + echo "//npm.pkg.github.com/:_authToken=$NODE_AUTH_TOKEN" >> ~/.npmrc + npm ci --ignore-scripts + env: + NODE_AUTH_TOKEN: ${{ secrets.REPO_READ_ONLY_TOKEN }} + - name: Install PHP + uses: shivammathur/setup-php@master + with: + php-version: 8.2 + - name: Composer install + env: + COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.REPO_READ_ONLY_TOKEN }}"}}' + run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist --no-dev + - name: Run build task + run: npm run build + - name: Clean build + run: | + rm -r node_modules .git var/cache var/log || true + mkdir -p var/log + mkdir -p var/cache + - name: Create version.json + run: | + echo "{ \"version\": \"${{ env.RELEASE_VERSION }}\", \"git_ref\": \"$GITHUB_SHA\"}" > public/version.json + - name: Create tar + run: tar -czf woo-web_${{ env.RELEASE_VERSION }}.tar.gz ./config ./public/ ./src/ ./templates ./translations ./vendor/ ./.db_requirements ./var/cache ./var/log ./worker-*.conf ./bin/console + - name: Upload release tar + uses: actions/upload-artifact@v4 + with: + name: woo-web_${{ env.RELEASE_VERSION }} + path: woo-web_${{ env.RELEASE_VERSION }}.tar.gz diff --git a/.github/workflows/robotframeworkci.yml b/.github/workflows/robotframeworkci.yml new file mode 100644 index 000000000..64e9dca9c --- /dev/null +++ b/.github/workflows/robotframeworkci.yml @@ -0,0 +1,144 @@ +name: E2E Tests CI + +on: + workflow_dispatch: + +jobs: + composer-install: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: vendor/ + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + - name: Install PHP + uses: shivammathur/setup-php@master + with: + php-version: 8.2 + extensions: zip + - name: Install Dependencies + env: + COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.REPO_READ_ONLY_TOKEN }}"}}' + run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist + + robot-tests: + needs: + - composer-install + runs-on: ubuntu-22.04 + services: + postgres: + image: postgres:14.10-bookworm + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + - 5432:5432 + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + redis: + image: redis:5 + ports: + - 6379:6379 + options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 + rabbitmq: + image: rabbitmq:3 + env: + RABBITMQ_DEFAULT_USER: guest + RABBITMQ_DEFAULT_PASS: guest + ports: + - 5672:5672 + - 15672:15672 + options: --health-cmd "rabbitmq-diagnostics -q check_running" --health-interval 10s --health-timeout 5s --health-retries 5 + tika: + image: apache/tika:latest + ports: + - 9998:9998 + elasticsearch: + image: elasticsearch:8.2.2 + env: + discovery.type: single-node + cluster.name: elasticsearch + bootstrap.memory_lock: "true" + ES_JAVA_OPTS: "-Xms512m -Xmx512m" + xpack.security.enabled: false + ports: + - 9200:9200 + - 9300:9300 + options: --health-cmd "curl -f http://localhost:9200/_cluster/health?wait_for_status=yellow" --health-interval 10s --health-timeout 5s --health-retries 5 + + steps: + - uses: actions/checkout@v4 + - name: Install PHP + uses: shivammathur/setup-php@master + with: + php-version: 8.2 + extensions: xdebug, pgsql, zip + - uses: actions/cache@v4 + with: + path: vendor/ + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + - name: Copy .env + run: cp -n .env.ci .env.local + - name: Execute Generate Database Key + run: | + DBKEY=$(bin/console generate:database-key) + echo DATABASE_ENCRYPTION_KEY=${DBKEY:5} >> .env.local + cat .env.local + - name: Build FE + run: | + echo "//npm.pkg.github.com/:_authToken=$NODE_AUTH_TOKEN" >> ~/.npmrc + npm ci + npm run build + env: + NODE_AUTH_TOKEN: ${{ secrets.REPO_READ_ONLY_TOKEN }} + - name: Download symfony app + run: | + wget https://get.symfony.com/cli/installer -O - | bash + mv /home/runner/.symfony5/bin/symfony /usr/local/bin/symfony + - name: Migrate and seed database + run: php bin/console d:m:m -n && php bin/console d:f:l -n + - name: Install libraries + run: | + sudo apt-get update -qq + sudo apt-get install -y openjdk-17-jdk git libicu-dev libpq-dev libonig-dev tesseract-ocr tesseract-ocr-nld poppler-utils pdftk librabbitmq-dev p7zip-full xlsx2csv + php bin/console woopie:check:production + - name: Create woopie index & alias + run: | + php bin/console woopie:index:create robotframework latest --read --write + - name: Run Symfony Server + run: symfony server:start -d + + + # Robot framework setup + - name: Set up Python 3.10 + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Install Robot Framework dependencies + run: | + sudo apt-get install --reinstall libpq-dev + python -m pip install --upgrade pip + pip install -r tests/robot_framework/requirements.txt + rfbrowser init + - name: Run process consume worker + run: | + php bin/console messenger:consume -vv high esupdater global ingestor & + - name: Execute tests (Robot Framework) + run: | + python -m robot -d tests/robot_framework/results -x outputxunit.xml -i CI -v headless:true tests/robot_framework + - name: Upload RF test results + uses: actions/upload-artifact@v4 + if: always() + with: + name: reports + path: | + tests/robot_framework/results + var/log + - name: Publish test results + uses: minvws/nl-rdo-github-action-robotframework-test-summary@v0.2.0 + if: always() + with: + output_file: 'tests/robot_framework/results/output.xml' diff --git a/.gitignore b/.gitignore index 50031308e..06ec00e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ yarn-error.log ### Robot Framework ### /tests/robot_framework/results /tests/robot_framework/libraries/__pycache__ +.venv ### Robot Framework ### ### Virtu ### diff --git a/.irealisatie b/.irealisatie new file mode 100644 index 000000000..3cf23d2fb --- /dev/null +++ b/.irealisatie @@ -0,0 +1,7 @@ +GIT=GitHub +REPO=minvws/nl-rdo-woo-web-private +CLUSTER=Woo +MAINTAINER=rdo-woo-codeowners +COMPONENTS=audit-logger-bundle,horsebattery +LANGUAGES=php,js,md +DESCRIPTION=Woo-platform Ministry of VWS diff --git a/.markdownlint.json b/.markdownlint.json index dd4a0a010..5f7f785a6 100644 --- a/.markdownlint.json +++ b/.markdownlint.json @@ -8,5 +8,8 @@ "allowed_elements": [ "dl", "dt", "dd", "details", "summary", "code" ] + }, + "ul-style" : { + "style": "dash" } } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..cc54ae817 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "sonarlint.connectedMode.project": { + "connectionId": "vws", + "projectKey": "nl-rdo-woo-web-private" + } +} diff --git a/Taskfile.dist.yml b/Taskfile.dist.yml index 4bfe45737..c3e7e36d6 100644 --- a/Taskfile.dist.yml +++ b/Taskfile.dist.yml @@ -35,7 +35,7 @@ tasks: cmds: - task: dc vars: { DOCKER_COMPOSE_ARGS: "build --build-arg USER_UID=$(id -u)" } - - task: rf:build + # - task: rf:build composer:install: desc: Install composer dependencies @@ -47,7 +47,7 @@ tasks: desc: Install node dependencies cmds: - task: dc:run - vars: { CLI_ARGS: "app npm ci" } + vars: { CLI_ARGS: "app npm ci --no-fund" } npm:build: desc: Build assets @@ -59,8 +59,9 @@ tasks: desc: Setup development environment interactive: true cmds: + - task: d:create-cache-volumes - task: env - - "{{.BASE_PATH}}/bin/auth-package-managers" + - '"{{.BASE_PATH}}/bin/auth-package-managers"' - task: dc:build - task: composer:install - task: dc @@ -69,6 +70,7 @@ tasks: vars: { CLI_ARGS: "app bash -c 'wait-for-it postgres:5432 --timeout=0 --strict -- wait-for-it rabbitmq:5672 --timeout=0 --strict -- echo \"Done waiting\"'" } - task: app:migrate - task: app:loadfixtures + - task: app:migrate:test - task: dc:run vars: { CLI_ARGS: "app bin/console woopie:index:create woopie latest --read --write" } - task: npm:install @@ -114,6 +116,12 @@ tasks: - task: down - task: up + ps: + desc: Show all project containers + cmds: + - task: dc + vars: { DOCKER_COMPOSE_ARGS: "ps -a" } + env: desc: Template .env run: once @@ -121,7 +129,7 @@ tasks: DATABASE_ENCRYPTION_KEY: 3140050008b203765bc6ed21721f020e8e72febd72669adcf3151098abdaedc13ddbceb53c7bea8688f9f9a20af5a8ea438528359b8f82ec6545bfa11dddb73735670403cd7495dd6726bb9d2815813d7808ec38d67cfea223113f1ab7d44f817ce6aeff cmds: - cp .env.development .env.local - - docker run --rm --volume $(pwd):/workspace --workdir /workspace ghcr.io/ilyes512/utils:latest + - docker run --rm --volume "$(pwd)":/workspace --workdir /workspace ghcr.io/ilyes512/utils:latest sed -i "s/DATABASE_ENCRYPTION_KEY=.*/DATABASE_ENCRYPTION_KEY={{.DATABASE_ENCRYPTION_KEY}}/g" .env.local sources: - .env.development @@ -138,6 +146,8 @@ tasks: - /.idea cmds: - task: down + - docker volume rm woo_composer || true + - docker volume rm woo_npm || true - git clean -xd --force @@ -175,6 +185,16 @@ tasks: - task: dc:run vars: { CLI_ARGS: "app bin/console woopie:sql:dump" } + app:migrate:test: + desc: Run (doctrine) database migrations in test environment + cmds: + - task: dc:run + vars: { CLI_ARGS: "app bin/console doctrine:database:create --if-not-exists --no-interaction --env=test" } + - task: dc:run + vars: { CLI_ARGS: "app bin/console doctrine:schema:drop --full-database --force --no-interaction --env=test" } + - task: dc:run + vars: { CLI_ARGS: "app bin/console doctrine:schema:create --no-interaction --env=test" } + app:cleansheet: desc: Clears dossiers and inquiries (with related data) from the database. Also clears ES index and RabbitMq message queues. cmds: @@ -266,13 +286,21 @@ tasks: app:update: desc: (re) Pull dependencies, run migrations, build front-end and sync .env + aliases: [app:refresh] cmds: + - task: d:create-cache-volumes - task: composer:install - task: app:migrate + - task: app:migrate:test - task: npm:install - task: npm:build - task: app:syncdotenv + d:create-cache-volumes: + cmds: + - docker volume create woo_composer + - docker volume create woo_npm + worker:start: desc: Start the worker cmds: diff --git a/assets/img/admin/icons.svg b/assets/img/admin/icons.svg index 95c1bb8a7..7998b1847 100644 --- a/assets/img/admin/icons.svg +++ b/assets/img/admin/icons.svg @@ -11,6 +11,10 @@ check + + chevron-down + + chevron-left @@ -19,10 +23,6 @@ chevron-right - - chevron-down - - copy @@ -52,10 +52,6 @@ - - Audio file - - CSV file diff --git a/assets/img/chevron-down.svg b/assets/img/chevron-down.svg index 6c073430b..4c1ff6c4a 100644 --- a/assets/img/chevron-down.svg +++ b/assets/img/chevron-down.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/assets/img/public/icons.svg b/assets/img/public/icons.svg index d84db8182..667845ad1 100644 --- a/assets/img/public/icons.svg +++ b/assets/img/public/icons.svg @@ -1,10 +1,5 @@ - - audio - - - check diff --git a/assets/js/admin/clickable-row.test.ts b/assets/js/admin/clickable-row.test.ts index a940795d0..57385e332 100644 --- a/assets/js/admin/clickable-row.test.ts +++ b/assets/js/admin/clickable-row.test.ts @@ -1,8 +1,8 @@ -import { beforeEach, describe, expect, test } from '@jest/globals'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import { getLocation } from '../utils/browser'; import { clickableRows } from './clickable-row'; -jest.mock('../utils/browser'); +vi.mock('../utils/browser'); describe('the "clickableRows" function', () => { const getRows = () => Array.from(document.querySelectorAll('tr')); @@ -43,6 +43,7 @@ describe('the "clickableRows" function', () => { afterEach(() => { cleanup(); + vi.resetAllMocks(); }); describe('table rows containing an element with the "js-clickable-row__focusable" class name', () => { diff --git a/assets/js/admin/clickable-row.ts b/assets/js/admin/clickable-row.ts index d5db21954..7dba66ebc 100644 --- a/assets/js/admin/clickable-row.ts +++ b/assets/js/admin/clickable-row.ts @@ -1,4 +1,4 @@ -import { getLocation } from '../utils/browser'; +import { getLocation } from '../utils'; import { onFocusIn, onFocusOut } from '../utils/on'; const enum ClickableRowClassNames { diff --git a/assets/js/admin/dossier/documents-status.ts b/assets/js/admin/dossier/documents-status.ts index 16df63e5d..b204a4fb0 100644 --- a/assets/js/admin/dossier/documents-status.ts +++ b/assets/js/admin/dossier/documents-status.ts @@ -8,7 +8,6 @@ export const dossierDocumentsStatus = () => { let canNotContinueYetErrorElement: HTMLElement | null = null; let placeholderElement: HTMLElement | null = null; let timeoutId: NodeJS.Timeout | null = null; - let uploadsProcessingElement: HTMLElement | null = null; let uploadsRemainingElement: HTMLElement | null = null; let uploadsSectionElement: HTMLElement | null = null; @@ -20,7 +19,6 @@ export const dossierDocumentsStatus = () => { canNotContinueYetErrorElement = document.getElementById('js-dossier-documents-can-not-continue'); uploadsRemainingElement = placeholderElement.querySelector('.js-uploads-remaining'); - uploadsProcessingElement = placeholderElement.querySelector('.js-uploads-processing'); uploadsSectionElement = placeholderElement.querySelector('.js-upload-section'); abortController = new AbortController(); @@ -34,8 +32,12 @@ export const dossierDocumentsStatus = () => { areAllFilesUploaded = completed; - if (uploadsProcessingElement && uploadsRemainingElement) { + const uploadsProcessingElement = placeholderElement?.querySelector('.js-uploads-processing'); + if (uploadsProcessingElement) { uploadsProcessingElement.innerHTML = uploadsProcessingContent; + } + + if (uploadsRemainingElement) { uploadsRemainingElement.innerHTML = uploadsRemainingContent; } diff --git a/assets/js/admin/print.test.ts b/assets/js/admin/print.test.ts index 3e6c1ffd1..dd8bd96bb 100644 --- a/assets/js/admin/print.test.ts +++ b/assets/js/admin/print.test.ts @@ -1,8 +1,8 @@ -import { beforeEach, describe, expect, test } from '@jest/globals'; +import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; import { getWindow } from '../utils'; import { printPage } from './print'; -jest.mock('../utils'); +vi.mock('../utils'); describe('the "printPage" function', () => { const getPrintPageButton = () => document.querySelector('.js-print-page') as HTMLElement; @@ -21,6 +21,7 @@ describe('the "printPage" function', () => { afterEach(() => { cleanup(); + vi.resetAllMocks(); }); test('should print the page when clicking a button with the "js-print-page" class name', () => { diff --git a/assets/js/admin/utils/file/file-system.ts b/assets/js/admin/utils/file/file-system.ts index 31369372b..c50eeacf4 100644 --- a/assets/js/admin/utils/file/file-system.ts +++ b/assets/js/admin/utils/file/file-system.ts @@ -1,4 +1,4 @@ -import { areFilesEqual } from './file'; +import { areFilesEqual, isValidMaxFileSize } from './file'; export interface InvalidFile { file: File; @@ -106,7 +106,7 @@ export const validateFiles = (files: FileList, mimeTypes: string[], maxFileSize? const mimeTypesSet = new Set(mimeTypes); const hasValidMimeTypesDefined = mimeTypesSet.size > 0; - const hasValidMaxFileSize = Number.isInteger(maxFileSize) && Number(maxFileSize) > 0; + const hasValidMaxFileSize = isValidMaxFileSize(maxFileSize); const hasValidMimeType = (file: File) => { if (!hasValidMimeTypesDefined) { diff --git a/assets/js/admin/utils/file/file.test.ts b/assets/js/admin/utils/file/file.test.ts index 0dd80a9f0..93ef0a204 100644 --- a/assets/js/admin/utils/file/file.test.ts +++ b/assets/js/admin/utils/file/file.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, test } from '@jest/globals'; +import { describe, expect, test } from 'vitest'; import { areFilesEqual, formatFileSize, getIconNameByMimeType } from './file'; describe('The file utility functions', () => { @@ -19,11 +19,6 @@ describe('The file utility functions', () => { }); describe('the "getIconNameByMimeType" function', () => { - test('should return "file-audio" for audio mimetypes', () => { - expect(getIconNameByMimeType('audio/mp4')).toBe('file-audio'); - expect(getIconNameByMimeType('audio/mpeg')).toBe('file-audio'); - }); - test('should return "file-csv" for csv mimetypes', () => { expect(getIconNameByMimeType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')).toBe('file-csv'); }); diff --git a/assets/js/admin/utils/file/file.ts b/assets/js/admin/utils/file/file.ts index 561957a6d..b2183eec0 100644 --- a/assets/js/admin/utils/file/file.ts +++ b/assets/js/admin/utils/file/file.ts @@ -1,8 +1,6 @@ -import { formatNumber } from '@utils'; +import { formatNumber, isNumber } from '@utils'; const enum MimeType { - AudioMp4 = 'audio/mp4', - AudioMpeg = 'audio/mpeg', Csv = 'application/csv', Pdf = 'application/pdf', PdfX = 'application/x-pdf', @@ -15,8 +13,7 @@ const enum MimeType { Zip = 'application/zip', } -const MimeTypes: Readonly> = { - Audio: [MimeType.AudioMp4, MimeType.AudioMpeg], +export const MimeTypes: Readonly> = { Csv: [MimeType.Csv], Pdf: [MimeType.Pdf], Spreadsheet: [MimeType.OpenDocumentSpeadsheet, MimeType.OfficeDocumentSpreadsheet], @@ -40,7 +37,6 @@ export const formatFileSize = (bytes: number): string => { export const getIconNameByMimeType = (mimeType: string) => { const mappings = { - 'file-audio': MimeTypes.Audio, 'file-csv': [...MimeTypes.Csv, ...MimeTypes.Spreadsheet], 'file-pdf': MimeTypes.Pdf, 'file-video': MimeTypes.Video, @@ -55,7 +51,6 @@ export const getIconNameByMimeType = (mimeType: string) => { export const getFileTypeByMimeType = (mimeType: string) => { const mappings = { - audio: MimeTypes.Audio, csv: MimeTypes.Csv, spreadsheet: MimeTypes.Spreadsheet, pdf: MimeTypes.Pdf, @@ -67,10 +62,11 @@ export const getFileTypeByMimeType = (mimeType: string) => { return (Object.keys(mappings) as (keyof typeof mappings)[]).find((key) => mappings[key].includes(mimeType)) ?? 'onbekend'; }; +export const isValidMaxFileSize = (maxFileSize: unknown): boolean => isNumber(maxFileSize) && Number(maxFileSize) > 0; + const getExtenstionByMimeType = (mimeType: string): string | undefined => { const mappings: Record = { - '.mp4': [MimeType.AudioMp4, MimeType.VideoMp4], - '.mp3': [MimeType.AudioMpeg], + '.mp4': [MimeType.VideoMp4], '.pdf': [MimeType.Pdf], '.ods': [MimeType.OpenDocumentSpeadsheet], '.xlsx': [MimeType.OfficeDocumentSpreadsheet], diff --git a/assets/js/admin/utils/file/upload.ts b/assets/js/admin/utils/file/upload.ts index 6e9af5cbc..cd0e8f515 100644 --- a/assets/js/admin/utils/file/upload.ts +++ b/assets/js/admin/utils/file/upload.ts @@ -13,30 +13,41 @@ export interface Chunk { numberOfChunks: number; size: number; uploadFinished: boolean; + uploadUuid: string | undefined; +} + +interface Response { + groupId: string | null; + mimeType: string; + originalName: string; + size: number; + uploadUuid: string; } interface Options { - chunkSize?: number; - endpoint: string; + endpoint?: string; file: File; - inputName: string; + groupId?: string; onError?: () => void; onProgress?: (progress: number) => void; - onSuccess?: () => void; + onSuccess?: (uploadUuid: string | undefined) => void; + uploadName?: string; } export const uploadFile = (options: Options) => { const { - endpoint, + endpoint = '/balie/uploader', file, - inputName, + groupId, onError = () => {}, onProgress = () => {}, onSuccess = () => {}, + uploadName = 'file', } = options; - const CHUNK_SIZE = 16 * 1024 * 1024; - const cleanupFunctions: (() => void)[] = []; + let cleanupUpload: () => void = () => {}; + + const CHUNK_SIZE = 16 * 1024 * 1024; // 16 Mb const fileId = uniqueId('file', 32); const store = new Map(); const totalFileSize = file.size; @@ -63,26 +74,42 @@ export const uploadFile = (options: Options) => { numberOfChunks, size: content.size, uploadFinished: false, + uploadUuid: undefined, }; store.set(id, chunk); + } - cleanupFunctions.push(uploadChunk(chunk, id)); + uploadNextChunk(); + }; + + const uploadNextChunk = async () => { + const chunks = getChunks(); + const nextChunkToUpload = chunks.find((chunk) => !chunk.isUploaded); + + if (!nextChunkToUpload) { + onSuccess(chunks.find((chunk) => chunk.uploadUuid)?.uploadUuid); + return; } + + cleanupUpload = uploadChunk(nextChunkToUpload); }; - const uploadChunk = (chunk: Chunk, chunkId: number) => { + const uploadChunk = (chunk: Chunk) => { const { request, sendRequest } = createChunkRequest(chunk); const abortController = new AbortController(); request.upload.addEventListener('progress', (event) => { const { loaded, total } = event; - updateChunkProgress(chunkId, loaded, total); + updateChunkProgress(chunk.id, loaded, total); }, { signal: abortController.signal }); request.addEventListener('load', () => { - updateChunkUploadResult(chunkId, isSuccessStatusCode(request.status)); + updateChunkUploadResult(chunk.id, isSuccessStatusCode(request.status), request.response?.data); + }, { signal: abortController.signal }); + + request.addEventListener('readystatechange', () => { }, { signal: abortController.signal }); sendRequest(); @@ -93,25 +120,22 @@ export const uploadFile = (options: Options) => { }; }; - const updateChunkUploadResult = (chunkId: number, isUploadSuccess: boolean) => { + const updateChunkUploadResult = (chunkId: number, isUploadSuccess: boolean, response?: Response) => { const chunk = getChunk(chunkId); chunk.isUploaded = true; chunk.isUploadSuccess = isUploadSuccess; + chunk.uploadUuid = response?.uploadUuid; store.set(chunkId, chunk); - const areAllChunksUploaded = getChunks().every((chunkItem) => chunkItem.isUploaded); - if (!areAllChunksUploaded) { - return; - } + cleanupUpload(); const haveChunksFailed = getChunks().some((chunkItem) => chunkItem.isUploadSuccess === false); if (haveChunksFailed) { - cleanup(); onError(); return; } - onSuccess(); + uploadNextChunk(); }; const updateChunkProgress = (chunkId: number, bytesSent: number, bytesToSend: number) => { @@ -138,14 +162,18 @@ export const uploadFile = (options: Options) => { const createChunkRequest = (chunk: Chunk): { request: XMLHttpRequest, sendRequest: () => void } => { const formData = new FormData(); - formData.append(inputName, chunk.content, file.name); - formData.append('chunkbyteoffset', chunk.byteOffset.toString()); + formData.append(uploadName, chunk.content, file.name); formData.append('chunkindex', chunk.index.toString()); formData.append('totalchunkcount', chunk.numberOfChunks.toString()); formData.append('uuid', fileId); // each chunk of a file should have the same uuid + if (groupId) { + formData.append('groupId', groupId); + } const request = new XMLHttpRequest(); request.open('POST', endpoint, true); + request.responseType = 'json'; + request.setRequestHeader('Accept', 'application/json'); return { request, @@ -156,11 +184,7 @@ export const uploadFile = (options: Options) => { const getChunk = (id: number) => store.get(id) as Chunk; const getChunks = () => Array.from(store.values()); - const cleanup = () => { - cleanupFunctions.forEach((cleanupFunction) => cleanupFunction()); - }; - intialize(); - return cleanup; + return cleanupUpload; }; diff --git a/assets/js/admin/visibility-toggler.test.ts b/assets/js/admin/visibility-toggler.test.ts index 691fe7719..e6d8a022c 100644 --- a/assets/js/admin/visibility-toggler.test.ts +++ b/assets/js/admin/visibility-toggler.test.ts @@ -1,4 +1,4 @@ -import { beforeEach, describe, expect, test } from '@jest/globals'; +import { afterEach, beforeEach, describe, expect, test } from 'vitest'; import { isElementHidden } from '@utils'; import { visibilityToggler } from './visibility-toggler'; diff --git a/assets/js/admin/vue/component/Alert.vue b/assets/js/admin/vue/component/Alert.vue index 148b19840..bb0fc0cf8 100644 --- a/assets/js/admin/vue/component/Alert.vue +++ b/assets/js/admin/vue/component/Alert.vue @@ -1,8 +1,6 @@
- +
diff --git a/assets/js/admin/vue/component/Collapsible.vue b/assets/js/admin/vue/component/Collapsible.vue new file mode 100644 index 000000000..60703d445 --- /dev/null +++ b/assets/js/admin/vue/component/Collapsible.vue @@ -0,0 +1,57 @@ + + + diff --git a/assets/js/admin/vue/component/decision-attachments/AttachmentForm.vue b/assets/js/admin/vue/component/decision-attachments/AttachmentForm.vue deleted file mode 100644 index 83c6e52b2..000000000 --- a/assets/js/admin/vue/component/decision-attachments/AttachmentForm.vue +++ /dev/null @@ -1,120 +0,0 @@ - - - diff --git a/assets/js/admin/vue/component/file/MimeTypeIcon.vue b/assets/js/admin/vue/component/file/MimeTypeIcon.vue index 2fb24a5bf..c9599abdb 100644 --- a/assets/js/admin/vue/component/file/MimeTypeIcon.vue +++ b/assets/js/admin/vue/component/file/MimeTypeIcon.vue @@ -14,7 +14,7 @@ }, }); - const name = getIconNameByMimeType(props.mimeType); + const name = computed(() => getIconNameByMimeType(props.mimeType));