From 52327da82c0e4da2296c9da71e71cca44510a4f1 Mon Sep 17 00:00:00 2001 From: Giovanni Francesco Luigi Catania Date: Thu, 23 Apr 2026 09:30:58 +0200 Subject: [PATCH] caricata WA --- README.md | 3 +- idrocap_wa/.htaccess | 12 + idrocap_wa/Dockerfile | 20 + idrocap_wa/README.md | 61 + idrocap_wa/bin/bash_completion.sh | 47 + idrocap_wa/bin/cake | 75 + idrocap_wa/bin/cake.bat | 27 + idrocap_wa/bin/cake.php | 10 + idrocap_wa/composer.json | 67 + idrocap_wa/composer.lock | 7466 +++ idrocap_wa/config/.env.example | 38 + idrocap_wa/config/app.php | 436 + idrocap_wa/config/app_local.example.php | 94 + idrocap_wa/config/app_local.php | 94 + idrocap_wa/config/bootstrap.php | 231 + idrocap_wa/config/bootstrap_cli.php | 35 + idrocap_wa/config/cakelte.php | 43 + idrocap_wa/config/keys/private.key | 52 + idrocap_wa/config/keys/public.key | 15 + idrocap_wa/config/paths.php | 94 + idrocap_wa/config/plugins.php | 15 + idrocap_wa/config/routes.php | 357 + idrocap_wa/config/schema/i18n.sql | 18 + idrocap_wa/config/schema/sessions.sql | 15 + idrocap_wa/dockerfiles/cake | 152 + idrocap_wa/dockerfiles/run | 93 + idrocap_wa/dockerfiles/www.conf | 453 + idrocap_wa/index.php | 16 + .../jixel-background-task-handler/Dockerfile | 39 + .../jixel-background-task-handler/jbth.py | 152 + .../jixel-background-task-handler/jbth.sh | 9 + .../jixel-background-task-handler/jgprc.py | 169 + .../jixel-background-task-handler/jgprc.sh | 26 + .../jixel-background-task-handler.sh | 12 + .../jixel-cron.log | 0 .../jixel-cron.sh | 5 + .../jixel-cron.txt | 6 + .../jixel-general-purpose-rabbit-consumer.sh | 12 + idrocap_wa/phpcs.xml | 12 + idrocap_wa/phpstan.neon | 6 + idrocap_wa/phpunit.xml.dist | 37 + idrocap_wa/plugins/.gitkeep | 0 idrocap_wa/psalm.xml | 15 + idrocap_wa/resources/.gitkeep | 0 idrocap_wa/resources/locales/cake.pot | 279 + idrocap_wa/resources/locales/default.pot | 1709 + idrocap_wa/resources/locales/en/default.po | 1709 + .../resources/locales/en/previous_default.po | 1709 + idrocap_wa/resources/locales/it/cake.po | 279 + idrocap_wa/src/Application.php | 268 + .../Command/AddCadastralCodeToUsesCommand.php | 95 + .../AddDerivationCoordinatesCommand.php | 44 + ...ingAntimafiaCertificateRequestsCommand.php | 57 + .../src/Command/CopyTranslationsCommand.php | 144 + .../IntendedUseVegetationCheckCommand.php | 107 + .../NormalizeApplicantProvinceCommand.php | 65 + .../Command/NotificationsHandlerCommand.php | 65 + ...kWaterDrawingPaperworkSnapshotsCommand.php | 98 + idrocap_wa/src/Console/Installer.php | 250 + .../src/Controller/AiServicesController.php | 91 + .../src/Controller/Api/AppController.php | 74 + .../Controller/Api/AttachmentsController.php | 53 + .../src/Controller/Api/ErrorController.php | 70 + .../Api/NotificationsController.php | 156 + .../Api/OrganisationTypesController.php | 31 + .../Api/OrganisationsController.php | 157 + .../Api/SubscriptionsController.php | 67 + .../src/Controller/Api/UsersController.php | 230 + .../Api/WaterDrawingDerivationsController.php | 75 + .../WaterDrawingMeasurementsController.php | 47 + .../Api/WaterDrawingPaperworksController.php | 170 + idrocap_wa/src/Controller/AppController.php | 424 + .../src/Controller/ApplicantsController.php | 112 + .../src/Controller/AttachmentsController.php | 98 + .../src/Controller/CapabilitiesController.php | 205 + idrocap_wa/src/Controller/Component/.gitkeep | 0 .../Component/StreamableCsvExportTrait.php | 103 + .../ControllableObjectsController.php | 56 + .../src/Controller/DashboardController.php | 35 + .../src/Controller/DeliveriesController.php | 185 + .../src/Controller/DistrictsController.php | 66 + .../src/Controller/EmailsController.php | 78 + idrocap_wa/src/Controller/ErrorController.php | 70 + idrocap_wa/src/Controller/FaxesController.php | 78 + .../src/Controller/FiltersController.php | 25 + .../src/Controller/GroupsController.php | 236 + idrocap_wa/src/Controller/MapsController.php | 187 + .../src/Controller/MobilePhonesController.php | 79 + .../Controller/NotificationsController.php | 97 + .../Controller/OrganisationsController.php | 204 + idrocap_wa/src/Controller/PecsController.php | 78 + .../src/Controller/PhonesController.php | 78 + .../src/Controller/PrivacyController.php | 174 + idrocap_wa/src/Controller/TagsController.php | 91 + .../Controller/TelegramChatsController.php | 76 + idrocap_wa/src/Controller/UsersController.php | 624 + .../WaterDrawingArticlesController.php | 124 + .../WaterDrawingDerivationsController.php | 123 + .../Controller/WaterDrawingFeesController.php | 174 + .../WaterDrawingIntendedUsesController.php | 108 + .../WaterDrawingMeasurementsController.php | 124 + .../WaterDrawingMetersController.php | 97 + .../WaterDrawingPaperworkPecsController.php | 148 + .../WaterDrawingPaperworksController.php | 1775 + .../WaterDrawingPaymentsController.php | 256 + .../WaterDrawingReturnPointsController.php | 112 + idrocap_wa/src/Error/AppExceptionRenderer.php | 27 + .../Identifier/JixelPasswordIdentifier.php | 198 + ...rTimezoneDatetimeRequestDataMiddleware.php | 37 + idrocap_wa/src/Model/Behavior/.gitkeep | 0 .../Model/Behavior/AttachmentsBehavior.php | 165 + .../ControllableObjectInterfaceBehavior.php | 42 + idrocap_wa/src/Model/Entity/Actor.php | 302 + idrocap_wa/src/Model/Entity/ActorType.php | 35 + idrocap_wa/src/Model/Entity/Applicant.php | 81 + .../ApplicantsWaterDrawingPaperwork.php | 37 + idrocap_wa/src/Model/Entity/Attachment.php | 86 + .../src/Model/Entity/BackgroundTask.php | 43 + .../src/Model/Entity/CadastralCropType.php | 31 + .../src/Model/Entity/CapabilitiesMenuItem.php | 35 + .../Model/Entity/CapabilitiesMenuSection.php | 35 + idrocap_wa/src/Model/Entity/Capability.php | 53 + .../src/Model/Entity/CapabilityGroup.php | 35 + .../src/Model/Entity/ControllableObject.php | 297 + .../Entity/ControllableObjectInterface.php | 35 + .../ControllableObjectInterfaceType.php | 34 + .../Model/Entity/ControllableObjectType.php | 33 + idrocap_wa/src/Model/Entity/County.php | 52 + idrocap_wa/src/Model/Entity/Delivery.php | 53 + idrocap_wa/src/Model/Entity/DeliveryType.php | 31 + .../src/Model/Entity/DispatchingTask.php | 47 + .../src/Model/Entity/DispatchingTaskItem.php | 47 + .../Model/Entity/DispatchingTaskStatus.php | 31 + idrocap_wa/src/Model/Entity/District.php | 52 + idrocap_wa/src/Model/Entity/Email.php | 43 + .../src/Model/Entity/EmailDescription.php | 33 + idrocap_wa/src/Model/Entity/Fax.php | 41 + .../src/Model/Entity/FaxDescription.php | 33 + idrocap_wa/src/Model/Entity/Filter.php | 43 + idrocap_wa/src/Model/Entity/Group.php | 53 + idrocap_wa/src/Model/Entity/GroupsGroup.php | 33 + idrocap_wa/src/Model/Entity/Language.php | 33 + idrocap_wa/src/Model/Entity/Location.php | 56 + .../src/Model/Entity/LocationAttribute.php | 43 + idrocap_wa/src/Model/Entity/Map.php | 43 + idrocap_wa/src/Model/Entity/MenuItem.php | 82 + idrocap_wa/src/Model/Entity/MenuSection.php | 35 + idrocap_wa/src/Model/Entity/Message.php | 61 + idrocap_wa/src/Model/Entity/MessageStatus.php | 31 + idrocap_wa/src/Model/Entity/MessageType.php | 32 + .../src/Model/Entity/MobileComponent.php | 35 + idrocap_wa/src/Model/Entity/MobilePhone.php | 43 + .../Model/Entity/MobilePhoneDescription.php | 33 + idrocap_wa/src/Model/Entity/Notification.php | 51 + .../src/Model/Entity/NotificationType.php | 31 + idrocap_wa/src/Model/Entity/Organisation.php | 259 + .../src/Model/Entity/OrganisationType.php | 32 + idrocap_wa/src/Model/Entity/Pec.php | 43 + .../src/Model/Entity/PecDescription.php | 33 + idrocap_wa/src/Model/Entity/Permission.php | 34 + idrocap_wa/src/Model/Entity/Phone.php | 39 + .../src/Model/Entity/PhoneDescription.php | 33 + idrocap_wa/src/Model/Entity/Privacy.php | 32 + idrocap_wa/src/Model/Entity/PrivacyUser.php | 37 + .../src/Model/Entity/PushNotification.php | 37 + idrocap_wa/src/Model/Entity/Snapshot.php | 47 + idrocap_wa/src/Model/Entity/Tag.php | 56 + idrocap_wa/src/Model/Entity/TelegramChat.php | 41 + .../src/Model/Entity/TelegramContact.php | 51 + .../UnpackedWaterDrawingPaperworkSnapshot.php | 55 + idrocap_wa/src/Model/Entity/User.php | 643 + .../UserTimezoneDatetimeEntityTrait.php | 32 + ...erDrawingAntimafiaCertificationRequest.php | 43 + ...ingAntimafiaCertificationRequestStatus.php | 31 + .../src/Model/Entity/WaterDrawingArticle.php | 32 + .../Model/Entity/WaterDrawingDerivation.php | 67 + .../Entity/WaterDrawingDerivationType.php | 31 + .../src/Model/Entity/WaterDrawingFee.php | 65 + .../Model/Entity/WaterDrawingIntendedUse.php | 55 + .../Entity/WaterDrawingIntendedUseType.php | 31 + .../Model/Entity/WaterDrawingMeasurement.php | 39 + .../src/Model/Entity/WaterDrawingMeter.php | 45 + .../Model/Entity/WaterDrawingPaperwork.php | 479 + .../Entity/WaterDrawingPaperworkHistory.php | 54 + .../Model/Entity/WaterDrawingPaperworkPec.php | 53 + .../Entity/WaterDrawingPaperworkStatus.php | 33 + .../src/Model/Entity/WaterDrawingPayment.php | 56 + .../Model/Entity/WaterDrawingPaymentType.php | 31 + .../Model/Entity/WaterDrawingReturnPoint.php | 43 + .../src/Model/Entity/WaterDrawingToolType.php | 31 + .../Entity/WaterDrawingWateringSystem.php | 31 + .../src/Model/Table/ActorTypesTable.php | 81 + idrocap_wa/src/Model/Table/ActorsTable.php | 126 + .../src/Model/Table/ApplicantsTable.php | 208 + .../ApplicantsWaterDrawingPaperworksTable.php | 100 + .../src/Model/Table/AttachmentsTable.php | 133 + .../src/Model/Table/BackgroundTasksTable.php | 103 + .../Model/Table/CadastralCropTypesTable.php | 69 + .../Table/CapabilitiesMenuItemsTable.php | 91 + .../Table/CapabilitiesMenuSectionsTable.php | 91 + .../src/Model/Table/CapabilitiesTable.php | 145 + .../src/Model/Table/CapabilityGroupsTable.php | 79 + .../ControllableObjectInterfaceTypesTable.php | 77 + .../ControllableObjectInterfacesTable.php | 95 + .../Table/ControllableObjectTypesTable.php | 74 + .../Model/Table/ControllableObjectsTable.php | 167 + idrocap_wa/src/Model/Table/CountiesTable.php | 165 + .../src/Model/Table/DeliveriesTable.php | 145 + .../src/Model/Table/DeliveryTypesTable.php | 65 + .../Model/Table/DispatchingTaskItemsTable.php | 111 + .../Table/DispatchingTaskStatusesTable.php | 65 + .../src/Model/Table/DispatchingTasksTable.php | 113 + idrocap_wa/src/Model/Table/DistrictsTable.php | 136 + .../Model/Table/EmailDescriptionsTable.php | 74 + idrocap_wa/src/Model/Table/EmailsTable.php | 111 + .../src/Model/Table/FaxDescriptionsTable.php | 73 + idrocap_wa/src/Model/Table/FaxesTable.php | 107 + idrocap_wa/src/Model/Table/FiltersTable.php | 105 + .../src/Model/Table/GroupsGroupsTable.php | 94 + idrocap_wa/src/Model/Table/GroupsTable.php | 157 + idrocap_wa/src/Model/Table/LanguagesTable.php | 71 + .../Model/Table/LocationAttributesTable.php | 116 + idrocap_wa/src/Model/Table/LocationsTable.php | 118 + idrocap_wa/src/Model/Table/MapsTable.php | 88 + idrocap_wa/src/Model/Table/MenuItemsTable.php | 135 + .../src/Model/Table/MenuSectionsTable.php | 80 + .../src/Model/Table/MessageStatusesTable.php | 65 + .../src/Model/Table/MessageTypesTable.php | 69 + idrocap_wa/src/Model/Table/MessagesTable.php | 150 + .../src/Model/Table/MobileComponentsTable.php | 77 + .../Table/MobilePhoneDescriptionsTable.php | 74 + .../src/Model/Table/MobilePhonesTable.php | 111 + .../Model/Table/NotificationTypesTable.php | 65 + .../src/Model/Table/NotificationsTable.php | 122 + .../Model/Table/OrganisationTypesTable.php | 69 + .../src/Model/Table/OrganisationsTable.php | 286 + .../src/Model/Table/PecDescriptionsTable.php | 74 + idrocap_wa/src/Model/Table/PecsTable.php | 111 + .../src/Model/Table/PermissionsTable.php | 85 + .../Model/Table/PhoneDescriptionsTable.php | 73 + idrocap_wa/src/Model/Table/PhonesTable.php | 103 + idrocap_wa/src/Model/Table/PrivacyTable.php | 90 + .../src/Model/Table/PrivacyUsersTable.php | 123 + .../Model/Table/PushNotificationsTable.php | 101 + idrocap_wa/src/Model/Table/SnapshotsTable.php | 118 + idrocap_wa/src/Model/Table/TagsTable.php | 94 + .../src/Model/Table/TelegramChatsTable.php | 99 + .../src/Model/Table/TelegramContactsTable.php | 116 + ...kedWaterDrawingPaperworkSnapshotsTable.php | 137 + idrocap_wa/src/Model/Table/UsersTable.php | 476 + ...mafiaCertificationRequestStatusesTable.php | 67 + ...ingAntimafiaCertificationRequestsTable.php | 107 + .../Model/Table/WaterDrawingArticlesTable.php | 76 + .../WaterDrawingDerivationTypesTable.php | 66 + .../Table/WaterDrawingDerivationsTable.php | 206 + .../src/Model/Table/WaterDrawingFeesTable.php | 124 + .../WaterDrawingIntendedUseTypesTable.php | 67 + .../Table/WaterDrawingIntendedUsesTable.php | 147 + .../Table/WaterDrawingMeasurementsTable.php | 108 + .../Model/Table/WaterDrawingMetersTable.php | 118 + .../WaterDrawingPaperworkHistoriesTable.php | 170 + .../Table/WaterDrawingPaperworkPecsTable.php | 136 + .../WaterDrawingPaperworkStatusesTable.php | 70 + .../Table/WaterDrawingPaperworksTable.php | 383 + .../Table/WaterDrawingPaymentTypesTable.php | 67 + .../Model/Table/WaterDrawingPaymentsTable.php | 149 + .../Table/WaterDrawingReturnPointsTable.php | 120 + .../Table/WaterDrawingToolTypesTable.php | 67 + .../WaterDrawingWateringSystemsTable.php | 67 + idrocap_wa/src/View/AjaxView.php | 46 + idrocap_wa/src/View/AppView.php | 52 + idrocap_wa/src/View/Cell/.gitkeep | 0 .../src/View/Cell/DistrictProvinceCell.php | 68 + idrocap_wa/src/View/Cell/FilterInputCell.php | 51 + idrocap_wa/src/View/Cell/FiltersCell.php | 50 + idrocap_wa/src/View/Cell/IntendedUsesCell.php | 33 + idrocap_wa/src/View/Cell/MapCell.php | 234 + idrocap_wa/src/View/CustomCsvView.php | 100 + .../src/View/Helper/BreadcrumbHelper.php | 67 + idrocap_wa/src/View/Helper/MenuHelper.php | 108 + .../src/View/Helper/NotificationsHelper.php | 87 + idrocap_wa/src/View/Helper/SectionsHelper.php | 55 + .../src/WGS/Auth/OpenIdConnectClient.php | 163 + .../src/WGS/FileStorage/FileStorage.php | 14 + .../WGS/FileStorage/FileStorageFactory.php | 37 + .../src/WGS/FileStorage/HadoopFileStorage.php | 116 + .../WGS/FileStorage/S3MinioFileStorage.php | 180 + idrocap_wa/src/WGS/Geo/CadastralUtils.php | 61 + .../Geo/ExtGeoResourceAttributesRetriever.php | 40 + idrocap_wa/src/WGS/Geo/GeoValidation.php | 61 + idrocap_wa/src/WGS/Geo/Geocoding.php | 84 + .../Geo/IntGeoResourceAttributesRetriever.php | 57 + .../WGS/Geo/LocationAttributesRetriever.php | 65 + .../NotificationsHandler/MessagingHandler.php | 631 + .../NotificationGenerator.php | 169 + .../NotificationsHandler.php | 243 + .../RecipientsDetector.php | 119 + .../SystemNotificationsDispatcher.php | 122 + .../WGS/SnapshotsHandler/SnapshotsHandler.php | 304 + .../Utils/Attachments/AttachmentChecker.php | 27 + .../Utils/Attachments/AttachmentConverter.php | 39 + .../Attachments/SignedAttachmentChecker.php | 133 + .../DistrictCellDto.php | 25 + .../ProvinceCellDto.php | 25 + .../Dto/Users/CitizenRegistrationDTO.php | 81 + .../src/WGS/Utils/Enum/InputFieldType.php | 8 + .../WGS/Utils/Enum/ProvinceDistrictFields.php | 12 + idrocap_wa/src/WGS/Utils/Enum/Regions.php | 6 + .../src/WGS/Utils/Enum/SicilyProvinces.php | 33 + .../Helper/ProvinceDistrictFieldHelper.php | 44 + ...ntendedUseVegetationCheckCommandSender.php | 28 + .../templates/Applicants/citizen_add.php | 49 + .../templates/Applicants/citizen_edit.php | 49 + .../templates/Applicants/citizen_view.php | 63 + idrocap_wa/templates/Applicants/edit.php | 71 + idrocap_wa/templates/Applicants/view.php | 72 + idrocap_wa/templates/Capabilities/index.php | 85 + .../ControllableObjects/get_attachments.php | 119 + idrocap_wa/templates/Dashboard/index.php | 32 + idrocap_wa/templates/Deliveries/index.php | 284 + idrocap_wa/templates/Emails/add.php | 54 + idrocap_wa/templates/Emails/edit.php | 54 + idrocap_wa/templates/Error/error400.php | 49 + idrocap_wa/templates/Error/error500.php | 53 + idrocap_wa/templates/Faxes/add.php | 54 + idrocap_wa/templates/Faxes/edit.php | 54 + .../templates/Filters/get_filter_input.php | 1 + idrocap_wa/templates/Groups/add.php | 61 + idrocap_wa/templates/Groups/edit.php | 66 + .../templates/Groups/handle_capabilities.php | 75 + idrocap_wa/templates/Groups/index.php | 63 + idrocap_wa/templates/Groups/view.php | 45 + idrocap_wa/templates/Maps/index.php | 149 + idrocap_wa/templates/MobilePhones/add.php | 54 + idrocap_wa/templates/MobilePhones/edit.php | 54 + idrocap_wa/templates/Notifications/index.php | 4 + .../templates/Notifications/read_all.php | 5 + idrocap_wa/templates/Organisations/add.php | 197 + idrocap_wa/templates/Organisations/edit.php | 118 + idrocap_wa/templates/Organisations/index.php | 75 + idrocap_wa/templates/Organisations/view.php | 99 + idrocap_wa/templates/Pecs/add.php | 54 + idrocap_wa/templates/Pecs/edit.php | 54 + idrocap_wa/templates/Phones/add.php | 53 + idrocap_wa/templates/Phones/edit.php | 53 + .../templates/Privacy/accept_privacy.php | 29 + idrocap_wa/templates/Privacy/edit.php | 24 + idrocap_wa/templates/Privacy/view.php | 19 + idrocap_wa/templates/Privacy/view_public.php | 10 + idrocap_wa/templates/Tags/add.php | 54 + idrocap_wa/templates/Tags/edit.php | 55 + idrocap_wa/templates/Tags/index.php | 63 + idrocap_wa/templates/Tags/view.php | 52 + idrocap_wa/templates/TelegramChats/add.php | 53 + idrocap_wa/templates/TelegramChats/edit.php | 53 + idrocap_wa/templates/Users/add.php | 108 + idrocap_wa/templates/Users/add_citizen.php | 256 + .../templates/Users/choose_new_password.php | 10 + idrocap_wa/templates/Users/edit.php | 112 + idrocap_wa/templates/Users/index.php | 71 + idrocap_wa/templates/Users/login.php | 27 + .../templates/Users/one_time_password.php | 8 + .../templates/Users/password_recovery.php | 9 + idrocap_wa/templates/Users/view.php | 72 + .../templates/WaterDrawingArticles/add.php | 45 + .../templates/WaterDrawingArticles/edit.php | 45 + .../templates/WaterDrawingArticles/index.php | 65 + .../templates/WaterDrawingArticles/view.php | 55 + .../templates/WaterDrawingDerivations/add.php | 250 + .../WaterDrawingDerivations/edit.php | 235 + .../WaterDrawingDerivations/index.php | 72 + .../WaterDrawingDerivations/view.php | 104 + idrocap_wa/templates/WaterDrawingFees/add.php | 46 + .../templates/WaterDrawingFees/edit.php | 46 + .../templates/WaterDrawingFees/index.php | 76 + .../templates/WaterDrawingFees/view.php | 91 + .../WaterDrawingIntendedUses/add.php | 37 + .../WaterDrawingIntendedUses/edit.php | 42 + .../WaterDrawingIntendedUses/index.php | 60 + .../WaterDrawingIntendedUses/view.php | 64 + .../WaterDrawingMeasurements/add.php | 51 + .../WaterDrawingMeasurements/index.php | 73 + .../templates/WaterDrawingMeters/add.php | 66 + .../templates/WaterDrawingMeters/dismiss.php | 67 + .../templates/WaterDrawingMeters/edit.php | 66 + .../templates/WaterDrawingMeters/view.php | 103 + .../WaterDrawingPaperworkPecs/add.php | 62 + .../WaterDrawingPaperworkPecs/edit.php | 62 + .../WaterDrawingPaperworkPecs/index.php | 81 + .../WaterDrawingPaperworkPecs/view.php | 61 + .../templates/WaterDrawingPaperworks/add.php | 632 + .../WaterDrawingPaperworks/add_scan.php | 49 + .../antimafia_request_to_anac.php | 49 + ...ts_water_drawing_paperworks_item_block.php | 5 + .../WaterDrawingPaperworks/assign.php | 48 + .../citizen_documentation_index.php | 115 + .../citizen_documentation_requested.php | 376 + .../citizen_request_paperwork.php | 35 + .../citizen_submission_index.php | 73 + .../citizen_submit_paperwork.php | 46 + .../citizen_upload_attachment.php | 60 + .../citizen_upload_payment_receipt.php | 58 + .../templates/WaterDrawingPaperworks/edit.php | 641 + .../WaterDrawingPaperworks/edit_scan.php | 667 + .../WaterDrawingPaperworks/index.php | 81 + .../index_snapshots.php | 80 + .../index_snapshots_all.php | 77 + ...es_water_drawing_paperworks_item_block.php | 1 + .../upload_antimafia_attachment.php | 49 + .../upload_attachment.php | 50 + .../upload_attachment_scan.php | 50 + .../WaterDrawingPaperworks/validate.php | 713 + .../WaterDrawingPaperworks/validate_index.php | 71 + .../WaterDrawingPaperworks/validate_scan.php | 728 + .../templates/WaterDrawingPaperworks/view.php | 768 + .../WaterDrawingPaperworks/view_scan.php | 727 + .../WaterDrawingPaperworks/view_snapshot.php | 641 + .../templates/WaterDrawingPayments/add.php | 93 + .../templates/WaterDrawingPayments/edit.php | 92 + .../templates/WaterDrawingPayments/index.php | 83 + .../templates/WaterDrawingPayments/view.php | 95 + .../WaterDrawingReturnPoints/add.php | 125 + .../WaterDrawingReturnPoints/edit.php | 124 + .../WaterDrawingReturnPoints/index.php | 54 + .../WaterDrawingReturnPoints/view.php | 128 + idrocap_wa/templates/cell/.gitkeep | 1 + .../cell/DistrictProvince/display.php | 41 + .../templates/cell/FilterInput/display.php | 12 + idrocap_wa/templates/cell/Filters/display.php | 152 + .../templates/cell/IntendedUses/display.php | 1 + idrocap_wa/templates/cell/Map/display.php | 13 + idrocap_wa/templates/element/Map.php | 622 + .../element/MapCore/MapPrimitives.php | 373 + .../WaterDrawingPaperworks/applicants.php | 196 + .../WaterDrawingPaperworks/intended_uses.php | 151 + .../templates/element/attachmentPreview.php | 41 + idrocap_wa/templates/element/attachments.php | 341 + .../templates/element/districtSelect.php | 210 + .../templates/element/flash/default.php | 15 + idrocap_wa/templates/element/flash/error.php | 11 + idrocap_wa/templates/element/flash/info.php | 11 + .../templates/element/flash/success.php | 11 + .../templates/element/flash/warning.php | 11 + .../templates/element/provinceSelect.php | 145 + idrocap_wa/templates/email/html/default.php | 22 + idrocap_wa/templates/email/text/default.php | 18 + idrocap_wa/templates/layout/ajax.php | 17 + idrocap_wa/templates/layout/default.php | 47 + .../templates/layout/email/html/default.php | 25 + .../templates/layout/email/text/default.php | 17 + idrocap_wa/templates/layout/error.php | 41 + idrocap_wa/templates/layout/view_public.php | 68 + .../BootstrapUI/element/flash/default.php | 30 + .../plugin/CakeLte/element/footer/main.php | 14 + .../plugin/CakeLte/element/header/main.php | 21 + .../plugin/CakeLte/element/header/menu.php | 2 + .../CakeLte/element/header/notifications.php | 51 + .../plugin/CakeLte/element/sidebar/main.php | 6 + .../plugin/CakeLte/element/sidebar/menu.php | 33 + .../plugin/CakeLte/layout/default.php | 108 + .../templates/plugin/CakeLte/layout/login.php | 111 + idrocap_wa/tests/Fixture/.gitkeep | 0 idrocap_wa/tests/TestCase/ApplicationTest.php | 85 + .../TestCase/Controller/Component/.gitkeep | 0 .../Controller/PagesControllerTest.php | 115 + .../tests/TestCase/Model/Behavior/.gitkeep | 0 .../tests/TestCase/View/Helper/.gitkeep | 0 idrocap_wa/tests/bootstrap.php | 66 + idrocap_wa/tests/schema.sql | 4 + idrocap_wa/webroot/.gitignore | 3 + idrocap_wa/webroot/.htaccess | 5 + idrocap_wa/webroot/adminlte | 1 + idrocap_wa/webroot/bower.json | 17 + idrocap_wa/webroot/css/cake.css | 299 + .../webroot/css/citizen-registration.css | 14 + idrocap_wa/webroot/css/fonts.css | 80 + idrocap_wa/webroot/css/home.css | 75 + idrocap_wa/webroot/css/idrocap-styles.css | 33 + idrocap_wa/webroot/css/jixel_ol.css | 66 + idrocap_wa/webroot/css/milligram.min.css | 9 + idrocap_wa/webroot/css/normalize.min.css | 8 + idrocap_wa/webroot/favicon.ico | Bin 0 -> 227390 bytes idrocap_wa/webroot/favicon2.ico | Bin 0 -> 15086 bytes idrocap_wa/webroot/font/Raleway-License.txt | 51 + .../webroot/font/cakedingbats-webfont.eot | Bin 0 -> 75538 bytes .../webroot/font/cakedingbats-webfont.svg | 78 + .../webroot/font/cakedingbats-webfont.ttf | Bin 0 -> 75412 bytes .../webroot/font/cakedingbats-webfont.woff | Bin 0 -> 43484 bytes .../webroot/font/cakedingbats-webfont.woff2 | Bin 0 -> 35456 bytes .../font/raleway-400-cyrillic-ext.woff2 | Bin 0 -> 22516 bytes .../webroot/font/raleway-400-cyrillic.woff2 | Bin 0 -> 21768 bytes .../webroot/font/raleway-400-latin-ext.woff2 | Bin 0 -> 25652 bytes .../webroot/font/raleway-400-latin.woff2 | Bin 0 -> 41852 bytes .../webroot/font/raleway-400-vietnamese.woff2 | Bin 0 -> 7648 bytes .../font/raleway-700-cyrillic-ext.woff2 | Bin 0 -> 22516 bytes .../webroot/font/raleway-700-cyrillic.woff2 | Bin 0 -> 21768 bytes .../webroot/font/raleway-700-latin-ext.woff2 | Bin 0 -> 25652 bytes .../webroot/font/raleway-700-latin.woff2 | Bin 0 -> 41852 bytes .../webroot/font/raleway-700-vietnamese.woff2 | Bin 0 -> 7648 bytes idrocap_wa/webroot/img/cake-logo.png | Bin 0 -> 2683 bytes idrocap_wa/webroot/img/cake.icon.png | Bin 0 -> 943 bytes idrocap_wa/webroot/img/cake.icon.svg | 7 + idrocap_wa/webroot/img/cake.logo.svg | 41 + idrocap_wa/webroot/img/cake.power.gif | Bin 0 -> 201 bytes .../webroot/img/logo-autorita-dibacino.png | Bin 0 -> 14539 bytes idrocap_wa/webroot/img/logo-fsc.png | Bin 0 -> 11329 bytes idrocap_wa/webroot/img/logo-poa.png | Bin 0 -> 13583 bytes .../webroot/img/logo-regione-sicilia.png | Bin 0 -> 379241 bytes idrocap_wa/webroot/img/logo_mite.png | Bin 0 -> 26664 bytes idrocap_wa/webroot/img/user2-160x160.jpg | Bin 0 -> 7070 bytes idrocap_wa/webroot/index.php | 37 + idrocap_wa/webroot/js/.gitkeep | 0 .../dist/entrypoints/content.js | 27 + .../utils/Autocomplete/AutocompleteHandler.js | 69 + .../entrypoints/utils/Clients/BaseClient.js | 38 + .../entrypoints/utils/Clients/OpenAIClient.js | 39 + .../entrypoints/utils/Clients/WgsAIClient.js | 10 + .../utils/Interfaces/PromptInterface.js | 1 + .../utils/Services/AutoCompleteService.js | 34 + .../dist/entrypoints/utils/TaskFlow.js | 15 + .../utils/Utility/DataFormatter.js | 55 + .../utils/Utility/DomElementHandler.js | 26 + .../entrypoints/utils/Utility/EventHandler.js | 5 + .../entrypoints/utils/Utility/FormAnalyzer.js | 137 + .../utils/Utility/FormExclusions.js | 25 + .../entrypoints/utils/Utility/FormFiller.js | 112 + .../js/ia-form-filler/styles/style.css | 228 + idrocap_wa/webroot/js/init_tiny_mce.js | 62 + idrocap_wa/webroot/js/jixel-primitives.js | 45 + idrocap_wa/webroot/js/moment.js | 5685 +++ .../js/tinymce/icons/default/icons.min.js | 1 + idrocap_wa/webroot/js/tinymce/langs/README.md | 3 + idrocap_wa/webroot/js/tinymce/langs/it.js | 1 + idrocap_wa/webroot/js/tinymce/license.md | 6 + .../js/tinymce/models/dom/model.min.js | 4 + .../tinymce/plugins/accordion/plugin.min.js | 4 + .../js/tinymce/plugins/advlist/plugin.min.js | 4 + .../js/tinymce/plugins/anchor/plugin.min.js | 4 + .../js/tinymce/plugins/autolink/plugin.min.js | 4 + .../tinymce/plugins/autoresize/plugin.min.js | 4 + .../js/tinymce/plugins/autosave/plugin.min.js | 4 + .../js/tinymce/plugins/charmap/plugin.min.js | 4 + .../js/tinymce/plugins/code/plugin.min.js | 4 + .../tinymce/plugins/codesample/plugin.min.js | 4 + .../plugins/directionality/plugin.min.js | 4 + .../plugins/emoticons/js/emojiimages.js | 1 + .../plugins/emoticons/js/emojiimages.min.js | 3 + .../js/tinymce/plugins/emoticons/js/emojis.js | 1 + .../plugins/emoticons/js/emojis.min.js | 2 + .../tinymce/plugins/emoticons/plugin.min.js | 4 + .../tinymce/plugins/fullscreen/plugin.min.js | 4 + .../tinymce/plugins/help/js/i18n/keynav/ar.js | 93 + .../plugins/help/js/i18n/keynav/bg_BG.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/ca.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/cs.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/da.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/de.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/el.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/en.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/es.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/eu.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/fa.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/fi.js | 93 + .../plugins/help/js/i18n/keynav/fr_FR.js | 93 + .../plugins/help/js/i18n/keynav/he_IL.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/hi.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/hr.js | 93 + .../plugins/help/js/i18n/keynav/hu_HU.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/id.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/it.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/ja.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/kk.js | 93 + .../plugins/help/js/i18n/keynav/ko_KR.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/ms.js | 93 + .../plugins/help/js/i18n/keynav/nb_NO.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/nl.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/pl.js | 93 + .../plugins/help/js/i18n/keynav/pt_BR.js | 93 + .../plugins/help/js/i18n/keynav/pt_PT.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/ro.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/ru.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/sk.js | 93 + .../plugins/help/js/i18n/keynav/sl_SI.js | 93 + .../plugins/help/js/i18n/keynav/sv_SE.js | 93 + .../plugins/help/js/i18n/keynav/th_TH.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/tr.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/uk.js | 93 + .../tinymce/plugins/help/js/i18n/keynav/vi.js | 93 + .../plugins/help/js/i18n/keynav/zh_CN.js | 87 + .../plugins/help/js/i18n/keynav/zh_TW.js | 93 + .../js/tinymce/plugins/help/plugin.min.js | 4 + .../js/tinymce/plugins/image/plugin.min.js | 4 + .../tinymce/plugins/importcss/plugin.min.js | 4 + .../plugins/insertdatetime/plugin.min.js | 4 + .../js/tinymce/plugins/link/plugin.min.js | 4 + .../js/tinymce/plugins/lists/plugin.min.js | 4 + .../js/tinymce/plugins/media/plugin.min.js | 4 + .../tinymce/plugins/nonbreaking/plugin.min.js | 4 + .../tinymce/plugins/pagebreak/plugin.min.js | 4 + .../js/tinymce/plugins/preview/plugin.min.js | 4 + .../tinymce/plugins/quickbars/plugin.min.js | 4 + .../js/tinymce/plugins/save/plugin.min.js | 4 + .../plugins/searchreplace/plugin.min.js | 4 + .../js/tinymce/plugins/table/plugin.min.js | 4 + .../plugins/visualblocks/plugin.min.js | 4 + .../tinymce/plugins/visualchars/plugin.min.js | 4 + .../tinymce/plugins/wordcount/plugin.min.js | 4 + .../js/tinymce/skins/content/dark/content.js | 1 + .../skins/content/dark/content.min.css | 1 + .../tinymce/skins/content/default/content.js | 1 + .../skins/content/default/content.min.css | 1 + .../tinymce/skins/content/document/content.js | 1 + .../skins/content/document/content.min.css | 1 + .../skins/content/tinymce-5-dark/content.js | 1 + .../content/tinymce-5-dark/content.min.css | 1 + .../skins/content/tinymce-5/content.js | 1 + .../skins/content/tinymce-5/content.min.css | 1 + .../tinymce/skins/content/writer/content.js | 1 + .../skins/content/writer/content.min.css | 1 + .../skins/ui/oxide-dark/content.inline.js | 1 + .../ui/oxide-dark/content.inline.min.css | 1 + .../js/tinymce/skins/ui/oxide-dark/content.js | 1 + .../skins/ui/oxide-dark/content.min.css | 1 + .../js/tinymce/skins/ui/oxide-dark/skin.js | 1 + .../tinymce/skins/ui/oxide-dark/skin.min.css | 1 + .../skins/ui/oxide-dark/skin.shadowdom.js | 1 + .../ui/oxide-dark/skin.shadowdom.min.css | 1 + .../tinymce/skins/ui/oxide/content.inline.js | 1 + .../skins/ui/oxide/content.inline.min.css | 1 + .../js/tinymce/skins/ui/oxide/content.js | 1 + .../js/tinymce/skins/ui/oxide/content.min.css | 1 + .../webroot/js/tinymce/skins/ui/oxide/skin.js | 1 + .../js/tinymce/skins/ui/oxide/skin.min.css | 1 + .../tinymce/skins/ui/oxide/skin.shadowdom.js | 1 + .../skins/ui/oxide/skin.shadowdom.min.css | 1 + .../skins/ui/tinymce-5-dark/content.inline.js | 1 + .../ui/tinymce-5-dark/content.inline.min.css | 1 + .../skins/ui/tinymce-5-dark/content.js | 1 + .../skins/ui/tinymce-5-dark/content.min.css | 1 + .../tinymce/skins/ui/tinymce-5-dark/skin.js | 1 + .../skins/ui/tinymce-5-dark/skin.min.css | 1 + .../skins/ui/tinymce-5-dark/skin.shadowdom.js | 1 + .../ui/tinymce-5-dark/skin.shadowdom.min.css | 1 + .../skins/ui/tinymce-5/content.inline.js | 1 + .../skins/ui/tinymce-5/content.inline.min.css | 1 + .../js/tinymce/skins/ui/tinymce-5/content.js | 1 + .../skins/ui/tinymce-5/content.min.css | 1 + .../js/tinymce/skins/ui/tinymce-5/skin.js | 1 + .../tinymce/skins/ui/tinymce-5/skin.min.css | 1 + .../skins/ui/tinymce-5/skin.shadowdom.js | 1 + .../skins/ui/tinymce-5/skin.shadowdom.min.css | 1 + .../js/tinymce/themes/silver/theme.min.js | 4 + idrocap_wa/webroot/js/tinymce/tinymce.d.ts | 3254 ++ idrocap_wa/webroot/js/tinymce/tinymce.min.js | 4 + idrocap_wa/webroot/ol-ext/extra/Cloud.js | 196 + .../webroot/ol-ext/extra/Exif2Geojson.js | 76 + idrocap_wa/webroot/ol-ext/extra/ExportMap.js | 84 + .../webroot/ol-ext/extra/FontAwesome5Def.js | 681 + .../webroot/ol-ext/extra/FontAwesomeDef.js | 681 + .../webroot/ol-ext/extra/FontMaki2Def.js | 171 + .../webroot/ol-ext/extra/FontMakiDef.js | 131 + idrocap_wa/webroot/ol-ext/extra/IFrameAPI.js | 107 + .../webroot/ol-ext/extra/MapIFrameAPI.js | 159 + .../webroot/ol-ext/extra/TextureImage.js | 16 + idrocap_wa/webroot/ol-ext/extra/WSynchro.js | 71 + idrocap_wa/webroot/ol-ext/ol-ext.css | 6828 +++ idrocap_wa/webroot/ol-ext/ol-ext.js | 42128 ++++++++++++++++ idrocap_wa/webroot/ol-ext/ol-ext.min.css | 1 + idrocap_wa/webroot/ol-ext/ol-ext.min.js | 9 + idrocap_wa/webroot/package-lock.json | 443 + idrocap_wa/webroot/package.json | 5 + .../webroot/sounds/all_notification_read.mp3 | Bin 0 -> 116192 bytes .../webroot/sounds/new_notification.mp3 | Bin 0 -> 108669 bytes 673 files changed, 126346 insertions(+), 1 deletion(-) create mode 100644 idrocap_wa/.htaccess create mode 100644 idrocap_wa/Dockerfile create mode 100644 idrocap_wa/README.md create mode 100644 idrocap_wa/bin/bash_completion.sh create mode 100755 idrocap_wa/bin/cake create mode 100644 idrocap_wa/bin/cake.bat create mode 100644 idrocap_wa/bin/cake.php create mode 100644 idrocap_wa/composer.json create mode 100644 idrocap_wa/composer.lock create mode 100644 idrocap_wa/config/.env.example create mode 100644 idrocap_wa/config/app.php create mode 100644 idrocap_wa/config/app_local.example.php create mode 100644 idrocap_wa/config/app_local.php create mode 100644 idrocap_wa/config/bootstrap.php create mode 100644 idrocap_wa/config/bootstrap_cli.php create mode 100644 idrocap_wa/config/cakelte.php create mode 100644 idrocap_wa/config/keys/private.key create mode 100644 idrocap_wa/config/keys/public.key create mode 100644 idrocap_wa/config/paths.php create mode 100644 idrocap_wa/config/plugins.php create mode 100644 idrocap_wa/config/routes.php create mode 100644 idrocap_wa/config/schema/i18n.sql create mode 100644 idrocap_wa/config/schema/sessions.sql create mode 100755 idrocap_wa/dockerfiles/cake create mode 100755 idrocap_wa/dockerfiles/run create mode 100644 idrocap_wa/dockerfiles/www.conf create mode 100644 idrocap_wa/index.php create mode 100755 idrocap_wa/jixel-background-task-handler/Dockerfile create mode 100755 idrocap_wa/jixel-background-task-handler/jbth.py create mode 100755 idrocap_wa/jixel-background-task-handler/jbth.sh create mode 100755 idrocap_wa/jixel-background-task-handler/jgprc.py create mode 100755 idrocap_wa/jixel-background-task-handler/jgprc.sh create mode 100755 idrocap_wa/jixel-background-task-handler/jixel-background-task-handler.sh create mode 100644 idrocap_wa/jixel-background-task-handler/jixel-cron.log create mode 100755 idrocap_wa/jixel-background-task-handler/jixel-cron.sh create mode 100644 idrocap_wa/jixel-background-task-handler/jixel-cron.txt create mode 100755 idrocap_wa/jixel-background-task-handler/jixel-general-purpose-rabbit-consumer.sh create mode 100644 idrocap_wa/phpcs.xml create mode 100644 idrocap_wa/phpstan.neon create mode 100644 idrocap_wa/phpunit.xml.dist create mode 100644 idrocap_wa/plugins/.gitkeep create mode 100644 idrocap_wa/psalm.xml create mode 100644 idrocap_wa/resources/.gitkeep create mode 100644 idrocap_wa/resources/locales/cake.pot create mode 100644 idrocap_wa/resources/locales/default.pot create mode 100644 idrocap_wa/resources/locales/en/default.po create mode 100644 idrocap_wa/resources/locales/en/previous_default.po create mode 100644 idrocap_wa/resources/locales/it/cake.po create mode 100644 idrocap_wa/src/Application.php create mode 100644 idrocap_wa/src/Command/AddCadastralCodeToUsesCommand.php create mode 100644 idrocap_wa/src/Command/AddDerivationCoordinatesCommand.php create mode 100644 idrocap_wa/src/Command/CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand.php create mode 100644 idrocap_wa/src/Command/CopyTranslationsCommand.php create mode 100644 idrocap_wa/src/Command/IntendedUseVegetationCheckCommand.php create mode 100644 idrocap_wa/src/Command/NormalizeApplicantProvinceCommand.php create mode 100644 idrocap_wa/src/Command/NotificationsHandlerCommand.php create mode 100644 idrocap_wa/src/Command/UnpackWaterDrawingPaperworkSnapshotsCommand.php create mode 100644 idrocap_wa/src/Console/Installer.php create mode 100644 idrocap_wa/src/Controller/AiServicesController.php create mode 100644 idrocap_wa/src/Controller/Api/AppController.php create mode 100644 idrocap_wa/src/Controller/Api/AttachmentsController.php create mode 100644 idrocap_wa/src/Controller/Api/ErrorController.php create mode 100644 idrocap_wa/src/Controller/Api/NotificationsController.php create mode 100644 idrocap_wa/src/Controller/Api/OrganisationTypesController.php create mode 100644 idrocap_wa/src/Controller/Api/OrganisationsController.php create mode 100644 idrocap_wa/src/Controller/Api/SubscriptionsController.php create mode 100644 idrocap_wa/src/Controller/Api/UsersController.php create mode 100644 idrocap_wa/src/Controller/Api/WaterDrawingDerivationsController.php create mode 100644 idrocap_wa/src/Controller/Api/WaterDrawingMeasurementsController.php create mode 100644 idrocap_wa/src/Controller/Api/WaterDrawingPaperworksController.php create mode 100644 idrocap_wa/src/Controller/AppController.php create mode 100644 idrocap_wa/src/Controller/ApplicantsController.php create mode 100644 idrocap_wa/src/Controller/AttachmentsController.php create mode 100644 idrocap_wa/src/Controller/CapabilitiesController.php create mode 100644 idrocap_wa/src/Controller/Component/.gitkeep create mode 100644 idrocap_wa/src/Controller/Component/StreamableCsvExportTrait.php create mode 100644 idrocap_wa/src/Controller/ControllableObjectsController.php create mode 100644 idrocap_wa/src/Controller/DashboardController.php create mode 100644 idrocap_wa/src/Controller/DeliveriesController.php create mode 100644 idrocap_wa/src/Controller/DistrictsController.php create mode 100644 idrocap_wa/src/Controller/EmailsController.php create mode 100644 idrocap_wa/src/Controller/ErrorController.php create mode 100644 idrocap_wa/src/Controller/FaxesController.php create mode 100644 idrocap_wa/src/Controller/FiltersController.php create mode 100644 idrocap_wa/src/Controller/GroupsController.php create mode 100644 idrocap_wa/src/Controller/MapsController.php create mode 100644 idrocap_wa/src/Controller/MobilePhonesController.php create mode 100644 idrocap_wa/src/Controller/NotificationsController.php create mode 100644 idrocap_wa/src/Controller/OrganisationsController.php create mode 100644 idrocap_wa/src/Controller/PecsController.php create mode 100644 idrocap_wa/src/Controller/PhonesController.php create mode 100644 idrocap_wa/src/Controller/PrivacyController.php create mode 100644 idrocap_wa/src/Controller/TagsController.php create mode 100644 idrocap_wa/src/Controller/TelegramChatsController.php create mode 100644 idrocap_wa/src/Controller/UsersController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingArticlesController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingDerivationsController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingFeesController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingIntendedUsesController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingMeasurementsController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingMetersController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingPaperworkPecsController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingPaperworksController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingPaymentsController.php create mode 100644 idrocap_wa/src/Controller/WaterDrawingReturnPointsController.php create mode 100755 idrocap_wa/src/Error/AppExceptionRenderer.php create mode 100644 idrocap_wa/src/Identifier/JixelPasswordIdentifier.php create mode 100644 idrocap_wa/src/Middleware/UserTimezoneDatetimeRequestDataMiddleware.php create mode 100644 idrocap_wa/src/Model/Behavior/.gitkeep create mode 100644 idrocap_wa/src/Model/Behavior/AttachmentsBehavior.php create mode 100644 idrocap_wa/src/Model/Behavior/ControllableObjectInterfaceBehavior.php create mode 100644 idrocap_wa/src/Model/Entity/Actor.php create mode 100644 idrocap_wa/src/Model/Entity/ActorType.php create mode 100644 idrocap_wa/src/Model/Entity/Applicant.php create mode 100644 idrocap_wa/src/Model/Entity/ApplicantsWaterDrawingPaperwork.php create mode 100644 idrocap_wa/src/Model/Entity/Attachment.php create mode 100644 idrocap_wa/src/Model/Entity/BackgroundTask.php create mode 100644 idrocap_wa/src/Model/Entity/CadastralCropType.php create mode 100644 idrocap_wa/src/Model/Entity/CapabilitiesMenuItem.php create mode 100644 idrocap_wa/src/Model/Entity/CapabilitiesMenuSection.php create mode 100644 idrocap_wa/src/Model/Entity/Capability.php create mode 100644 idrocap_wa/src/Model/Entity/CapabilityGroup.php create mode 100644 idrocap_wa/src/Model/Entity/ControllableObject.php create mode 100644 idrocap_wa/src/Model/Entity/ControllableObjectInterface.php create mode 100644 idrocap_wa/src/Model/Entity/ControllableObjectInterfaceType.php create mode 100644 idrocap_wa/src/Model/Entity/ControllableObjectType.php create mode 100644 idrocap_wa/src/Model/Entity/County.php create mode 100644 idrocap_wa/src/Model/Entity/Delivery.php create mode 100644 idrocap_wa/src/Model/Entity/DeliveryType.php create mode 100644 idrocap_wa/src/Model/Entity/DispatchingTask.php create mode 100644 idrocap_wa/src/Model/Entity/DispatchingTaskItem.php create mode 100644 idrocap_wa/src/Model/Entity/DispatchingTaskStatus.php create mode 100644 idrocap_wa/src/Model/Entity/District.php create mode 100644 idrocap_wa/src/Model/Entity/Email.php create mode 100644 idrocap_wa/src/Model/Entity/EmailDescription.php create mode 100644 idrocap_wa/src/Model/Entity/Fax.php create mode 100644 idrocap_wa/src/Model/Entity/FaxDescription.php create mode 100644 idrocap_wa/src/Model/Entity/Filter.php create mode 100644 idrocap_wa/src/Model/Entity/Group.php create mode 100644 idrocap_wa/src/Model/Entity/GroupsGroup.php create mode 100644 idrocap_wa/src/Model/Entity/Language.php create mode 100644 idrocap_wa/src/Model/Entity/Location.php create mode 100644 idrocap_wa/src/Model/Entity/LocationAttribute.php create mode 100644 idrocap_wa/src/Model/Entity/Map.php create mode 100644 idrocap_wa/src/Model/Entity/MenuItem.php create mode 100644 idrocap_wa/src/Model/Entity/MenuSection.php create mode 100644 idrocap_wa/src/Model/Entity/Message.php create mode 100644 idrocap_wa/src/Model/Entity/MessageStatus.php create mode 100644 idrocap_wa/src/Model/Entity/MessageType.php create mode 100644 idrocap_wa/src/Model/Entity/MobileComponent.php create mode 100644 idrocap_wa/src/Model/Entity/MobilePhone.php create mode 100644 idrocap_wa/src/Model/Entity/MobilePhoneDescription.php create mode 100644 idrocap_wa/src/Model/Entity/Notification.php create mode 100644 idrocap_wa/src/Model/Entity/NotificationType.php create mode 100644 idrocap_wa/src/Model/Entity/Organisation.php create mode 100644 idrocap_wa/src/Model/Entity/OrganisationType.php create mode 100644 idrocap_wa/src/Model/Entity/Pec.php create mode 100644 idrocap_wa/src/Model/Entity/PecDescription.php create mode 100644 idrocap_wa/src/Model/Entity/Permission.php create mode 100644 idrocap_wa/src/Model/Entity/Phone.php create mode 100644 idrocap_wa/src/Model/Entity/PhoneDescription.php create mode 100644 idrocap_wa/src/Model/Entity/Privacy.php create mode 100644 idrocap_wa/src/Model/Entity/PrivacyUser.php create mode 100644 idrocap_wa/src/Model/Entity/PushNotification.php create mode 100644 idrocap_wa/src/Model/Entity/Snapshot.php create mode 100644 idrocap_wa/src/Model/Entity/Tag.php create mode 100644 idrocap_wa/src/Model/Entity/TelegramChat.php create mode 100644 idrocap_wa/src/Model/Entity/TelegramContact.php create mode 100644 idrocap_wa/src/Model/Entity/UnpackedWaterDrawingPaperworkSnapshot.php create mode 100644 idrocap_wa/src/Model/Entity/User.php create mode 100644 idrocap_wa/src/Model/Entity/UserTimezoneDatetimeEntityTrait.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequest.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequestStatus.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingArticle.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingDerivation.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingDerivationType.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingFee.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingIntendedUse.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingIntendedUseType.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingMeasurement.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingMeter.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingPaperwork.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingPaperworkHistory.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingPaperworkPec.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingPaperworkStatus.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingPayment.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingPaymentType.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingReturnPoint.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingToolType.php create mode 100644 idrocap_wa/src/Model/Entity/WaterDrawingWateringSystem.php create mode 100644 idrocap_wa/src/Model/Table/ActorTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/ActorsTable.php create mode 100644 idrocap_wa/src/Model/Table/ApplicantsTable.php create mode 100644 idrocap_wa/src/Model/Table/ApplicantsWaterDrawingPaperworksTable.php create mode 100644 idrocap_wa/src/Model/Table/AttachmentsTable.php create mode 100644 idrocap_wa/src/Model/Table/BackgroundTasksTable.php create mode 100644 idrocap_wa/src/Model/Table/CadastralCropTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/CapabilitiesMenuItemsTable.php create mode 100644 idrocap_wa/src/Model/Table/CapabilitiesMenuSectionsTable.php create mode 100644 idrocap_wa/src/Model/Table/CapabilitiesTable.php create mode 100644 idrocap_wa/src/Model/Table/CapabilityGroupsTable.php create mode 100644 idrocap_wa/src/Model/Table/ControllableObjectInterfaceTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/ControllableObjectInterfacesTable.php create mode 100644 idrocap_wa/src/Model/Table/ControllableObjectTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/ControllableObjectsTable.php create mode 100644 idrocap_wa/src/Model/Table/CountiesTable.php create mode 100644 idrocap_wa/src/Model/Table/DeliveriesTable.php create mode 100644 idrocap_wa/src/Model/Table/DeliveryTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/DispatchingTaskItemsTable.php create mode 100644 idrocap_wa/src/Model/Table/DispatchingTaskStatusesTable.php create mode 100644 idrocap_wa/src/Model/Table/DispatchingTasksTable.php create mode 100644 idrocap_wa/src/Model/Table/DistrictsTable.php create mode 100644 idrocap_wa/src/Model/Table/EmailDescriptionsTable.php create mode 100644 idrocap_wa/src/Model/Table/EmailsTable.php create mode 100644 idrocap_wa/src/Model/Table/FaxDescriptionsTable.php create mode 100644 idrocap_wa/src/Model/Table/FaxesTable.php create mode 100644 idrocap_wa/src/Model/Table/FiltersTable.php create mode 100644 idrocap_wa/src/Model/Table/GroupsGroupsTable.php create mode 100644 idrocap_wa/src/Model/Table/GroupsTable.php create mode 100644 idrocap_wa/src/Model/Table/LanguagesTable.php create mode 100644 idrocap_wa/src/Model/Table/LocationAttributesTable.php create mode 100644 idrocap_wa/src/Model/Table/LocationsTable.php create mode 100644 idrocap_wa/src/Model/Table/MapsTable.php create mode 100644 idrocap_wa/src/Model/Table/MenuItemsTable.php create mode 100644 idrocap_wa/src/Model/Table/MenuSectionsTable.php create mode 100644 idrocap_wa/src/Model/Table/MessageStatusesTable.php create mode 100644 idrocap_wa/src/Model/Table/MessageTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/MessagesTable.php create mode 100644 idrocap_wa/src/Model/Table/MobileComponentsTable.php create mode 100644 idrocap_wa/src/Model/Table/MobilePhoneDescriptionsTable.php create mode 100644 idrocap_wa/src/Model/Table/MobilePhonesTable.php create mode 100644 idrocap_wa/src/Model/Table/NotificationTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/NotificationsTable.php create mode 100644 idrocap_wa/src/Model/Table/OrganisationTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/OrganisationsTable.php create mode 100644 idrocap_wa/src/Model/Table/PecDescriptionsTable.php create mode 100644 idrocap_wa/src/Model/Table/PecsTable.php create mode 100644 idrocap_wa/src/Model/Table/PermissionsTable.php create mode 100644 idrocap_wa/src/Model/Table/PhoneDescriptionsTable.php create mode 100644 idrocap_wa/src/Model/Table/PhonesTable.php create mode 100644 idrocap_wa/src/Model/Table/PrivacyTable.php create mode 100644 idrocap_wa/src/Model/Table/PrivacyUsersTable.php create mode 100644 idrocap_wa/src/Model/Table/PushNotificationsTable.php create mode 100644 idrocap_wa/src/Model/Table/SnapshotsTable.php create mode 100644 idrocap_wa/src/Model/Table/TagsTable.php create mode 100644 idrocap_wa/src/Model/Table/TelegramChatsTable.php create mode 100644 idrocap_wa/src/Model/Table/TelegramContactsTable.php create mode 100644 idrocap_wa/src/Model/Table/UnpackedWaterDrawingPaperworkSnapshotsTable.php create mode 100644 idrocap_wa/src/Model/Table/UsersTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestStatusesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestsTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingArticlesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingDerivationTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingDerivationsTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingFeesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingIntendedUseTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingIntendedUsesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingMeasurementsTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingMetersTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingPaperworkHistoriesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingPaperworkPecsTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingPaperworkStatusesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingPaperworksTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingPaymentTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingPaymentsTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingReturnPointsTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingToolTypesTable.php create mode 100644 idrocap_wa/src/Model/Table/WaterDrawingWateringSystemsTable.php create mode 100644 idrocap_wa/src/View/AjaxView.php create mode 100644 idrocap_wa/src/View/AppView.php create mode 100644 idrocap_wa/src/View/Cell/.gitkeep create mode 100644 idrocap_wa/src/View/Cell/DistrictProvinceCell.php create mode 100644 idrocap_wa/src/View/Cell/FilterInputCell.php create mode 100755 idrocap_wa/src/View/Cell/FiltersCell.php create mode 100644 idrocap_wa/src/View/Cell/IntendedUsesCell.php create mode 100755 idrocap_wa/src/View/Cell/MapCell.php create mode 100644 idrocap_wa/src/View/CustomCsvView.php create mode 100644 idrocap_wa/src/View/Helper/BreadcrumbHelper.php create mode 100644 idrocap_wa/src/View/Helper/MenuHelper.php create mode 100644 idrocap_wa/src/View/Helper/NotificationsHelper.php create mode 100644 idrocap_wa/src/View/Helper/SectionsHelper.php create mode 100644 idrocap_wa/src/WGS/Auth/OpenIdConnectClient.php create mode 100755 idrocap_wa/src/WGS/FileStorage/FileStorage.php create mode 100755 idrocap_wa/src/WGS/FileStorage/FileStorageFactory.php create mode 100755 idrocap_wa/src/WGS/FileStorage/HadoopFileStorage.php create mode 100755 idrocap_wa/src/WGS/FileStorage/S3MinioFileStorage.php create mode 100644 idrocap_wa/src/WGS/Geo/CadastralUtils.php create mode 100644 idrocap_wa/src/WGS/Geo/ExtGeoResourceAttributesRetriever.php create mode 100644 idrocap_wa/src/WGS/Geo/GeoValidation.php create mode 100644 idrocap_wa/src/WGS/Geo/Geocoding.php create mode 100644 idrocap_wa/src/WGS/Geo/IntGeoResourceAttributesRetriever.php create mode 100644 idrocap_wa/src/WGS/Geo/LocationAttributesRetriever.php create mode 100644 idrocap_wa/src/WGS/NotificationsHandler/MessagingHandler.php create mode 100644 idrocap_wa/src/WGS/NotificationsHandler/NotificationGenerator.php create mode 100644 idrocap_wa/src/WGS/NotificationsHandler/NotificationsHandler.php create mode 100644 idrocap_wa/src/WGS/NotificationsHandler/RecipientsDetector.php create mode 100644 idrocap_wa/src/WGS/NotificationsHandler/SystemNotificationsDispatcher.php create mode 100644 idrocap_wa/src/WGS/SnapshotsHandler/SnapshotsHandler.php create mode 100644 idrocap_wa/src/WGS/Utils/Attachments/AttachmentChecker.php create mode 100644 idrocap_wa/src/WGS/Utils/Attachments/AttachmentConverter.php create mode 100644 idrocap_wa/src/WGS/Utils/Attachments/SignedAttachmentChecker.php create mode 100644 idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/DistrictCellDto.php create mode 100644 idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/ProvinceCellDto.php create mode 100644 idrocap_wa/src/WGS/Utils/Dto/Users/CitizenRegistrationDTO.php create mode 100644 idrocap_wa/src/WGS/Utils/Enum/InputFieldType.php create mode 100644 idrocap_wa/src/WGS/Utils/Enum/ProvinceDistrictFields.php create mode 100644 idrocap_wa/src/WGS/Utils/Enum/Regions.php create mode 100644 idrocap_wa/src/WGS/Utils/Enum/SicilyProvinces.php create mode 100644 idrocap_wa/src/WGS/Utils/Helper/ProvinceDistrictFieldHelper.php create mode 100644 idrocap_wa/src/WGS/Utils/RabbitMQSenders/IntendedUseVegetationCheckCommandSender.php create mode 100644 idrocap_wa/templates/Applicants/citizen_add.php create mode 100644 idrocap_wa/templates/Applicants/citizen_edit.php create mode 100644 idrocap_wa/templates/Applicants/citizen_view.php create mode 100644 idrocap_wa/templates/Applicants/edit.php create mode 100644 idrocap_wa/templates/Applicants/view.php create mode 100644 idrocap_wa/templates/Capabilities/index.php create mode 100755 idrocap_wa/templates/ControllableObjects/get_attachments.php create mode 100644 idrocap_wa/templates/Dashboard/index.php create mode 100644 idrocap_wa/templates/Deliveries/index.php create mode 100644 idrocap_wa/templates/Emails/add.php create mode 100644 idrocap_wa/templates/Emails/edit.php create mode 100644 idrocap_wa/templates/Error/error400.php create mode 100644 idrocap_wa/templates/Error/error500.php create mode 100644 idrocap_wa/templates/Faxes/add.php create mode 100644 idrocap_wa/templates/Faxes/edit.php create mode 100644 idrocap_wa/templates/Filters/get_filter_input.php create mode 100644 idrocap_wa/templates/Groups/add.php create mode 100644 idrocap_wa/templates/Groups/edit.php create mode 100644 idrocap_wa/templates/Groups/handle_capabilities.php create mode 100644 idrocap_wa/templates/Groups/index.php create mode 100644 idrocap_wa/templates/Groups/view.php create mode 100644 idrocap_wa/templates/Maps/index.php create mode 100644 idrocap_wa/templates/MobilePhones/add.php create mode 100644 idrocap_wa/templates/MobilePhones/edit.php create mode 100644 idrocap_wa/templates/Notifications/index.php create mode 100644 idrocap_wa/templates/Notifications/read_all.php create mode 100644 idrocap_wa/templates/Organisations/add.php create mode 100644 idrocap_wa/templates/Organisations/edit.php create mode 100644 idrocap_wa/templates/Organisations/index.php create mode 100644 idrocap_wa/templates/Organisations/view.php create mode 100644 idrocap_wa/templates/Pecs/add.php create mode 100644 idrocap_wa/templates/Pecs/edit.php create mode 100644 idrocap_wa/templates/Phones/add.php create mode 100644 idrocap_wa/templates/Phones/edit.php create mode 100644 idrocap_wa/templates/Privacy/accept_privacy.php create mode 100644 idrocap_wa/templates/Privacy/edit.php create mode 100644 idrocap_wa/templates/Privacy/view.php create mode 100644 idrocap_wa/templates/Privacy/view_public.php create mode 100644 idrocap_wa/templates/Tags/add.php create mode 100644 idrocap_wa/templates/Tags/edit.php create mode 100644 idrocap_wa/templates/Tags/index.php create mode 100644 idrocap_wa/templates/Tags/view.php create mode 100644 idrocap_wa/templates/TelegramChats/add.php create mode 100644 idrocap_wa/templates/TelegramChats/edit.php create mode 100644 idrocap_wa/templates/Users/add.php create mode 100644 idrocap_wa/templates/Users/add_citizen.php create mode 100644 idrocap_wa/templates/Users/choose_new_password.php create mode 100644 idrocap_wa/templates/Users/edit.php create mode 100644 idrocap_wa/templates/Users/index.php create mode 100644 idrocap_wa/templates/Users/login.php create mode 100644 idrocap_wa/templates/Users/one_time_password.php create mode 100644 idrocap_wa/templates/Users/password_recovery.php create mode 100644 idrocap_wa/templates/Users/view.php create mode 100644 idrocap_wa/templates/WaterDrawingArticles/add.php create mode 100644 idrocap_wa/templates/WaterDrawingArticles/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingArticles/index.php create mode 100644 idrocap_wa/templates/WaterDrawingArticles/view.php create mode 100644 idrocap_wa/templates/WaterDrawingDerivations/add.php create mode 100644 idrocap_wa/templates/WaterDrawingDerivations/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingDerivations/index.php create mode 100644 idrocap_wa/templates/WaterDrawingDerivations/view.php create mode 100644 idrocap_wa/templates/WaterDrawingFees/add.php create mode 100644 idrocap_wa/templates/WaterDrawingFees/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingFees/index.php create mode 100644 idrocap_wa/templates/WaterDrawingFees/view.php create mode 100644 idrocap_wa/templates/WaterDrawingIntendedUses/add.php create mode 100644 idrocap_wa/templates/WaterDrawingIntendedUses/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingIntendedUses/index.php create mode 100644 idrocap_wa/templates/WaterDrawingIntendedUses/view.php create mode 100644 idrocap_wa/templates/WaterDrawingMeasurements/add.php create mode 100644 idrocap_wa/templates/WaterDrawingMeasurements/index.php create mode 100644 idrocap_wa/templates/WaterDrawingMeters/add.php create mode 100644 idrocap_wa/templates/WaterDrawingMeters/dismiss.php create mode 100644 idrocap_wa/templates/WaterDrawingMeters/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingMeters/view.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworkPecs/add.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworkPecs/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworkPecs/index.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworkPecs/view.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/add.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/add_scan.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/antimafia_request_to_anac.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/applicants_water_drawing_paperworks_item_block.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/assign.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_index.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_requested.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/citizen_request_paperwork.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/citizen_submission_index.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/citizen_submit_paperwork.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_attachment.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_payment_receipt.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/edit_scan.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/index.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots_all.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/intended_uses_water_drawing_paperworks_item_block.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/upload_antimafia_attachment.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment_scan.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/validate.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/validate_index.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/validate_scan.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/view.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/view_scan.php create mode 100644 idrocap_wa/templates/WaterDrawingPaperworks/view_snapshot.php create mode 100644 idrocap_wa/templates/WaterDrawingPayments/add.php create mode 100644 idrocap_wa/templates/WaterDrawingPayments/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingPayments/index.php create mode 100644 idrocap_wa/templates/WaterDrawingPayments/view.php create mode 100644 idrocap_wa/templates/WaterDrawingReturnPoints/add.php create mode 100644 idrocap_wa/templates/WaterDrawingReturnPoints/edit.php create mode 100644 idrocap_wa/templates/WaterDrawingReturnPoints/index.php create mode 100644 idrocap_wa/templates/WaterDrawingReturnPoints/view.php create mode 100644 idrocap_wa/templates/cell/.gitkeep create mode 100644 idrocap_wa/templates/cell/DistrictProvince/display.php create mode 100644 idrocap_wa/templates/cell/FilterInput/display.php create mode 100755 idrocap_wa/templates/cell/Filters/display.php create mode 100644 idrocap_wa/templates/cell/IntendedUses/display.php create mode 100755 idrocap_wa/templates/cell/Map/display.php create mode 100755 idrocap_wa/templates/element/Map.php create mode 100644 idrocap_wa/templates/element/MapCore/MapPrimitives.php create mode 100644 idrocap_wa/templates/element/WaterDrawingPaperworks/applicants.php create mode 100644 idrocap_wa/templates/element/WaterDrawingPaperworks/intended_uses.php create mode 100755 idrocap_wa/templates/element/attachmentPreview.php create mode 100755 idrocap_wa/templates/element/attachments.php create mode 100644 idrocap_wa/templates/element/districtSelect.php create mode 100644 idrocap_wa/templates/element/flash/default.php create mode 100644 idrocap_wa/templates/element/flash/error.php create mode 100644 idrocap_wa/templates/element/flash/info.php create mode 100644 idrocap_wa/templates/element/flash/success.php create mode 100644 idrocap_wa/templates/element/flash/warning.php create mode 100644 idrocap_wa/templates/element/provinceSelect.php create mode 100644 idrocap_wa/templates/email/html/default.php create mode 100644 idrocap_wa/templates/email/text/default.php create mode 100644 idrocap_wa/templates/layout/ajax.php create mode 100644 idrocap_wa/templates/layout/default.php create mode 100644 idrocap_wa/templates/layout/email/html/default.php create mode 100644 idrocap_wa/templates/layout/email/text/default.php create mode 100644 idrocap_wa/templates/layout/error.php create mode 100644 idrocap_wa/templates/layout/view_public.php create mode 100644 idrocap_wa/templates/plugin/BootstrapUI/element/flash/default.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/element/footer/main.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/element/header/main.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/element/header/menu.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/element/header/notifications.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/element/sidebar/main.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/element/sidebar/menu.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/layout/default.php create mode 100644 idrocap_wa/templates/plugin/CakeLte/layout/login.php create mode 100644 idrocap_wa/tests/Fixture/.gitkeep create mode 100644 idrocap_wa/tests/TestCase/ApplicationTest.php create mode 100644 idrocap_wa/tests/TestCase/Controller/Component/.gitkeep create mode 100644 idrocap_wa/tests/TestCase/Controller/PagesControllerTest.php create mode 100644 idrocap_wa/tests/TestCase/Model/Behavior/.gitkeep create mode 100644 idrocap_wa/tests/TestCase/View/Helper/.gitkeep create mode 100644 idrocap_wa/tests/bootstrap.php create mode 100644 idrocap_wa/tests/schema.sql create mode 100644 idrocap_wa/webroot/.gitignore create mode 100644 idrocap_wa/webroot/.htaccess create mode 120000 idrocap_wa/webroot/adminlte create mode 100644 idrocap_wa/webroot/bower.json create mode 100644 idrocap_wa/webroot/css/cake.css create mode 100644 idrocap_wa/webroot/css/citizen-registration.css create mode 100644 idrocap_wa/webroot/css/fonts.css create mode 100644 idrocap_wa/webroot/css/home.css create mode 100644 idrocap_wa/webroot/css/idrocap-styles.css create mode 100644 idrocap_wa/webroot/css/jixel_ol.css create mode 100644 idrocap_wa/webroot/css/milligram.min.css create mode 100644 idrocap_wa/webroot/css/normalize.min.css create mode 100644 idrocap_wa/webroot/favicon.ico create mode 100644 idrocap_wa/webroot/favicon2.ico create mode 100644 idrocap_wa/webroot/font/Raleway-License.txt create mode 100644 idrocap_wa/webroot/font/cakedingbats-webfont.eot create mode 100644 idrocap_wa/webroot/font/cakedingbats-webfont.svg create mode 100644 idrocap_wa/webroot/font/cakedingbats-webfont.ttf create mode 100644 idrocap_wa/webroot/font/cakedingbats-webfont.woff create mode 100644 idrocap_wa/webroot/font/cakedingbats-webfont.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-400-cyrillic-ext.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-400-cyrillic.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-400-latin-ext.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-400-latin.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-400-vietnamese.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-700-cyrillic-ext.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-700-cyrillic.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-700-latin-ext.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-700-latin.woff2 create mode 100644 idrocap_wa/webroot/font/raleway-700-vietnamese.woff2 create mode 100644 idrocap_wa/webroot/img/cake-logo.png create mode 100644 idrocap_wa/webroot/img/cake.icon.png create mode 100644 idrocap_wa/webroot/img/cake.icon.svg create mode 100644 idrocap_wa/webroot/img/cake.logo.svg create mode 100644 idrocap_wa/webroot/img/cake.power.gif create mode 100644 idrocap_wa/webroot/img/logo-autorita-dibacino.png create mode 100644 idrocap_wa/webroot/img/logo-fsc.png create mode 100644 idrocap_wa/webroot/img/logo-poa.png create mode 100644 idrocap_wa/webroot/img/logo-regione-sicilia.png create mode 100644 idrocap_wa/webroot/img/logo_mite.png create mode 100644 idrocap_wa/webroot/img/user2-160x160.jpg create mode 100644 idrocap_wa/webroot/index.php create mode 100644 idrocap_wa/webroot/js/.gitkeep create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/content.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Autocomplete/AutocompleteHandler.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/BaseClient.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/OpenAIClient.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Clients/WgsAIClient.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Interfaces/PromptInterface.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Services/AutoCompleteService.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/TaskFlow.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DataFormatter.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/DomElementHandler.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/EventHandler.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormAnalyzer.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormExclusions.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/dist/entrypoints/utils/Utility/FormFiller.js create mode 100644 idrocap_wa/webroot/js/ia-form-filler/styles/style.css create mode 100644 idrocap_wa/webroot/js/init_tiny_mce.js create mode 100644 idrocap_wa/webroot/js/jixel-primitives.js create mode 100644 idrocap_wa/webroot/js/moment.js create mode 100644 idrocap_wa/webroot/js/tinymce/icons/default/icons.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/langs/README.md create mode 100644 idrocap_wa/webroot/js/tinymce/langs/it.js create mode 100644 idrocap_wa/webroot/js/tinymce/license.md create mode 100644 idrocap_wa/webroot/js/tinymce/models/dom/model.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/accordion/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/advlist/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/anchor/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/autolink/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/autoresize/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/autosave/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/charmap/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/code/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/codesample/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/directionality/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojiimages.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/emoticons/js/emojis.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/emoticons/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/fullscreen/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ar.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/bg_BG.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ca.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/cs.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/da.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/de.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/el.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/en.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/es.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/eu.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fa.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fi.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/fr_FR.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/he_IL.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hi.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hr.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/hu_HU.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/id.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/it.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ja.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/kk.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ko_KR.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ms.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nb_NO.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/nl.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pl.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_BR.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/pt_PT.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ro.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/ru.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sk.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sl_SI.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/sv_SE.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/th_TH.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/tr.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/uk.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/vi.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_CN.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/js/i18n/keynav/zh_TW.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/help/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/image/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/importcss/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/insertdatetime/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/link/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/lists/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/media/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/nonbreaking/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/pagebreak/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/preview/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/quickbars/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/save/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/searchreplace/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/table/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/visualblocks/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/visualchars/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/plugins/wordcount/plugin.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/dark/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/dark/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/default/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/default/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/document/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/document/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/tinymce-5-dark/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/tinymce-5-dark/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/tinymce-5/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/tinymce-5/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/writer/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/content/writer/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/content.inline.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/content.inline.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/skin.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/skin.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/skin.shadowdom.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/content.inline.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/content.inline.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/skin.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/skin.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/skin.shadowdom.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/oxide/skin.shadowdom.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/content.inline.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/content.inline.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/skin.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/skin.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5-dark/skin.shadowdom.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/content.inline.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/content.inline.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/content.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/content.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/skin.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/skin.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/skin.shadowdom.js create mode 100644 idrocap_wa/webroot/js/tinymce/skins/ui/tinymce-5/skin.shadowdom.min.css create mode 100644 idrocap_wa/webroot/js/tinymce/themes/silver/theme.min.js create mode 100644 idrocap_wa/webroot/js/tinymce/tinymce.d.ts create mode 100644 idrocap_wa/webroot/js/tinymce/tinymce.min.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/Cloud.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/Exif2Geojson.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/ExportMap.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/FontAwesome5Def.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/FontAwesomeDef.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/FontMaki2Def.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/FontMakiDef.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/IFrameAPI.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/MapIFrameAPI.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/TextureImage.js create mode 100755 idrocap_wa/webroot/ol-ext/extra/WSynchro.js create mode 100755 idrocap_wa/webroot/ol-ext/ol-ext.css create mode 100755 idrocap_wa/webroot/ol-ext/ol-ext.js create mode 100755 idrocap_wa/webroot/ol-ext/ol-ext.min.css create mode 100755 idrocap_wa/webroot/ol-ext/ol-ext.min.js create mode 100644 idrocap_wa/webroot/package-lock.json create mode 100644 idrocap_wa/webroot/package.json create mode 100644 idrocap_wa/webroot/sounds/all_notification_read.mp3 create mode 100644 idrocap_wa/webroot/sounds/new_notification.mp3 diff --git a/README.md b/README.md index 9daeafb..c57fdec 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -test +idrocap_wa -> Web Application + diff --git a/idrocap_wa/.htaccess b/idrocap_wa/.htaccess new file mode 100644 index 0000000..e029162 --- /dev/null +++ b/idrocap_wa/.htaccess @@ -0,0 +1,12 @@ +# Uncomment the following to prevent the httpoxy vulnerability +# See: https://httpoxy.org/ +# +# RequestHeader unset Proxy +# + + + RewriteEngine on + RewriteRule ^(\.well-known/.*)$ $1 [L] + RewriteRule ^$ webroot/ [L] + RewriteRule (.*) webroot/$1 [L] + \ No newline at end of file diff --git a/idrocap_wa/Dockerfile b/idrocap_wa/Dockerfile new file mode 100644 index 0000000..4a3d615 --- /dev/null +++ b/idrocap_wa/Dockerfile @@ -0,0 +1,20 @@ +FROM registrywgs.webgenesis.it/webgenesys/jixel/jixel-dockers/almalinux9.5-php8.4.4:latest-master +RUN dnf -y install npm +RUN npm install -g bower +RUN dnf -y install git +RUN mkdir /var/www/jixel +COPY . /var/www/jixel +WORKDIR /var/www/jixel +RUN composer install --no-interaction +WORKDIR /var/www/jixel/webroot +RUN npm install +RUN bower install +EXPOSE 443 +EXPOSE 80 +WORKDIR /var/www/jixel +RUN mkdir /run/php-fpm +COPY ./dockerfiles/run /usr/local/bin/run +RUN chmod 500 /usr/local/bin/run +COPY ./dockerfiles/cake /var/www/jixel/bin/cake +RUN chmod 500 /var/www/jixel/bin/cake +CMD ["run"] diff --git a/idrocap_wa/README.md b/idrocap_wa/README.md new file mode 100644 index 0000000..dae0f2f --- /dev/null +++ b/idrocap_wa/README.md @@ -0,0 +1,61 @@ +# IDROCAP Jixel repository + +Jixel core for IDROCAP developing. Based on [CakePHP](https://cakephp.org) 5.x. + +The framework source code can be found here: [cakephp/cakephp](https://github.com/cakephp/cakephp). + +Before you run the docker stack: +make sure you have a few configs keys under in `config/app_local.php`: + +```php + 'Custom' => [ + 'background_tasks' => [ + 'notifications' => [ + 'channel' => 'newjixel_background_tasks', + ] + ], + ], +``` +and: + +```php + 'Datasources' => [ + 'default' => [ + 'host' => 'mysql8', + 'username' => 'jixel', + 'password' => 'jixel2023', + 'database' => 'jixel', + 'url' => env('DATABASE_URL', null), + ], + 'geo' => [ + 'host' => 'mysql-geo', + 'port' => '3307', + 'username' => 'gecos', + 'password' => 'gecos2015', + 'database' => 'geo', + ], + 'test' => [ + 'host' => 'localhost', + 'username' => 'my_app', + 'password' => 'secret', + 'database' => 'test_myapp', + 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'), + ], + ], +```` + +First bootstrap only (and only if you are mapping in your host machine, idrocapjixel repository): + +enter the container: +`docker exec -it -u jixel` + +install vendor packages: +`composer install -n` + +install vendor front end packages: +`cd webroot` +`npm install -y` +`bower install -y` + + + diff --git a/idrocap_wa/bin/bash_completion.sh b/idrocap_wa/bin/bash_completion.sh new file mode 100644 index 0000000..a3d3feb --- /dev/null +++ b/idrocap_wa/bin/bash_completion.sh @@ -0,0 +1,47 @@ +# +# Bash completion file for CakePHP console. +# Copy this file to a file named `cake` under `/etc/bash_completion.d/`. +# For more info check https://book.cakephp.org/4/en/console-commands/completion.html#how-to-enable-bash-autocompletion-for-the-cakephp-console +# + +_cake() +{ + local cur prev opts cake + COMPREPLY=() + cake="${COMP_WORDS[0]}" + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + + if [[ "$cur" == -* ]] ; then + if [[ ${COMP_CWORD} = 1 ]] ; then + opts=$(${cake} completion options) + elif [[ ${COMP_CWORD} = 2 ]] ; then + opts=$(${cake} completion options "${COMP_WORDS[1]}") + else + opts=$(${cake} completion options "${COMP_WORDS[1]}" "${COMP_WORDS[2]}") + fi + + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + if [[ ${COMP_CWORD} = 1 ]] ; then + opts=$(${cake} completion commands) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + return 0 + fi + + if [[ ${COMP_CWORD} = 2 ]] ; then + opts=$(${cake} completion subcommands $prev) + COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) + if [[ $COMPREPLY = "" ]] ; then + _filedir + return 0 + fi + return 0 + fi + + return 0 +} + +complete -F _cake cake bin/cake diff --git a/idrocap_wa/bin/cake b/idrocap_wa/bin/cake new file mode 100755 index 0000000..4b696c8 --- /dev/null +++ b/idrocap_wa/bin/cake @@ -0,0 +1,75 @@ +#!/usr/bin/env sh +################################################################################ +# +# Cake is a shell script for invoking CakePHP shell commands +# +# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# +# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# @link https://cakephp.org CakePHP(tm) Project +# @since 1.2.0 +# @license https://opensource.org/licenses/mit-license.php MIT License +# +################################################################################ + +# Canonicalize by following every symlink of the given name recursively +canonicalize() { + NAME="$1" + if [ -f "$NAME" ] + then + DIR=$(dirname -- "$NAME") + NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") + fi + while [ -h "$NAME" ]; do + DIR=$(dirname -- "$NAME") + SYM=$(readlink "$NAME") + NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM") + done + echo "$NAME" +} + +# Find a CLI version of PHP +findCliPhp() { + for TESTEXEC in php php-cli /usr/local/bin/php + do + SAPI=$(echo "" | $TESTEXEC 2>/dev/null) + if [ "$SAPI" = "cli" ] + then + echo $TESTEXEC + return + fi + done + echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2 + echo "php"; +} + +# If current path is a symlink, resolve to real path +realname="$0" +if [ -L "$realname" ] +then + realname=$(readlink -f "$0") +fi + +CONSOLE=$(dirname -- "$(canonicalize "$realname")") +APP=$(dirname "$CONSOLE") + +# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment +# variable with the correct path in it. +if [ -z "$PHP" ] +then + PHP=$(findCliPhp) +fi + +if [ "$(basename "$realname")" != 'cake' ] +then + exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@" +else + exec "$PHP" "$CONSOLE"/cake.php "$@" +fi + +exit diff --git a/idrocap_wa/bin/cake.bat b/idrocap_wa/bin/cake.bat new file mode 100644 index 0000000..a8a9af2 --- /dev/null +++ b/idrocap_wa/bin/cake.bat @@ -0,0 +1,27 @@ +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Cake is a Windows batch script for invoking CakePHP shell commands +:: +:: CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +:: Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: +:: Licensed under The MIT License +:: Redistributions of files must retain the above copyright notice. +:: +:: @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +:: @link https://cakephp.org CakePHP(tm) Project +:: @since 2.0.0 +:: @license https://opensource.org/licenses/mit-license.php MIT License +:: +:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +@echo off + +SET app=%0 +SET lib=%~dp0 + +php "%lib%cake.php" %* + +echo. + +exit /B %ERRORLEVEL% diff --git a/idrocap_wa/bin/cake.php b/idrocap_wa/bin/cake.php new file mode 100644 index 0000000..aab8d9f --- /dev/null +++ b/idrocap_wa/bin/cake.php @@ -0,0 +1,10 @@ +#!/usr/bin/php -q +run($argv)); diff --git a/idrocap_wa/composer.json b/idrocap_wa/composer.json new file mode 100644 index 0000000..086c0c3 --- /dev/null +++ b/idrocap_wa/composer.json @@ -0,0 +1,67 @@ +{ + "name": "cakephp/app", + "description": "CakePHP skeleton app", + "homepage": "https://cakephp.org", + "type": "project", + "license": "MIT", + "require": { + "php": ">=8.1", + "arodu/cakelte": "^2.0", + "aws/aws-sdk-php": "^3.301", + "cakephp/authentication": "^3.0", + "cakephp/cakephp": "^5.0.1", + "cakephp/migrations": "^4.0.0", + "cakephp/plugin-installer": "^2.0", + "firebase/php-jwt": "^6.10", + "friendsofcake/cakephp-csvview": "^5.0", + "lordsimal/cakephp-sentry": "^3.0", + "mobiledetect/mobiledetectlib": "^3.74", + "muffin/trash": "^4.0", + "php-amqplib/php-amqplib": "^3.6", + "simpleenergy/php-webhdfs": "^1.0" + }, + "require-dev": { + "cakephp/bake": "^3.0.0", + "cakephp/cakephp-codesniffer": "^5.0", + "cakephp/debug_kit": "^5.0.0", + "josegonzalez/dotenv": "^4.0", + "phpunit/phpunit": "^10.1.0" + }, + "suggest": { + "markstory/asset_compress": "An asset compression plugin which provides file concatenation and a flexible filter system for preprocessing and minification.", + "dereuromark/cakephp-ide-helper": "After baking your code, this keeps your annotations in sync with the code evolving from there on for maximum IDE and PHPStan/Psalm compatibility.", + "phpstan/phpstan": "PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even before you write tests for the code.", + "cakephp/repl": "Console tools for a REPL interface for CakePHP applications." + }, + "autoload": { + "psr-4": { + "App\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "App\\Test\\": "tests/", + "Cake\\Test\\": "vendor/cakephp/cakephp/tests/" + } + }, + "scripts": { + "post-install-cmd": "App\\Console\\Installer::postInstall", + "post-create-project-cmd": "App\\Console\\Installer::postInstall", + "check": [ + "@test", + "@cs-check" + ], + "cs-check": "phpcs --colors -p", + "cs-fix": "phpcbf --colors -p", + "stan": "phpstan analyse", + "test": "phpunit --colors=always" + }, + "config": { + "platform-check": true, + "sort-packages": true, + "allow-plugins": { + "cakephp/plugin-installer": true, + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/idrocap_wa/composer.lock b/idrocap_wa/composer.lock new file mode 100644 index 0000000..3da6955 --- /dev/null +++ b/idrocap_wa/composer.lock @@ -0,0 +1,7466 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "e213713928c919df6ae66477bb3a0300", + "packages": [ + { + "name": "almasaeed2010/adminlte", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/ColorlibHQ/AdminLTE.git", + "reference": "bd4d9c72931f1dd28601b6bfb387554a381ad540" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ColorlibHQ/AdminLTE/zipball/bd4d9c72931f1dd28601b6bfb387554a381ad540", + "reference": "bd4d9c72931f1dd28601b6bfb387554a381ad540", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Colorlib" + } + ], + "description": "AdminLTE - admin control panel and dashboard that's based on Bootstrap 4", + "homepage": "https://adminlte.io/", + "keywords": [ + "JS", + "admin", + "back-end", + "css", + "less", + "responsive", + "template", + "theme", + "web" + ], + "support": { + "issues": "https://github.com/ColorlibHQ/AdminLTE/issues", + "source": "https://github.com/ColorlibHQ/AdminLTE/tree/v3.2.0" + }, + "time": "2022-02-07T20:33:09+00:00" + }, + { + "name": "arodu/cakelte", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/arodu/cakelte.git", + "reference": "0077bdd47e848122d665f55fa391cad067e8b454" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/arodu/cakelte/zipball/0077bdd47e848122d665f55fa391cad067e8b454", + "reference": "0077bdd47e848122d665f55fa391cad067e8b454", + "shasum": "" + }, + "require": { + "almasaeed2010/adminlte": "^3.2", + "cakephp/cakephp": "^5.0", + "friendsofcake/bootstrap-ui": "^5.0" + }, + "require-dev": { + "cakedc/cakephp-phpstan": "^3.1", + "cakephp/cakephp-codesniffer": "^5.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.1.0" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "CakeLte\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "CakeLTE: AdminLTE plugin for CakePHP", + "support": { + "issues": "https://github.com/arodu/cakelte/issues", + "source": "https://github.com/arodu/cakelte/tree/v2.0.1" + }, + "time": "2024-03-05T11:41:23+00:00" + }, + { + "name": "aws/aws-crt-php", + "version": "v1.2.7", + "source": { + "type": "git", + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e", + "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7" + }, + "time": "2024-10-18T22:15:13+00:00" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.340.2", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "22cee29c0ca8d93a7a9c03d13739217373a21fcc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/22cee29c0ca8d93a7a9c03d13739217373a21fcc", + "reference": "22cee29c0ca8d93a7a9c03d13739217373a21fcc", + "shasum": "" + }, + "require": { + "aws/aws-crt-php": "^1.2.3", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.4.5", + "mtdowling/jmespath.php": "^2.8.0", + "php": ">=8.1", + "psr/http-message": "^2.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^2.7.8", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", + "psr/cache": "^2.0 || ^3.0", + "psr/simple-cache": "^2.0 || ^3.0", + "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0", + "symfony/filesystem": "^v6.4.0 || ^v7.1.0", + "yoast/phpunit-polyfills": "^2.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + }, + "exclude-from-classmap": [ + "src/data/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://github.com/aws/aws-sdk-php/discussions", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.340.2" + }, + "time": "2025-02-26T19:28:12+00:00" + }, + { + "name": "cakephp/authentication", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/authentication.git", + "reference": "3583745feb37c5069930cd1661bb0723a8f64f99" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/authentication/zipball/3583745feb37c5069930cd1661bb0723a8f64f99", + "reference": "3583745feb37c5069930cd1661bb0723a8f64f99", + "shasum": "" + }, + "require": { + "cakephp/http": "^5.0", + "laminas/laminas-diactoros": "^3.0", + "psr/http-client": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0" + }, + "require-dev": { + "cakephp/cakephp": "^5.1.0", + "cakephp/cakephp-codesniffer": "^5.0", + "firebase/php-jwt": "^6.2", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "suggest": { + "cakephp/cakephp": "Install full core to use \"CookieAuthenticator\".", + "cakephp/orm": "To use \"OrmResolver\" (Not needed separately if using full CakePHP framework).", + "cakephp/utility": "Provides CakePHP security methods. Required for the JWT adapter and Legacy password hasher.", + "ext-ldap": "Make sure this php extension is installed and enabled on your system if you want to use the built-in LDAP adapter for \"LdapIdentifier\".", + "firebase/php-jwt": "If you want to use the JWT adapter add this dependency" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Authentication\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/authentication/graphs/contributors" + } + ], + "description": "Authentication plugin for CakePHP", + "homepage": "https://cakephp.org", + "keywords": [ + "Authentication", + "auth", + "cakephp", + "middleware" + ], + "support": { + "docs": "https://book.cakephp.org/authentication/3/en/", + "forum": "https://discourse.cakephp.org/", + "issues": "https://github.com/cakephp/authentication/issues", + "source": "https://github.com/cakephp/authentication" + }, + "time": "2024-10-18T15:48:32+00:00" + }, + { + "name": "cakephp/cakephp", + "version": "5.1.6", + "source": { + "type": "git", + "url": "https://github.com/cakephp/cakephp.git", + "reference": "4b8915cf32949cac5c798af2ff65f688c4d76d21" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/cakephp/zipball/4b8915cf32949cac5c798af2ff65f688c4d76d21", + "reference": "4b8915cf32949cac5c798af2ff65f688c4d76d21", + "shasum": "" + }, + "require": { + "cakephp/chronos": "^3.1", + "composer/ca-bundle": "^1.5", + "ext-intl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "laminas/laminas-diactoros": "^3.3", + "laminas/laminas-httphandlerrunner": "^2.6", + "league/container": "^4.2", + "php": ">=8.1", + "psr/container": "^1.1 || ^2.0", + "psr/http-client": "^1.0.2", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0.2", + "psr/http-server-middleware": "^1.0.2", + "psr/log": "^3.0", + "psr/simple-cache": "^2.0 || ^3.0" + }, + "provide": { + "psr/container-implementation": "^2.0", + "psr/http-client-implementation": "^1.0", + "psr/http-factory-implementation": "^1.0", + "psr/http-server-handler-implementation": "^1.0", + "psr/http-server-middleware-implementation": "^1.0", + "psr/log-implementation": "^3.0", + "psr/simple-cache-implementation": "^3.0" + }, + "replace": { + "cakephp/cache": "self.version", + "cakephp/collection": "self.version", + "cakephp/console": "self.version", + "cakephp/core": "self.version", + "cakephp/database": "self.version", + "cakephp/datasource": "self.version", + "cakephp/event": "self.version", + "cakephp/form": "self.version", + "cakephp/http": "self.version", + "cakephp/i18n": "self.version", + "cakephp/log": "self.version", + "cakephp/orm": "self.version", + "cakephp/utility": "self.version", + "cakephp/validation": "self.version" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "http-interop/http-factory-tests": "^2.0", + "mikey179/vfsstream": "^1.6.10", + "mockery/mockery": "^1.6", + "paragonie/csp-builder": "^2.3 || ^3.0", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan": "1.12.7", + "phpunit/phpunit": "^10.5.5 || ^11.1.3", + "symplify/phpstan-rules": "^12.4" + }, + "suggest": { + "ext-curl": "To enable more efficient network calls in Http\\Client.", + "ext-openssl": "To use Security::encrypt() or have secure CSRF token generation.", + "paragonie/csp-builder": "CSP builder, to use the CSP Middleware" + }, + "type": "library", + "autoload": { + "files": [ + "src/Core/functions.php", + "src/Error/functions.php", + "src/Collection/functions.php", + "src/I18n/functions.php", + "src/ORM/bootstrap.php", + "src/Routing/functions.php", + "src/Utility/bootstrap.php" + ], + "psr-4": { + "Cake\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp/graphs/contributors" + } + ], + "description": "The CakePHP framework", + "homepage": "https://cakephp.org", + "keywords": [ + "conventions over configuration", + "dry", + "form", + "framework", + "mvc", + "orm", + "psr-7", + "rapid-development", + "validation" + ], + "support": { + "forum": "https://discourse.cakephp.org/", + "issues": "https://github.com/cakephp/cakephp/issues", + "source": "https://github.com/cakephp/cakephp" + }, + "time": "2025-02-23T20:09:05+00:00" + }, + { + "name": "cakephp/chronos", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/cakephp/chronos.git", + "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/chronos/zipball/786d69e1ee4b735765cbdb5521b9603e9b98d650", + "reference": "786d69e1ee4b735765cbdb5521b9603e9b98d650", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/clock": "^1.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.1.0 || ^11.1.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Cake\\Chronos\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + }, + { + "name": "The CakePHP Team", + "homepage": "https://cakephp.org" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "https://cakephp.org", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "issues": "https://github.com/cakephp/chronos/issues", + "source": "https://github.com/cakephp/chronos" + }, + "time": "2024-07-18T03:18:04+00:00" + }, + { + "name": "cakephp/migrations", + "version": "4.5.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/migrations.git", + "reference": "675b494235a3d3d8b76fda6a684f4ab38b5a6f7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/migrations/zipball/675b494235a3d3d8b76fda6a684f4ab38b5a6f7f", + "reference": "675b494235a3d3d8b76fda6a684f4ab38b5a6f7f", + "shasum": "" + }, + "require": { + "cakephp/cache": "^5.0", + "cakephp/orm": "^5.0", + "php": ">=8.1", + "robmorgan/phinx": "^0.16.0" + }, + "require-dev": { + "cakephp/bake": "dev-3.next", + "cakephp/cakephp": "dev-5.next as 5.1.0", + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "suggest": { + "cakephp/bake": "If you want to generate migrations.", + "dereuromark/cakephp-ide-helper": "If you want to have IDE suggest/autocomplete when creating migrations." + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Migrations\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/migrations/graphs/contributors" + } + ], + "description": "Database Migration plugin for CakePHP based on Phinx", + "homepage": "https://github.com/cakephp/migrations", + "keywords": [ + "cakephp", + "migrations" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/migrations/issues", + "source": "https://github.com/cakephp/migrations" + }, + "time": "2025-01-16T15:21:04+00:00" + }, + { + "name": "cakephp/plugin-installer", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/cakephp/plugin-installer.git", + "reference": "5420701fd47d82fe81805ebee34fbbcef34c52ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/plugin-installer/zipball/5420701fd47d82fe81805ebee34fbbcef34c52ba", + "reference": "5420701fd47d82fe81805ebee34fbbcef34c52ba", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "composer/composer": "^2.0", + "phpunit/phpunit": "^10.1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Cake\\Composer\\Plugin" + }, + "autoload": { + "psr-4": { + "Cake\\Composer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://cakephp.org" + } + ], + "description": "A composer installer for CakePHP 3.0+ plugins.", + "support": { + "issues": "https://github.com/cakephp/plugin-installer/issues", + "source": "https://github.com/cakephp/plugin-installer/tree/2.0.1" + }, + "time": "2023-09-10T10:02:44+00:00" + }, + { + "name": "composer/ca-bundle", + "version": "1.5.5", + "source": { + "type": "git", + "url": "https://github.com/composer/ca-bundle.git", + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/08c50d5ec4c6ced7d0271d2862dec8c1033283e6", + "reference": "08c50d5ec4c6ced7d0271d2862dec8c1033283e6", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\CaBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.5.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-01-08T16:17:16+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v6.11.0", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "reference": "8f718f4dfc9c5d5f0c994cdfd103921b43592712", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.11.0" + }, + "time": "2025-01-23T05:11:06+00:00" + }, + { + "name": "friendsofcake/bootstrap-ui", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfCake/bootstrap-ui.git", + "reference": "3bd2963c13ff2d829010270669f0a259537acd6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfCake/bootstrap-ui/zipball/3bd2963c13ff2d829010270669f0a259537acd6a", + "reference": "3bd2963c13ff2d829010270669f0a259537acd6a", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.1.4" + }, + "require-dev": { + "cakephp/bake": "^3.0", + "cakephp/cakephp-codesniffer": "^5.1", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "BootstrapUI\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jad Bitar", + "homepage": "http://jadb.io", + "role": "Author" + }, + { + "name": "Others", + "homepage": "https://github.com/friendsofcake/bootstrap-ui/graphs/contributors" + } + ], + "description": "Bootstrap front-end framework support for CakePHP", + "homepage": "http://github.com/friendsofcake/bootstrap-ui", + "keywords": [ + "bootstrap", + "cakephp", + "front-end" + ], + "support": { + "issues": "http://github.com/friendsofcake/bootstrap-ui/issues", + "source": "http://github.com/friendsofcake/bootstrap-ui" + }, + "time": "2024-12-13T06:20:08+00:00" + }, + { + "name": "friendsofcake/cakephp-csvview", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfCake/cakephp-csvview.git", + "reference": "c2e539c6e8a53c4fcbc27bfa3776f535dea96dc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfCake/cakephp-csvview/zipball/c2e539c6e8a53c4fcbc27bfa3776f535dea96dc1", + "reference": "c2e539c6e8a53c4fcbc27bfa3776f535dea96dc1", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.1" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "CsvView\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jose Diaz-Gonzalez", + "email": "email@josediazgonzalez.com", + "homepage": "https://josediazgonzalez.com", + "role": "Maintainer" + }, + { + "name": "ADmad", + "homepage": "https://github.com/admad", + "role": "Contributor" + }, + { + "name": "Mark Scherer", + "homepage": "https://github.com/dereuromark", + "role": "Contributor" + }, + { + "name": "Joshua Paling", + "homepage": "https://github.com/joshuapaling", + "role": "Contributor" + }, + { + "name": "Gaurish Sharma", + "homepage": "https://github.com/gaurish", + "role": "Contributor" + }, + { + "name": "Gregory Gaskill", + "homepage": "https://github.com/chronon", + "role": "Contributor" + } + ], + "description": "A CSV View class for CakePHP", + "homepage": "https://github.com/friendsofcake/cakephp-csvview", + "keywords": [ + "cakephp", + "csv", + "export", + "view" + ], + "support": { + "issues": "https://github.com/friendsofcake/cakephp-csvview/issues", + "source": "https://github.com/friendsofcake/cakephp-csvview" + }, + "time": "2023-10-13T18:16:38+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b", + "reference": "d281ed313b989f213357e3be1a179f02196ac99b", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2024-07-24T11:22:20+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2024-10-17T10:06:22+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2024-07-18T11:15:46+00:00" + }, + { + "name": "jean85/pretty-package-versions", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Jean85/pretty-package-versions.git", + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "reference": "3c4e5f62ba8d7de1734312e4fff32f67a8daaf10", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.1.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^7.5|^8.5|^9.6", + "vimeo/psalm": "^4.3 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.1.0" + }, + "time": "2024-11-18T16:19:46+00:00" + }, + { + "name": "laminas/laminas-diactoros", + "version": "3.5.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "143a16306602ce56b8b092a7914fef03c37f9ed2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/143a16306602ce56b8b092a7914fef03c37f9ed2", + "reference": "143a16306602ce56b8b092a7914fef03c37f9ed2", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0" + }, + "conflict": { + "amphp/amp": "<2.6.4" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.1 || ^2.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^2.2.0", + "laminas/laminas-coding-standard": "~2.5.0", + "php-http/psr7-integration-tests": "^1.4.0", + "phpunit/phpunit": "^10.5.36", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\Diactoros", + "config-provider": "Laminas\\Diactoros\\ConfigProvider" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2024-10-14T11:59:49+00:00" + }, + { + "name": "laminas/laminas-httphandlerrunner", + "version": "2.11.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-httphandlerrunner.git", + "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/c428d9f67f280d155637cbe2b7245b5188c8cdae", + "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae", + "shasum": "" + }, + "require": { + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-message-implementation": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "require-dev": { + "laminas/laminas-coding-standard": "~3.0.0", + "laminas/laminas-diactoros": "^3.4.0", + "phpunit/phpunit": "^10.5.36", + "psalm/plugin-phpunit": "^0.19.0", + "vimeo/psalm": "^5.26.1" + }, + "type": "library", + "extra": { + "laminas": { + "config-provider": "Laminas\\HttpHandlerRunner\\ConfigProvider" + } + }, + "autoload": { + "psr-4": { + "Laminas\\HttpHandlerRunner\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Execute PSR-15 RequestHandlerInterface instances and emit responses they generate.", + "homepage": "https://laminas.dev", + "keywords": [ + "components", + "laminas", + "mezzio", + "psr-15", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-httphandlerrunner/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-httphandlerrunner/issues", + "rss": "https://github.com/laminas/laminas-httphandlerrunner/releases.atom", + "source": "https://github.com/laminas/laminas-httphandlerrunner" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2024-10-17T20:37:17+00:00" + }, + { + "name": "league/container", + "version": "4.2.4", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/container.git", + "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/container/zipball/7ea728b013b9a156c409c6f0fc3624071b742dec", + "reference": "7ea728b013b9a156c409c6f0fc3624071b742dec", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "replace": { + "orno/di": "~2.0" + }, + "require-dev": { + "nette/php-generator": "^3.4", + "nikic/php-parser": "^4.10", + "phpstan/phpstan": "^0.12.47", + "phpunit/phpunit": "^8.5.17", + "roave/security-advisories": "dev-latest", + "scrutinizer/ocular": "^1.8", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev", + "dev-2.x": "2.x-dev", + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "4.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Container\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Phil Bennett", + "email": "mail@philbennett.co.uk", + "role": "Developer" + } + ], + "description": "A fast and intuitive dependency injection container.", + "homepage": "https://github.com/thephpleague/container", + "keywords": [ + "container", + "dependency", + "di", + "injection", + "league", + "provider", + "service" + ], + "support": { + "issues": "https://github.com/thephpleague/container/issues", + "source": "https://github.com/thephpleague/container/tree/4.2.4" + }, + "funding": [ + { + "url": "https://github.com/philipobenito", + "type": "github" + } + ], + "time": "2024-11-10T12:42:13+00:00" + }, + { + "name": "lordsimal/cakephp-sentry", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/LordSimal/cakephp-sentry.git", + "reference": "de9640aeee76c50a7a5e0bc2346e295c7adb292f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/LordSimal/cakephp-sentry/zipball/de9640aeee76c50a7a5e0bc2346e295c7adb292f", + "reference": "de9640aeee76c50a7a5e0bc2346e295c7adb292f", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.1.0", + "php": "^8.1", + "sentry/sentry": "^4.0" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "mockery/mockery": "^1.6", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "CakeSentry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Pfeifer", + "email": "info@pfeiferkevin.at", + "role": "Maintainer" + } + ], + "description": "Sentry plugin for CakePHP", + "support": { + "issues": "https://github.com/LordSimal/cakephp-sentry/issues", + "source": "https://github.com/LordSimal/cakephp-sentry/tree/3.2.0" + }, + "time": "2024-12-31T19:23:16+00:00" + }, + { + "name": "mobiledetect/mobiledetectlib", + "version": "3.74.3", + "source": { + "type": "git", + "url": "https://github.com/serbanghita/Mobile-Detect.git", + "reference": "39582ab62f86b40e4edb698159f895929a29c346" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/serbanghita/Mobile-Detect/zipball/39582ab62f86b40e4edb698159f895929a29c346", + "reference": "39582ab62f86b40e4edb698159f895929a29c346", + "shasum": "" + }, + "require": { + "php": ">=7.4" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.14", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Detection\\": "src/" + }, + "classmap": [ + "src/MobileDetect.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Serban Ghita", + "email": "serbanghita@gmail.com", + "homepage": "https://mobiledetect.net", + "role": "Developer" + } + ], + "description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.", + "homepage": "https://github.com/serbanghita/Mobile-Detect", + "keywords": [ + "detect mobile devices", + "mobile", + "mobile detect", + "mobile detector", + "php mobile detect" + ], + "support": { + "issues": "https://github.com/serbanghita/Mobile-Detect/issues", + "source": "https://github.com/serbanghita/Mobile-Detect/tree/3.74.3" + }, + "funding": [ + { + "url": "https://github.com/serbanghita", + "type": "github" + } + ], + "time": "2023-10-27T16:28:04+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "time": "2024-09-04T18:46:31+00:00" + }, + { + "name": "muffin/trash", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/UseMuffin/Trash.git", + "reference": "bbdaab7b2f1848fbce9111daadda1146ef1122a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/UseMuffin/Trash/zipball/bbdaab7b2f1848fbce9111daadda1146ef1122a2", + "reference": "bbdaab7b2f1848fbce9111daadda1146ef1122a2", + "shasum": "" + }, + "require": { + "cakephp/orm": "^5.0.0", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/cakephp": "^5.0.0", + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.1.0" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Muffin\\Trash\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jad Bitar", + "homepage": "http://jadb.io", + "role": "Author" + }, + { + "name": "ADmad", + "homepage": "https://github.com/ADmad", + "role": "Author" + }, + { + "name": "Others", + "homepage": "https://github.com/usemuffin/trash/graphs/contributors" + } + ], + "description": "Adds soft delete support to CakePHP ORM tables.", + "homepage": "https://github.com/usemuffin/trash", + "keywords": [ + "cakephp", + "muffin", + "orm", + "trash" + ], + "support": { + "issues": "https://github.com/usemuffin/trash/issues", + "source": "https://github.com/usemuffin/trash" + }, + "time": "2025-02-04T07:09:14+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v3.0.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", + "shasum": "" + }, + "require": { + "php": "^8" + }, + "require-dev": { + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2024-05-08T12:36:18+00:00" + }, + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, + { + "name": "php-amqplib/php-amqplib", + "version": "v3.7.3", + "source": { + "type": "git", + "url": "https://github.com/php-amqplib/php-amqplib.git", + "reference": "9f50fe69a9f1a19e2cb25596a354d705de36fe59" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/9f50fe69a9f1a19e2cb25596a354d705de36fe59", + "reference": "9f50fe69a9f1a19e2cb25596a354d705de36fe59", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-sockets": "*", + "php": "^7.2||^8.0", + "phpseclib/phpseclib": "^2.0|^3.0" + }, + "conflict": { + "php": "7.4.0 - 7.4.1" + }, + "replace": { + "videlalvaro/php-amqplib": "self.version" + }, + "require-dev": { + "ext-curl": "*", + "nategood/httpful": "^0.2.20", + "phpunit/phpunit": "^7.5|^9.5", + "squizlabs/php_codesniffer": "^3.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpAmqpLib\\": "PhpAmqpLib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Alvaro Videla", + "role": "Original Maintainer" + }, + { + "name": "Raúl Araya", + "email": "nubeiro@gmail.com", + "role": "Maintainer" + }, + { + "name": "Luke Bakken", + "email": "luke@bakken.io", + "role": "Maintainer" + }, + { + "name": "Ramūnas Dronga", + "email": "github@ramuno.lt", + "role": "Maintainer" + } + ], + "description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.", + "homepage": "https://github.com/php-amqplib/php-amqplib/", + "keywords": [ + "message", + "queue", + "rabbitmq" + ], + "support": { + "issues": "https://github.com/php-amqplib/php-amqplib/issues", + "source": "https://github.com/php-amqplib/php-amqplib/tree/v3.7.3" + }, + "time": "2025-02-18T20:11:13+00:00" + }, + { + "name": "phpseclib/phpseclib", + "version": "3.0.43", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "^1|^2|^3", + "paragonie/random_compat": "^1.4|^2.0|^9.99.99", + "php": ">=5.6.1" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "ext-dom": "Install the DOM extension to load XML formatted public keys.", + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib3\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2024-12-14T21:12:59+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "time": "2023-04-10T20:06:20+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "time": "2023-04-11T06:14:47+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "robmorgan/phinx", + "version": "0.16.6", + "source": { + "type": "git", + "url": "https://github.com/cakephp/phinx.git", + "reference": "5bad10934336e8cf45d50d529cabfcbe7fe287c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/phinx/zipball/5bad10934336e8cf45d50d529cabfcbe7fe287c5", + "reference": "5bad10934336e8cf45d50d529cabfcbe7fe287c5", + "shasum": "" + }, + "require": { + "cakephp/database": "^5.0.2", + "composer-runtime-api": "^2.0", + "php-64bit": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/config": "^3.4|^4.0|^5.0|^6.0|^7.0", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "cakephp/cakephp": "^5.0.2", + "cakephp/cakephp-codesniffer": "^5.0", + "ext-json": "*", + "ext-pdo": "*", + "phpunit/phpunit": "^9.5.19", + "symfony/yaml": "^3.4|^4.0|^5.0|^6.0|^7.0" + }, + "suggest": { + "ext-json": "Install if using JSON configuration format", + "ext-pdo": "PDO extension is needed", + "symfony/yaml": "Install if using YAML configuration format" + }, + "bin": [ + "bin/phinx" + ], + "type": "library", + "autoload": { + "psr-4": { + "Phinx\\": "src/Phinx/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Rob Morgan", + "email": "robbym@gmail.com", + "homepage": "https://robmorgan.id.au", + "role": "Lead Developer" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com", + "homepage": "https://shadowhand.me", + "role": "Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Developer" + }, + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/phinx/graphs/contributors", + "role": "Developer" + } + ], + "description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.", + "homepage": "https://phinx.org", + "keywords": [ + "database", + "database migrations", + "db", + "migrations", + "phinx" + ], + "support": { + "issues": "https://github.com/cakephp/phinx/issues", + "source": "https://github.com/cakephp/phinx/tree/0.16.6" + }, + "time": "2024-12-20T23:02:54+00:00" + }, + { + "name": "sentry/sentry", + "version": "4.10.0", + "source": { + "type": "git", + "url": "https://github.com/getsentry/sentry-php.git", + "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/getsentry/sentry-php/zipball/2af937d47d8aadb8dab0b1d7b9557e495dd12856", + "reference": "2af937d47d8aadb8dab0b1d7b9557e495dd12856", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "guzzlehttp/psr7": "^1.8.4|^2.1.1", + "jean85/pretty-package-versions": "^1.5|^2.0.4", + "php": "^7.2|^8.0", + "psr/log": "^1.0|^2.0|^3.0", + "symfony/options-resolver": "^4.4.30|^5.0.11|^6.0|^7.0" + }, + "conflict": { + "raven/raven": "*" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.4", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^1.8.4|^2.1.1", + "monolog/monolog": "^1.6|^2.0|^3.0", + "phpbench/phpbench": "^1.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^8.5|^9.6", + "symfony/phpunit-bridge": "^5.2|^6.0|^7.0", + "vimeo/psalm": "^4.17" + }, + "suggest": { + "monolog/monolog": "Allow sending log messages to Sentry by using the included Monolog handler." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Sentry\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Sentry", + "email": "accounts@sentry.io" + } + ], + "description": "PHP SDK for Sentry (http://sentry.io)", + "homepage": "http://sentry.io", + "keywords": [ + "crash-reporting", + "crash-reports", + "error-handler", + "error-monitoring", + "log", + "logging", + "profiling", + "sentry", + "tracing" + ], + "support": { + "issues": "https://github.com/getsentry/sentry-php/issues", + "source": "https://github.com/getsentry/sentry-php/tree/4.10.0" + }, + "funding": [ + { + "url": "https://sentry.io/", + "type": "custom" + }, + { + "url": "https://sentry.io/pricing/", + "type": "custom" + } + ], + "time": "2024-11-06T07:44:19+00:00" + }, + { + "name": "simpleenergy/php-webhdfs", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/michaelbutler/php-WebHDFS.git", + "reference": "3212b98e9444e55aab7d129f002247bdcd0c26c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/michaelbutler/php-WebHDFS/zipball/3212b98e9444e55aab7d129f002247bdcd0c26c8", + "reference": "3212b98e9444e55aab7d129f002247bdcd0c26c8", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "php": ">=5.4.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "org\\apache\\hadoop\\": "src/", + "org\\apache\\hadoop\\tools": "app/models/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "tranch-xiao", + "homepage": "https://github.com/tranch-xiao" + }, + { + "name": "dshap", + "homepage": "https://github.com/dshap" + }, + { + "name": "jacobko", + "homepage": "https://github.com/jacobko" + }, + { + "name": "yosshi", + "homepage": "https://github.com/yosshi" + }, + { + "name": "Sebastian Lagemann", + "email": "sebastian@iqu.com" + } + ], + "description": "PHP WebHDFS, forked from https://github.com/simpleenergy/php-WebHDFS", + "support": { + "issues": "https://github.com/michaelbutler/php-WebHDFS/issues", + "source": "https://github.com/michaelbutler/php-WebHDFS/tree/1.0.8" + }, + "time": "2024-04-22T23:58:10+00:00" + }, + { + "name": "symfony/config", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "7716594aaae91d9141be080240172a92ecca4d44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/7716594aaae91d9141be080240172a92ecca4d44", + "reference": "7716594aaae91d9141be080240172a92ecca4d44", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-22T12:07:01+00:00" + }, + { + "name": "symfony/console", + "version": "v7.2.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.2.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-11T03:49:26+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-25T15:15:23+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-20T11:17:29+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-13T13:31:26+00:00" + } + ], + "packages-dev": [ + { + "name": "brick/varexporter", + "version": "0.5.0", + "source": { + "type": "git", + "url": "https://github.com/brick/varexporter.git", + "reference": "84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/brick/varexporter/zipball/84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b", + "reference": "84b2a7a91f69aa5d079aec5a0a7256ebf2dceb6b", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^9.3", + "psalm/phar": "5.21.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Brick\\VarExporter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A powerful alternative to var_export(), which can export closures and objects without __set_state()", + "keywords": [ + "var_export" + ], + "support": { + "issues": "https://github.com/brick/varexporter/issues", + "source": "https://github.com/brick/varexporter/tree/0.5.0" + }, + "funding": [ + { + "url": "https://github.com/BenMorel", + "type": "github" + } + ], + "time": "2024-05-10T17:15:19+00:00" + }, + { + "name": "cakephp/bake", + "version": "3.2.2", + "source": { + "type": "git", + "url": "https://github.com/cakephp/bake.git", + "reference": "165e2bd9cc407b0ea19f8a3b48927c10607f3963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/bake/zipball/165e2bd9cc407b0ea19f8a3b48927c10607f3963", + "reference": "165e2bd9cc407b0ea19f8a3b48927c10607f3963", + "shasum": "" + }, + "require": { + "brick/varexporter": "^0.5.0", + "cakephp/cakephp": "^5.1", + "cakephp/twig-view": "^2.0.0", + "nikic/php-parser": "^5.0.0", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0.0", + "cakephp/debug_kit": "^5.0.0", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Bake\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/bake/graphs/contributors" + } + ], + "description": "Bake plugin for CakePHP", + "homepage": "https://github.com/cakephp/bake", + "keywords": [ + "bake", + "cakephp" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "issues": "https://github.com/cakephp/bake/issues", + "source": "https://github.com/cakephp/bake" + }, + "time": "2025-01-17T14:18:00+00:00" + }, + { + "name": "cakephp/cakephp-codesniffer", + "version": "5.1.4", + "source": { + "type": "git", + "url": "https://github.com/cakephp/cakephp-codesniffer.git", + "reference": "6d0168a18c9fb6802103b41579abdcfba7021790" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/6d0168a18c9fb6802103b41579abdcfba7021790", + "reference": "6d0168a18c9fb6802103b41579abdcfba7021790", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "phpstan/phpdoc-parser": "^1.4.5", + "slevomat/coding-standard": "^8.15", + "squizlabs/php_codesniffer": "^3.9" + }, + "require-dev": { + "phpunit/phpunit": "^9.3.4" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "CakePHP\\": "CakePHP/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp-codesniffer/graphs/contributors" + } + ], + "description": "CakePHP CodeSniffer Standards", + "homepage": "https://cakephp.org", + "keywords": [ + "codesniffer", + "framework" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/cakephp-codesniffer/issues", + "source": "https://github.com/cakephp/cakephp-codesniffer" + }, + "time": "2024-12-18T21:15:44+00:00" + }, + { + "name": "cakephp/debug_kit", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/cakephp/debug_kit.git", + "reference": "b83ec9e0c62480f7cc9639e01cb9310bb7f0816d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/debug_kit/zipball/b83ec9e0c62480f7cc9639e01cb9310bb7f0816d", + "reference": "b83ec9e0c62480f7cc9639e01cb9310bb7f0816d", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.1", + "composer/composer": "^2.0", + "doctrine/sql-formatter": "^1.1.3", + "php": ">=8.1" + }, + "require-dev": { + "cakephp/authorization": "^3.0", + "cakephp/cakephp-codesniffer": "^5.0", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "suggest": { + "ext-pdo_sqlite": "DebugKit needs to store panel data in a database. SQLite is simple and easy to use." + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "DebugKit\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Story", + "homepage": "https://mark-story.com", + "role": "Author" + }, + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/debug_kit/graphs/contributors" + } + ], + "description": "CakePHP Debug Kit", + "homepage": "https://github.com/cakephp/debug_kit", + "keywords": [ + "cakephp", + "debug", + "dev", + "kit" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/debug_kit/issues", + "source": "https://github.com/cakephp/debug_kit" + }, + "time": "2024-12-30T18:48:17+00:00" + }, + { + "name": "cakephp/twig-view", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/cakephp/twig-view.git", + "reference": "b11df8e8734ae556d98b143192377dbc6a6f5360" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cakephp/twig-view/zipball/b11df8e8734ae556d98b143192377dbc6a6f5360", + "reference": "b11df8e8734ae556d98b143192377dbc6a6f5360", + "shasum": "" + }, + "require": { + "cakephp/cakephp": "^5.0.0", + "jasny/twig-extensions": "^1.3", + "twig/markdown-extra": "^3.0", + "twig/twig": "^3.11.1" + }, + "conflict": { + "wyrihaximus/twig-view": "*" + }, + "require-dev": { + "cakephp/cakephp-codesniffer": "^5.0", + "cakephp/debug_kit": "^5.0", + "michelf/php-markdown": "^1.9", + "mikey179/vfsstream": "^1.6.10", + "phpunit/phpunit": "^10.5.5 || ^11.1.3" + }, + "type": "cakephp-plugin", + "autoload": { + "psr-4": { + "Cake\\TwigView\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "CakePHP Community", + "homepage": "https://github.com/cakephp/cakephp/graphs/contributors" + } + ], + "description": "Twig powered View for CakePHP", + "keywords": [ + "cakephp", + "template", + "twig", + "view" + ], + "support": { + "forum": "https://stackoverflow.com/tags/cakephp", + "irc": "irc://irc.freenode.org/cakephp", + "issues": "https://github.com/cakephp/twig-view/issues", + "source": "https://github.com/cakephp/twig-view" + }, + "time": "2024-10-11T07:53:08+00:00" + }, + { + "name": "composer/class-map-generator", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/composer/class-map-generator.git", + "reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/ffe442c5974c44a9343e37a0abcb1cc37319f5b9", + "reference": "ffe442c5974c44a9343e37a0abcb1cc37319f5b9", + "shasum": "" + }, + "require": { + "composer/pcre": "^2.1 || ^3.1", + "php": "^7.2 || ^8.0", + "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\ClassMapGenerator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Utilities to scan PHP code and generate class maps.", + "keywords": [ + "classmap" + ], + "support": { + "issues": "https://github.com/composer/class-map-generator/issues", + "source": "https://github.com/composer/class-map-generator/tree/1.6.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-02-05T10:05:34+00:00" + }, + { + "name": "composer/composer", + "version": "2.8.6", + "source": { + "type": "git", + "url": "https://github.com/composer/composer.git", + "reference": "937c775a644bd7d2c3dfbb352747488463a6e673" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/composer/zipball/937c775a644bd7d2c3dfbb352747488463a6e673", + "reference": "937c775a644bd7d2c3dfbb352747488463a6e673", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.5", + "composer/class-map-generator": "^1.4.0", + "composer/metadata-minifier": "^1.0", + "composer/pcre": "^2.2 || ^3.2", + "composer/semver": "^3.3", + "composer/spdx-licenses": "^1.5.7", + "composer/xdebug-handler": "^2.0.2 || ^3.0.3", + "justinrainbow/json-schema": "^5.3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1.0 || ^2.0 || ^3.0", + "react/promise": "^2.11 || ^3.2", + "seld/jsonlint": "^1.4", + "seld/phar-utils": "^1.2", + "seld/signal-handler": "^2.0", + "symfony/console": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/filesystem": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/finder": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/polyfill-php73": "^1.24", + "symfony/polyfill-php80": "^1.24", + "symfony/polyfill-php81": "^1.24", + "symfony/process": "^5.4.35 || ^6.3.12 || ^7.0.3" + }, + "require-dev": { + "phpstan/phpstan": "^1.11.8", + "phpstan/phpstan-deprecation-rules": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpstan/phpstan-strict-rules": "^1.6.0", + "phpstan/phpstan-symfony": "^1.4.0", + "symfony/phpunit-bridge": "^6.4.3 || ^7.0.1" + }, + "suggest": { + "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", + "ext-zip": "Enabling the zip extension allows you to unzip archives", + "ext-zlib": "Allow gzip compression of HTTP requests" + }, + "bin": [ + "bin/composer" + ], + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "phpstan/rules.neon" + ] + }, + "branch-alias": { + "dev-main": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\": "src/Composer/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "https://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.", + "homepage": "https://getcomposer.org/", + "keywords": [ + "autoload", + "dependency", + "package" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/composer/issues", + "security": "https://github.com/composer/composer/security/policy", + "source": "https://github.com/composer/composer/tree/2.8.6" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2025-02-25T12:03:50+00:00" + }, + { + "name": "composer/metadata-minifier", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/composer/metadata-minifier.git", + "reference": "c549d23829536f0d0e984aaabbf02af91f443207" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/metadata-minifier/zipball/c549d23829536f0d0e984aaabbf02af91f443207", + "reference": "c549d23829536f0d0e984aaabbf02af91f443207", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "composer/composer": "^2", + "phpstan/phpstan": "^0.12.55", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\MetadataMinifier\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Small utility library that handles metadata minification and expansion.", + "keywords": [ + "composer", + "compression" + ], + "support": { + "issues": "https://github.com/composer/metadata-minifier/issues", + "source": "https://github.com/composer/metadata-minifier/tree/1.0.0" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2021-04-07T13:37:33+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, + { + "name": "composer/spdx-licenses", + "version": "1.5.8", + "source": { + "type": "git", + "url": "https://github.com/composer/spdx-licenses.git", + "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", + "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.55", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Spdx\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "SPDX licenses list and validation library.", + "keywords": [ + "license", + "spdx", + "validator" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/spdx-licenses/issues", + "source": "https://github.com/composer/spdx-licenses/tree/1.5.8" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2023-11-20T07:44:33+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-05-06T16:37:16+00:00" + }, + { + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + }, + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "keywords": [ + "PHPCodeSniffer", + "PHP_CodeSniffer", + "code quality", + "codesniffer", + "composer", + "installer", + "phpcbf", + "phpcs", + "plugin", + "qa", + "quality", + "standard", + "standards", + "style guide", + "stylecheck", + "tests" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" + }, + { + "name": "doctrine/sql-formatter", + "version": "1.5.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/sql-formatter.git", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5" + }, + "bin": [ + "bin/sql-formatter" + ], + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\SqlFormatter\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jeremy Dorn", + "email": "jeremy@jeremydorn.com", + "homepage": "https://jeremydorn.com/" + } + ], + "description": "a PHP SQL highlighting library", + "homepage": "https://github.com/doctrine/sql-formatter/", + "keywords": [ + "highlight", + "sql" + ], + "support": { + "issues": "https://github.com/doctrine/sql-formatter/issues", + "source": "https://github.com/doctrine/sql-formatter/tree/1.5.2" + }, + "time": "2025-01-24T11:45:48+00:00" + }, + { + "name": "jasny/twig-extensions", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/jasny/twig-extensions.git", + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/8a5ca5f49317bf421a519556ad2e876820d41e01", + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01", + "shasum": "" + }, + "require": { + "php": ">=7.4.0", + "twig/twig": "^2.7 | ^3.0" + }, + "require-dev": { + "ext-intl": "*", + "ext-json": "*", + "ext-pcre": "*", + "phpstan/phpstan": "^1.12.0", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.10" + }, + "suggest": { + "ext-intl": "Required for the use of the LocalDate Twig extension", + "ext-pcre": "Required for the use of the PCRE Twig extension" + }, + "type": "library", + "autoload": { + "psr-4": { + "Jasny\\Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Arnold Daniels", + "email": "arnold@jasny.net", + "homepage": "http://www.jasny.net" + } + ], + "description": "A set of useful Twig filters", + "homepage": "http://github.com/jasny/twig-extensions#README", + "keywords": [ + "PCRE", + "array", + "date", + "datetime", + "preg", + "regex", + "templating", + "text", + "time" + ], + "support": { + "issues": "https://github.com/jasny/twig-extensions/issues", + "source": "https://github.com/jasny/twig-extensions" + }, + "time": "2024-09-03T09:04:53+00:00" + }, + { + "name": "josegonzalez/dotenv", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/josegonzalez/php-dotenv.git", + "reference": "e97dbd3db53508dcd536e73ec787a7f11458d41d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/josegonzalez/php-dotenv/zipball/e97dbd3db53508dcd536e73ec787a7f11458d41d", + "reference": "e97dbd3db53508dcd536e73ec787a7f11458d41d", + "shasum": "" + }, + "require": { + "m1/env": "2.*", + "php": ">=5.5.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "~2.0", + "php-mock/php-mock-phpunit": "~1.1||~2.0", + "squizlabs/php_codesniffer": "~2.9||~3.7" + }, + "type": "library", + "autoload": { + "psr-0": { + "josegonzalez\\Dotenv": [ + "src", + "tests" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jose Diaz-Gonzalez", + "email": "dotenv@josegonzalez.com", + "homepage": "http://josediazgonzalez.com", + "role": "Maintainer" + } + ], + "description": "dotenv file parsing for PHP", + "homepage": "https://github.com/josegonzalez/php-dotenv", + "keywords": [ + "configuration", + "dotenv", + "php" + ], + "support": { + "issues": "https://github.com/josegonzalez/php-dotenv/issues", + "source": "https://github.com/josegonzalez/php-dotenv/tree/4.0.0" + }, + "time": "2023-05-29T22:49:26+00:00" + }, + { + "name": "justinrainbow/json-schema", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/jsonrainbow/json-schema.git", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "reference": "feb2ca6dd1cebdaf1ed60a4c8de2e53ce11c4fd8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "json-schema/json-schema-test-suite": "1.2.0", + "phpunit/phpunit": "^4.8.35" + }, + "bin": [ + "bin/validate-json" + ], + "type": "library", + "autoload": { + "psr-4": { + "JsonSchema\\": "src/JsonSchema/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bruno Prieto Reis", + "email": "bruno.p.reis@gmail.com" + }, + { + "name": "Justin Rainbow", + "email": "justin.rainbow@gmail.com" + }, + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + }, + { + "name": "Robert Schönthal", + "email": "seroscho@googlemail.com" + } + ], + "description": "A library to validate a json schema.", + "homepage": "https://github.com/justinrainbow/json-schema", + "keywords": [ + "json", + "schema" + ], + "support": { + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/5.3.0" + }, + "time": "2024-07-06T21:00:26+00:00" + }, + { + "name": "m1/env", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/m1/Env.git", + "reference": "5c296e3e13450a207e12b343f3af1d7ab569f6f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/m1/Env/zipball/5c296e3e13450a207e12b343f3af1d7ab569f6f3", + "reference": "5c296e3e13450a207e12b343f3af1d7ab569f6f3", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "scrutinizer/ocular": "~1.1", + "squizlabs/php_codesniffer": "^2.3" + }, + "suggest": { + "josegonzalez/dotenv": "For loading of .env", + "m1/vars": "For loading of configs" + }, + "type": "library", + "autoload": { + "psr-4": { + "M1\\Env\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Miles Croxford", + "email": "hello@milescroxford.com", + "homepage": "http://milescroxford.com", + "role": "Developer" + } + ], + "description": "Env is a lightweight library bringing .env file parser compatibility to PHP. In short - it enables you to read .env files with PHP.", + "homepage": "https://github.com/m1/Env", + "keywords": [ + ".env", + "config", + "dotenv", + "env", + "loader", + "m1", + "parser", + "support" + ], + "support": { + "issues": "https://github.com/m1/Env/issues", + "source": "https://github.com/m1/Env/tree/2.2.0" + }, + "time": "2020-02-19T09:02:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-02-12T12:17:51+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.33.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "reference": "82a311fd3690fb2bf7b64d5c98f912b3dd746140", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^4.15", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.33.0" + }, + "time": "2024-10-13T11:25:22+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "10.1.16", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^4.19.1 || ^5.1.0", + "php": ">=8.1", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^10.1" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-22T04:31:57+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "4.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c", + "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-31T06:24:48+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:56:09+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-31T14:07:24+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:57:52+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "10.5.45", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.12.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.1", + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.3", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "10.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-02-06T16:08:12+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "reference": "c34583b87e7b7a8055bf6c450c2c77ce32a24084", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:12:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503", + "reference": "a81fee9eef0b7a76af11d121767abc44c104e503", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:58:43+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:59:15+00:00" + }, + { + "name": "sebastian/comparator", + "version": "5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/diff": "^5.0", + "sebastian/exporter": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-18T14:56:07+00:00" + }, + { + "name": "sebastian/complexity", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "68ff824baeae169ec9f2137158ee529584553799" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-21T08:37:17+00:00" + }, + { + "name": "sebastian/diff", + "version": "5.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", + "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0", + "symfony/process": "^6.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:15:17+00:00" + }, + { + "name": "sebastian/environment", + "version": "6.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/8074dbcd93529b357029f5cc5058fd3e43666984", + "reference": "8074dbcd93529b357029f5cc5058fd3e43666984", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/6.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-23T08:47:14+00:00" + }, + { + "name": "sebastian/exporter", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/955288482d97c19a372d3f31006ab3f37da47adf", + "reference": "955288482d97c19a372d3f31006ab3f37da47adf", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.1", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:17:12+00:00" + }, + { + "name": "sebastian/global-state", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "reference": "987bafff24ecc4c9ac418cab1145b96dd6e9cbd9", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:19:19+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.18 || ^5.0", + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-12-21T08:38:20+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906", + "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "sebastian/object-reflector": "^3.0", + "sebastian/recursion-context": "^5.0" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:08:32+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957", + "reference": "24ed13d98130f0e7122df55d06c5c4942a577957", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:06:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", + "reference": "05909fb5bc7df4c52992396d0116aed689f93712", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:05:40+00:00" + }, + { + "name": "sebastian/type", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf", + "reference": "462699a16464c3944eefc02ebdd77882bd3925bf", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T07:10:45+00:00" + }, + { + "name": "sebastian/version", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-07T11:34:05+00:00" + }, + { + "name": "seld/jsonlint", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/jsonlint.git", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" + }, + "bin": [ + "bin/jsonlint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Seld\\JsonLint\\": "src/Seld/JsonLint/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "JSON Linter", + "keywords": [ + "json", + "linter", + "parser", + "validator" + ], + "support": { + "issues": "https://github.com/Seldaek/jsonlint/issues", + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/seld/jsonlint", + "type": "tidelift" + } + ], + "time": "2024-07-11T14:55:45+00:00" + }, + { + "name": "seld/phar-utils", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "support": { + "issues": "https://github.com/Seldaek/phar-utils/issues", + "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1" + }, + "time": "2022-08-31T10:31:18+00:00" + }, + { + "name": "seld/signal-handler", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/signal-handler.git", + "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/signal-handler/zipball/04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98", + "reference": "04a6112e883ad76c0ada8e4a9f7520bbfdb6bb98", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "phpstan/phpstan": "^1", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-phpunit": "^1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^7.5.20 || ^8.5.23", + "psr/log": "^1 || ^2 || ^3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\Signal\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Simple unix signal handler that silently fails where signals are not supported for easy cross-platform development", + "keywords": [ + "posix", + "sigint", + "signal", + "sigterm", + "unix" + ], + "support": { + "issues": "https://github.com/Seldaek/signal-handler/issues", + "source": "https://github.com/Seldaek/signal-handler/tree/2.0.2" + }, + "time": "2023-09-03T09:24:00+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.15.0", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "7d1d957421618a3803b593ec31ace470177d7817" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/7d1d957421618a3803b593ec31ace470177d7817", + "reference": "7d1d957421618a3803b593ec31ace470177d7817", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": "^1.23.1", + "squizlabs/php_codesniffer": "^3.9.0" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.10.60", + "phpstan/phpstan-deprecation-rules": "1.1.4", + "phpstan/phpstan-phpunit": "1.3.16", + "phpstan/phpstan-strict-rules": "1.5.2", + "phpunit/phpunit": "8.5.21|9.6.8|10.5.11" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.15.0" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2024-03-09T15:20:58+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "3.11.3", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", + "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" + }, + "bin": [ + "bin/phpcbf", + "bin/phpcs" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "keywords": [ + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" + }, + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + }, + { + "url": "https://thanks.dev/phpcsstandards", + "type": "thanks_dev" + } + ], + "time": "2025-01-23T17:04:15+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:17+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.2.4" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-05T08:33:46+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + }, + { + "name": "twig/markdown-extra", + "version": "v3.20.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/markdown-extra.git", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/f4616e1dd375209dacf6026f846e6b537d036ce4", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" + }, + "require-dev": { + "erusev/parsedown": "dev-master as 1.x-dev", + "league/commonmark": "^1.0|^2.0", + "league/html-to-markdown": "^4.8|^5.0", + "michelf/php-markdown": "^1.8|^2.0", + "symfony/phpunit-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Twig\\Extra\\Markdown\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + } + ], + "description": "A Twig extension for Markdown", + "homepage": "https://twig.symfony.com", + "keywords": [ + "html", + "markdown", + "twig" + ], + "support": { + "source": "https://github.com/twigphp/markdown-extra/tree/v3.20.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-01-31T20:45:36+00:00" + }, + { + "name": "twig/twig", + "version": "v3.20.0", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "3468920399451a384bef53cf7996965f7cd40183" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183", + "reference": "3468920399451a384bef53cf7996965f7cd40183", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.20.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-02-13T08:34:43+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.1" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/idrocap_wa/config/.env.example b/idrocap_wa/config/.env.example new file mode 100644 index 0000000..e90937b --- /dev/null +++ b/idrocap_wa/config/.env.example @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Used as a default to seed config/.env which +# enables you to use environment variables to configure +# the aspects of your application that vary by +# environment. +# +# Having this file in production is considered a **SECURITY RISK** and also decreases +# the bootstrap performance of your application. +# +# To use this file, first copy it into `config/.env`. Also ensure the related +# code block for loading this file is uncommented in `config/bootstrap.php` +# +# In development .env files are parsed by PHP +# and set into the environment. This provides a simpler +# development workflow over standard environment variables. +export APP_NAME="__APP_NAME__" +export DEBUG="true" +export APP_ENCODING="UTF-8" +export APP_DEFAULT_LOCALE="en_US" +export APP_DEFAULT_TIMEZONE="UTC" +export SECURITY_SALT="__SALT__" + +# Uncomment these to define cache configuration via environment variables. +#export CACHE_DURATION="+2 minutes" +#export CACHE_DEFAULT_URL="file:///path/to/tmp/cache/?prefix=${APP_NAME}_default_&duration=${CACHE_DURATION}" +#export CACHE_CAKECORE_URL="file:///path/to/tmp/cache/persistent?prefix=${APP_NAME}_cake_core_&serialize=true&duration=${CACHE_DURATION}" +#export CACHE_CAKEMODEL_URL="file:///path/to/tmp/cache/models?prefix=${APP_NAME}_cake_model_&serialize=true&duration=${CACHE_DURATION}" + +# Uncomment these to define email transport configuration via environment variables. +#export EMAIL_TRANSPORT_DEFAULT_URL="" + +# Uncomment these to define database configuration via environment variables. +#export DATABASE_URL="mysql://my_app:secret@localhost/${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" +#export DATABASE_TEST_URL="mysql://my_app:secret@localhost/test_${APP_NAME}?encoding=utf8&timezone=UTC&cacheMetadata=true"eIdentifiers=false&persistent=false" + +# Uncomment these to define logging configuration via environment variables. +#export LOG_DEBUG_URL="file:///path/to/logs/?levels[]=notice&levels[]=info&levels[]=debug&file=debug" +#export LOG_ERROR_URL="file:///path/to/logs/?levels[]=warning&levels[]=error&levels[]=critical&levels[]=alert&levels[]=emergency&file=error" diff --git a/idrocap_wa/config/app.php b/idrocap_wa/config/app.php new file mode 100644 index 0000000..f8f6a0b --- /dev/null +++ b/idrocap_wa/config/app.php @@ -0,0 +1,436 @@ + filter_var(env('DEBUG', false), FILTER_VALIDATE_BOOLEAN), + + /* + * Configure basic information about the application. + * + * - namespace - The namespace to find app classes under. + * - defaultLocale - The default locale for translation, formatting currencies and numbers, date and time. + * - encoding - The encoding used for HTML + database connections. + * - base - The base directory the app resides in. If false this + * will be auto detected. + * - dir - Name of app directory. + * - webroot - The webroot directory. + * - wwwRoot - The file path to webroot. + * - baseUrl - To configure CakePHP to *not* use mod_rewrite and to + * use CakePHP pretty URLs, remove these .htaccess + * files: + * /.htaccess + * /webroot/.htaccess + * And uncomment the baseUrl key below. + * - fullBaseUrl - A base URL to use for absolute links. When set to false (default) + * CakePHP generates required value based on `HTTP_HOST` environment variable. + * However, you can define it manually to optimize performance or if you + * are concerned about people manipulating the `Host` header. + * - imageBaseUrl - Web path to the public images directory under webroot. + * - cssBaseUrl - Web path to the public css directory under webroot. + * - jsBaseUrl - Web path to the public js directory under webroot. + * - paths - Configure paths for non class based resources. Supports the + * `plugins`, `templates`, `locales` subkeys, which allow the definition of + * paths for plugins, view templates and locale files respectively. + */ + 'App' => [ + 'namespace' => 'App', + 'encoding' => env('APP_ENCODING', 'UTF-8'), + 'defaultLocale' => env('APP_DEFAULT_LOCALE', 'it'), + 'defaultTimezone' => env('APP_DEFAULT_TIMEZONE', 'UTC'), + 'defaultUserTimezone' => 'Europe/Rome', + 'base' => false, + 'dir' => 'src', + 'webroot' => 'webroot', + 'wwwRoot' => WWW_ROOT, + //'baseUrl' => env('SCRIPT_NAME'), + 'fullBaseUrl' => false, + 'imageBaseUrl' => 'img/', + 'cssBaseUrl' => 'css/', + 'jsBaseUrl' => 'js/', + 'paths' => [ + 'plugins' => [ROOT . DS . 'plugins' . DS], + 'templates' => [ROOT . DS . 'templates' . DS], + 'locales' => [RESOURCES . 'locales' . DS], + ], + ], + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT'), + ], + + /* + * Apply timestamps with the last modified time to static assets (js, css, images). + * Will append a querystring parameter containing the time the file was modified. + * This is useful for busting browser caches. + * + * Set to true to apply timestamps when debug is true. Set to 'force' to always + * enable timestamping regardless of debug value. + */ + 'Asset' => [ + //'timestamp' => true, + // 'cacheTime' => '+1 year' + ], + + /* + * Configure the cache adapters. + */ + 'Cache' => [ + 'default' => [ + 'className' => RedisEngine::class, + 'database' => 1, + 'duration' => 3600, + 'groups' => [], + 'password' => false, + 'persistent' => true, + 'port' => 6379, + 'prefix' => '', + 'probability' => 100, + 'host' => null, + 'server' => 'redis', + 'timeout' => 0, + 'unix_socket' => false, + ], + + /* + * Configure the cache used for general framework caching. + * Translation cache files are stored with this configuration. + * Duration will be set to '+2 minutes' in bootstrap.php when debug = true + * If you set 'className' => 'Null' core cache will be disabled. + */ + '_cake_translations_' => [ + 'className' => FileEngine::class, + 'prefix' => 'myapp_cake_core_', + 'path' => CACHE . 'persistent' . DS, + 'serialize' => true, + 'duration' => '+1 years', + 'url' => env('CACHE_CAKECORE_URL', null), + ], + + /* + * Configure the cache for model and datasource caches. This cache + * configuration is used to store schema descriptions, and table listings + * in connections. + * Duration will be set to '+2 minutes' in bootstrap.php when debug = true + */ + '_cake_model_' => [ + 'className' => FileEngine::class, + 'prefix' => 'myapp_cake_model_', + 'path' => CACHE . 'models' . DS, + 'serialize' => true, + 'duration' => '+1 years', + 'url' => env('CACHE_CAKEMODEL_URL', null), + ], + ], + + /* + * Configure the Error and Exception handlers used by your application. + * + * By default errors are displayed using Debugger, when debug is true and logged + * by Cake\Log\Log when debug is false. + * + * In CLI environments exceptions will be printed to stderr with a backtrace. + * In web environments an HTML page will be displayed for the exception. + * With debug true, framework errors like Missing Controller will be displayed. + * When debug is false, framework errors will be coerced into generic HTTP errors. + * + * Options: + * + * - `errorLevel` - int - The level of errors you are interested in capturing. + * - `trace` - boolean - Whether backtraces should be included in + * logged errors/exceptions. + * - `log` - boolean - Whether you want exceptions logged. + * - `exceptionRenderer` - string - The class responsible for rendering uncaught exceptions. + * The chosen class will be used for both CLI and web environments. If you want different + * classes used in CLI and web environments you'll need to write that conditional logic as well. + * The conventional location for custom renderers is in `src/Error`. Your exception renderer needs to + * implement the `render()` method and return either a string or Http\Response. + * `errorRenderer` - string - The class responsible for rendering PHP errors. The selected + * class will be used for both web and CLI contexts. If you want different classes for each environment + * you'll need to write that conditional logic as well. Error renderers need to + * to implement the `Cake\Error\ErrorRendererInterface`. + * - `skipLog` - array - List of exceptions to skip for logging. Exceptions that + * extend one of the listed exceptions will also be skipped for logging. + * E.g.: + * `'skipLog' => ['Cake\Http\Exception\NotFoundException', 'Cake\Http\Exception\UnauthorizedException']` + * - `extraFatalErrorMemory` - int - The number of megabytes to increase the memory limit by + * when a fatal error is encountered. This allows + * breathing room to complete logging or error handling. + * - `ignoredDeprecationPaths` - array - A list of glob compatible file paths that deprecations + * should be ignored in. Use this to ignore deprecations for plugins or parts of + * your application that still emit deprecations. + */ + 'Error' => [ + 'errorLevel' => E_ALL, + 'skipLog' => [], + 'log' => true, + 'trace' => true, + 'ignoredDeprecationPaths' => [], + 'exceptionRenderer' => 'App\Error\AppExceptionRenderer', + ], + + /* + * Debugger configuration + * + * Define development error values for Cake\Error\Debugger + * + * - `editor` Set the editor URL format you want to use. + * By default atom, emacs, macvim, phpstorm, sublime, textmate, and vscode are + * available. You can add additional editor link formats using + * `Debugger::addEditor()` during your application bootstrap. + * - `outputMask` A mapping of `key` to `replacement` values that + * `Debugger` should replace in dumped data and logs generated by `Debugger`. + */ + 'Debugger' => [ + 'editor' => 'phpstorm', + ], + + /* + * Email configuration. + * + * By defining transports separately from delivery profiles you can easily + * re-use transport configuration across multiple profiles. + * + * You can specify multiple configurations for production, development and + * testing. + * + * Each transport needs a `className`. Valid options are as follows: + * + * Mail - Send using PHP mail function + * Smtp - Send using SMTP + * Debug - Do not send the email, just return the result + * + * You can add custom transports (or override existing transports) by adding the + * appropriate file to src/Mailer/Transport. Transports should be named + * 'YourTransport.php', where 'Your' is the name of the transport. + */ + 'EmailTransport' => [ + 'default' => [ + 'className' => MailTransport::class, + /* + * The keys host, port, timeout, username, password, client and tls + * are used in SMTP transports + */ + 'host' => 'localhost', + 'port' => 25, + 'timeout' => 30, + /* + * It is recommended to set these options through your environment or app_local.php + */ + //'username' => null, + //'password' => null, + 'client' => null, + 'tls' => false, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], + + /* + * Email delivery profiles + * + * Delivery profiles allow you to predefine various properties about email + * messages from your application and give the settings a name. This saves + * duplication across your application and makes maintenance and development + * easier. Each profile accepts a number of keys. See `Cake\Mailer\Email` + * for more information. + */ + 'Email' => [ + 'default' => [ + 'transport' => 'default', + 'from' => 'you@localhost', + /* + * Will by default be set to config value of App.encoding, if that exists otherwise to UTF-8. + */ + //'charset' => 'utf-8', + //'headerCharset' => 'utf-8', + ], + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * ### Notes + * - Drivers include Mysql Postgres Sqlite Sqlserver + * See vendor\cakephp\cakephp\src\Database\Driver for complete list + * - Do not use periods in database name - it may lead to error. + * See https://github.com/cakephp/cakephp/issues/6471 for details. + * - 'encoding' is recommended to be set to full UTF-8 4-Byte support. + * E.g set it to 'utf8mb4' in MariaDB and MySQL and 'utf8' for any + * other RDBMS. + */ + 'Datasources' => [ + /* + * These configurations should contain permanent settings used + * by all environments. + * + * The values in app_local.php will override any values set here + * and should be used for local and per-environment configurations. + * + * Environment variable based configurations can be loaded here or + * in app_local.php depending on the applications needs. + */ + 'default' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + + /* + * For MariaDB/MySQL the internal default changed from utf8 to utf8mb4, aka full utf-8 support, in CakePHP 3.6 + */ + //'encoding' => 'utf8mb4', + + /* + * If your MySQL server is configured with `skip-character-set-client-handshake` + * then you MUST use the `flags` config to set your charset encoding. + * For e.g. `'flags' => [\PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4']` + */ + 'flags' => [], + 'cacheMetadata' => true, + 'log' => false, + + /* + * Set identifier quoting to true if you are using reserved words or + * special characters in your table or column names. Enabling this + * setting will result in queries built using the Query Builder having + * identifiers quoted when creating SQL. It should be noted that this + * decreases performance because each query needs to be traversed and + * manipulated before being executed. + */ + 'quoteIdentifiers' => true, + + /* + * During development, if using MySQL < 5.6, uncommenting the + * following line could boost the speed at which schema metadata is + * fetched from the database. It can also be set directly with the + * mysql configuration directive 'innodb_stats_on_metadata = 0' + * which is the recommended value in production environments + */ + //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], + ], + + 'geo' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + 'encoding' => 'utf8', + 'flags' => [], + 'cacheMetadata' => true, + 'log' => false, + 'quoteIdentifiers' => false, + ], + + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'className' => Connection::class, + 'driver' => Mysql::class, + 'persistent' => false, + 'timezone' => 'UTC', + //'encoding' => 'utf8mb4', + 'flags' => [], + 'cacheMetadata' => true, + 'quoteIdentifiers' => false, + 'log' => false, + //'init' => ['SET GLOBAL innodb_stats_on_metadata = 0'], + ], + ], + + /* + * Configures logging options + */ + 'Log' => [ + 'debug' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'debug', + 'url' => env('LOG_DEBUG_URL', null), + 'scopes' => null, + 'levels' => ['notice', 'info', 'debug'], + ], + 'error' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'error', + 'url' => env('LOG_ERROR_URL', null), + 'scopes' => null, + 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], + ], + // To enable this dedicated query log, you need set your datasource's log flag to true + 'queries' => [ + 'className' => FileLog::class, + 'path' => LOGS, + 'file' => 'queries', + 'url' => env('LOG_QUERIES_URL', null), + 'scopes' => ['cake.database.queries'], + ], + ], + + /* + * Session configuration. + * + * Contains an array of settings to use for session configuration. The + * `defaults` key is used to define a default preset to use for sessions, any + * settings declared here will override the settings of the default config. + * + * ## Options + * + * - `cookie` - The name of the cookie to use. Defaults to value set for `session.name` php.ini config. + * Avoid using `.` in cookie names, as PHP will drop sessions from cookies with `.` in the name. + * - `cookiePath` - The url path for which session cookie is set. Maps to the + * `session.cookie_path` php.ini config. Defaults to base path of app. + * - `timeout` - The time in minutes the session should be valid for. + * Pass 0 to disable checking timeout. + * Please note that php.ini's session.gc_maxlifetime must be equal to or greater + * than the largest Session['timeout'] in all served websites for it to have the + * desired effect. + * - `defaults` - The default configuration set to use as a basis for your session. + * There are four built-in options: php, cake, cache, database. + * - `handler` - Can be used to enable a custom session handler. Expects an + * array with at least the `engine` key, being the name of the Session engine + * class to use for managing the session. CakePHP bundles the `CacheSession` + * and `DatabaseSession` engines. + * - `ini` - An associative array of additional 'session.*` ini values to set. + * + * The built-in `defaults` options are: + * + * - 'php' - Uses settings defined in your php.ini. + * - 'cake' - Saves session files in CakePHP's /tmp directory. + * - 'database' - Uses CakePHP's database sessions. + * - 'cache' - Use the Cache class to save sessions. + * + * To define a custom session handler, save it at src/Http/Session/.php. + * Make sure the class implements PHP's `SessionHandlerInterface` and set + * Session.handler to + * + * To use database sessions, load the SQL file located at config/schema/sessions.sql + */ + 'Session' => [ + 'cookie' => 'JIXEL', + 'defaults' => 'cache', + ], +]; diff --git a/idrocap_wa/config/app_local.example.php b/idrocap_wa/config/app_local.example.php new file mode 100644 index 0000000..8bdb855 --- /dev/null +++ b/idrocap_wa/config/app_local.example.php @@ -0,0 +1,94 @@ + filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT', '__SALT__'), + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * See app.php for more configuration options. + */ + 'Datasources' => [ + 'default' => [ + 'host' => 'localhost', + /* + * CakePHP will use the default DB port based on the driver selected + * MySQL on MAMP uses port 8889, MAMP users will want to uncomment + * the following line and set the port accordingly + */ + //'port' => 'non_standard_port_number', + + 'username' => 'my_app', + 'password' => 'secret', + + 'database' => 'my_app', + /* + * If not using the default 'public' schema with the PostgreSQL driver + * set it here. + */ + //'schema' => 'myapp', + + /* + * You can use a DSN string to set the entire configuration + */ + 'url' => env('DATABASE_URL', null), + ], + + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'host' => 'localhost', + //'port' => 'non_standard_port_number', + 'username' => 'my_app', + 'password' => 'secret', + 'database' => 'test_myapp', + //'schema' => 'myapp', + 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tmp/tests.sqlite'), + ], + ], + + /* + * Email configuration. + * + * Host and credential configuration in case you are using SmtpTransport + * + * See app.php for more configuration options. + */ + 'EmailTransport' => [ + 'default' => [ + 'host' => 'localhost', + 'port' => 25, + 'username' => null, + 'password' => null, + 'client' => null, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], +]; diff --git a/idrocap_wa/config/app_local.php b/idrocap_wa/config/app_local.php new file mode 100644 index 0000000..eb0c81e --- /dev/null +++ b/idrocap_wa/config/app_local.php @@ -0,0 +1,94 @@ + filter_var(env('DEBUG', true), FILTER_VALIDATE_BOOLEAN), + + /* + * Security and encryption configuration + * + * - salt - A random string used in security hashing methods. + * The salt value is also used as the encryption key. + * You should treat it as extremely sensitive data. + */ + 'Security' => [ + 'salt' => env('SECURITY_SALT', '1d8f10d21d25f4efea479140b503d0c32a7aac909d93d0a48bb9e153d49a0449'), + ], + + /* + * Connection information used by the ORM to connect + * to your application's datastores. + * + * See app.php for more configuration options. + */ + 'Datasources' => [ + 'default' => [ + 'host' => 'localhost', + /* + * CakePHP will use the default DB port based on the driver selected + * MySQL on MAMP uses port 8889, MAMP users will want to uncomment + * the following line and set the port accordingly + */ + //'port' => 'non_standard_port_number', + + 'username' => 'my_app', + 'password' => 'secret', + + 'database' => 'my_app', + /* + * If not using the default 'public' schema with the PostgreSQL driver + * set it here. + */ + //'schema' => 'myapp', + + /* + * You can use a DSN string to set the entire configuration + */ + 'url' => env('DATABASE_URL', null), + ], + + /* + * The test connection is used during the test suite. + */ + 'test' => [ + 'host' => 'localhost', + //'port' => 'non_standard_port_number', + 'username' => 'my_app', + 'password' => 'secret', + 'database' => 'test_myapp', + //'schema' => 'myapp', + 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tmp/tests.sqlite'), + ], + ], + + /* + * Email configuration. + * + * Host and credential configuration in case you are using SmtpTransport + * + * See app.php for more configuration options. + */ + 'EmailTransport' => [ + 'default' => [ + 'host' => 'localhost', + 'port' => 25, + 'username' => null, + 'password' => null, + 'client' => null, + 'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null), + ], + ], +]; diff --git a/idrocap_wa/config/bootstrap.php b/idrocap_wa/config/bootstrap.php new file mode 100644 index 0000000..9c0aaaa --- /dev/null +++ b/idrocap_wa/config/bootstrap.php @@ -0,0 +1,231 @@ +parse() +// ->putenv() +// ->toEnv() +// ->toServer(); +// } + +/* + * Read configuration file and inject configuration into various + * CakePHP classes. + * + * By default there is only one configuration file. It is often a good + * idea to create multiple configuration files, and separate the configuration + * that changes from configuration that does not. This makes deployment simpler. + */ +try { + Configure::config('default', new PhpConfig()); + Configure::load('app', 'default', false); +} catch (\Exception $e) { + exit($e->getMessage() . "\n"); +} + +/* + * Load an environment local configuration file to provide overrides to your configuration. + * Notice: For security reasons app_local.php **should not** be included in your git repo. + */ +if (file_exists(CONFIG . 'app_local.php')) { + Configure::load('app_local', 'default'); +} + +/* + * When debug = true the metadata cache should only last + * for a short time. + */ +if (Configure::read('debug')) { + Configure::write('Cache._cake_model_.duration', '+2 minutes'); + Configure::write('Cache._cake_core_.duration', '+2 minutes'); + // disable router cache during development + Configure::write('Cache._cake_routes_.duration', '+2 seconds'); +} + +/* + * Set the default server timezone. Using UTC makes time calculations / conversions easier. + * Check https://php.net/manual/en/timezones.php for list of valid timezone strings. + */ +date_default_timezone_set(Configure::read('App.defaultTimezone')); + +/* + * Configure the mbstring extension to use the correct encoding. + */ +mb_internal_encoding(Configure::read('App.encoding')); + +/* + * Set the default locale. This controls how dates, number and currency is + * formatted and sets the default language to use for translations. + */ +ini_set('intl.default_locale', Configure::read('App.defaultLocale')); + +/* + * Register application error and exception handlers. + */ +(new ErrorTrap(Configure::read('Error')))->register(); +(new ExceptionTrap(Configure::read('Error')))->register(); + +/* + * Include the CLI bootstrap overrides. + */ +if (PHP_SAPI === 'cli') { + require CONFIG . 'bootstrap_cli.php'; +} + +/* + * Set the full base URL. + * This URL is used as the base of all absolute links. + */ +$fullBaseUrl = Configure::read('App.fullBaseUrl'); +if (!$fullBaseUrl) { + /* + * When using proxies or load balancers, SSL/TLS connections might + * get terminated before reaching the server. If you trust the proxy, + * you can enable `$trustProxy` to rely on the `X-Forwarded-Proto` + * header to determine whether to generate URLs using `https`. + * + * See also https://book.cakephp.org/4/en/controllers/request-response.html#trusting-proxy-headers + */ + $trustProxy = false; + + $s = null; + if (env('HTTPS') || ($trustProxy && env('HTTP_X_FORWARDED_PROTO') === 'https')) { + $s = 's'; + } + + $httpHost = env('HTTP_HOST'); + if (isset($httpHost)) { + $fullBaseUrl = 'http' . $s . '://' . $httpHost; + } + unset($httpHost, $s); +} +if ($fullBaseUrl) { + Router::fullBaseUrl($fullBaseUrl); +} +unset($fullBaseUrl); + +Cache::setConfig(Configure::consume('Cache')); +ConnectionManager::setConfig(Configure::consume('Datasources')); +TransportFactory::setConfig(Configure::consume('EmailTransport')); +Mailer::setConfig(Configure::consume('Email')); +Log::setConfig(Configure::consume('Log')); +Security::setSalt(Configure::consume('Security.salt')); + +/* + * Setup detectors for mobile and tablet. + * If you don't use these checks you can safely remove this code + * and the mobiledetect package from composer.json. + */ +ServerRequest::addDetector('mobile', function ($request) { + $detector = new \Detection\MobileDetect(); + + return $detector->isMobile(); +}); +ServerRequest::addDetector('tablet', function ($request) { + $detector = new \Detection\MobileDetect(); + + return $detector->isTablet(); +}); + +/* + * You can enable default locale format parsing by adding calls + * to `useLocaleParser()`. This enables the automatic conversion of + * locale specific date formats. For details see + * @link https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html#parsing-localized-datetime-data + */ +// \Cake\Database\TypeFactory::build('time') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('date') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetime') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestamp') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetimefractional') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestampfractional') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('datetimetimezone') +// ->useLocaleParser(); +// \Cake\Database\TypeFactory::build('timestamptimezone') +// ->useLocaleParser(); + +/* + * Custom Inflector rules, can be set to correctly pluralize or singularize + * table, model, controller names or whatever other string is passed to the + * inflection functions. + */ +//Inflector::rules('plural', ['/^(inflect)or$/i' => '\1ables']); +//Inflector::rules('irregular', ['red' => 'redlings']); +//Inflector::rules('uninflected', ['dontinflectme']); + +// set a custom date and time format +// see https://book.cakephp.org/4/en/core-libraries/time.html#setting-the-default-locale-and-format-string +// and https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax +//\Cake\I18n\FrozenDate::setToStringFormat('dd.MM.yyyy'); +//\Cake\I18n\FrozenTime::setToStringFormat('dd.MM.yyyy HH:mm'); diff --git a/idrocap_wa/config/bootstrap_cli.php b/idrocap_wa/config/bootstrap_cli.php new file mode 100644 index 0000000..fc0dc30 --- /dev/null +++ b/idrocap_wa/config/bootstrap_cli.php @@ -0,0 +1,35 @@ + [ + 'app-name' => '' . Configure::read('Theme.title') . '', + 'app-logo' => Configure::read('Theme.logo'), + + 'small-text' => false, + 'dark-mode' => false, + 'layout-boxed' => false, + + 'header' => [ + 'fixed' => false, + 'border' => true, + 'style' => Header::STYLE_DARK, + 'dropdown-legacy' => false, + ], + + 'sidebar' => [ + 'fixed' => true, + 'collapsed' => false, + 'mini' => true, + 'mini-md' => false, + 'mini-xs' => false, + 'style' => Sidebar::STYLE_DARK_PRIMARY, + + 'flat-style' => false, + 'legacy-style' => false, + 'compact' => false, + 'child-indent' => true, + 'child-hide-collapse' => false, + 'disabled-auto-expand' => false, + ], + + 'footer' => [ + 'fixed' => false, + ], + ], +]; \ No newline at end of file diff --git a/idrocap_wa/config/keys/private.key b/idrocap_wa/config/keys/private.key new file mode 100644 index 0000000..7a309aa --- /dev/null +++ b/idrocap_wa/config/keys/private.key @@ -0,0 +1,52 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- + diff --git a/idrocap_wa/config/keys/public.key b/idrocap_wa/config/keys/public.key new file mode 100644 index 0000000..fc7f1a9 --- /dev/null +++ b/idrocap_wa/config/keys/public.key @@ -0,0 +1,15 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0YVnol1T7RaJIiMDiivC +1bgDyqn2b31j+t8NQXcLm7dOq8azWgsn3ySGj1Was/Mlye5uCegnj9LPOvK6b6wG +4NcNKEouAdjwoZ8PFsTZU2q/lGzrZe4Kc/E19oVgdKRhTgDuCKq7sShC7Un+2lY0 +CCt2GSA133Mqoztih5Y+zvlqyKaMxF6eNy62L1IqNUWEMFIgkVq4Jy2XMii7qrYd +E9cJbleZ1MDlTO7a0v3bhLxdC5D62HPcalV3qYKiCWX/EhCz4b8JWfoW8tfV8GoE +X+6JV+AohOXC9wdopCV89SJu1x+Sp4yWkBtm1nSMifaPfXqyz9tiGFL8ziJpEW59 +lTgbd1KZMCcoGIHR8gq7PowDVkAQIdU628DS3FPgBgPRV7r9oPuytjPzojmuu64a +ClgWylE6WDn2daBHUHtlY0NLA7VNjIMMnvnlM0OBGGN4god4LVzFZkgso36i6RJg +hYUiKaz7DOQEMEGx6bWQlHxnLR0/khv/1ERpKNWq/q0vXeoNA7L1jZ64k3U/MyWm +aJPdjcoPFGYI2Vwlz//M1TZmyoV7YC01YJcsTbA5+ocukOZDlvsEWZKWJoi/I5vY +cQfBZGrAY8pl7LFCVlnpUR+UHB3aFp0+Q4OK0OhQuOmbMqz2J/t2MbWXwBsnQkP3 +XNnoA1t4fbraPeex25NTZVMCAwEAAQ== +-----END PUBLIC KEY----- + diff --git a/idrocap_wa/config/paths.php b/idrocap_wa/config/paths.php new file mode 100644 index 0000000..fcd260d --- /dev/null +++ b/idrocap_wa/config/paths.php @@ -0,0 +1,94 @@ + [ + 'onlyDebug' => true, + ], + 'Bake' => [ + 'onlyCli' => true, + 'optional' => true, + ], + 'Migrations' => [ + 'onlyCli' => true, + ], + 'CakeLte' => [], +]; diff --git a/idrocap_wa/config/routes.php b/idrocap_wa/config/routes.php new file mode 100644 index 0000000..a7f36a7 --- /dev/null +++ b/idrocap_wa/config/routes.php @@ -0,0 +1,357 @@ +setRouteClass(InflectedRoute::class); + + $routes->prefix('Api', function (RouteBuilder $routes) { + $routes->setExtensions(['json', 'csv']); + + $routes->resources('Attachments', [ + 'id' => '.*', + ]); + + $routes->resources('Notifications', [ + 'map' => [ + '' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'index' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'count' => [ + 'action' => 'count', + 'method' => ['GET'], + ], + 'edit/{id}' => [ + 'action' => 'edit', + 'method' => ['POST'], + ], + 'check' => [ + 'action' => 'check', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('Organisations', [ + 'connectOptions' => [ + 'photo' => '.*', + 'pass' => ['id', 'photo'], + ], + 'map' => [ + 'get_photo/{photo}' => [ + 'action' => 'getPhoto', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('OrganisationTypes', ['inflect' => 'underscore']); + + $routes->resources('Users', [ + 'connectOptions' => [ + 'photo' => '.*', + 'pass' => ['id', 'photo'], + ], + 'map' => [ + 'login' => [ + 'action' => 'login', + 'method' => ['POST', 'GET'], + ], + 'get_photo/{photo}' => [ + 'action' => 'getPhoto', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('Subscriptions', [ + 'map' => [ + 'subscribe' => [ + 'action' => 'subscribe', + 'method' => ['POST'], + ], + 'unsubscribe' => [ + 'action' => 'unsubscribe', + 'method' => ['DELETE'], + ], + ], + ]); + + $routes->resources('WaterDrawingPaperworks', [ + 'inflect' => 'underscore', + 'map' => [ + '' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'index' => [ + 'action' => 'index', + 'method' => ['GET'], + ], + 'view/{id}' => [ + 'action' => 'view', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('WaterDrawingDerivations', [ + 'inflect' => 'underscore', + 'map' => [ + 'update_data' => [ + 'action' => 'update_data', + 'method' => ['POST'], + ], + 'update_location' => [ + 'action' => 'update_location', + 'method' => ['POST'], + ], + 'view/{id}' => [ + 'action' => 'view', + 'method' => ['GET'], + ], + ], + ]); + + $routes->resources('WaterDrawingMeasurements', [ + 'inflect' => 'underscore', + 'map' => [ + 'add' => [ + 'action' => 'add', + 'method' => ['POST'], + ], + 'last_index/{id}' => [ + 'action' => 'last_index', + 'method' => ['GET'], + ], + ], + ]); + }); + + $routes->scope('/', function (RouteBuilder $builder) { + $builder->setExtensions(['json', 'csv']); + + $builder->connect('/', ['controller' => 'Dashboard', 'action' => 'index']); + + $builder->connect('/attachments/view/{id}', ['controller' => 'Attachments', 'action' => 'view'])->setPass(['id']); + $builder->connect('/attachments/markAsRelevant/{id}', ['controller' => 'Attachments', 'action' => 'markAsRelevant'])->setPass(['id']); + $builder->connect('/attachments/markAsDeleted/{id}', ['controller' => 'Attachments', 'action' => 'markAsDeleted'])->setPass(['id']); + + $builder->connect('/capabilities', ['controller' => 'Capabilities', 'action' => 'index']); + $builder->connect('/capabilities/index', ['controller' => 'Capabilities', 'action' => 'index']); + $builder->connect('/capabilities/hide/{id}', ['controller' => 'Capabilities', 'action' => 'hide'])->setPass(['id']); + $builder->connect('/capabilities/show/{id}', ['controller' => 'Capabilities', 'action' => 'show'])->setPass(['id']); + $builder->connect('/capabilities/delete/{id}', ['controller' => 'Capabilities', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/capabilities/restore/{id}', ['controller' => 'Capabilities', 'action' => 'restore'])->setPass(['id']); + + $builder->connect('/controllable_objects/getAttachments/{id}', ['controller' => 'ControllableObjects', 'action' => 'getAttachments'])->setPass(['id']); + + $builder->connect('/deliveries/{id}', ['controller' => 'Deliveries', 'action' => 'index'])->setPass(['id']); + $builder->connect('/deliveries/index/{id}', ['controller' => 'Deliveries', 'action' => 'index'])->setPass(['id']); + $builder->connect('/deliveries/delete/{id}', ['controller' => 'Deliveries', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/emails/add/{id}', ['controller' => 'Emails', 'action' => 'add'])->setPass(['id']); + $builder->connect('/emails/edit/{id}', ['controller' => 'Emails', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/faxes/add/{id}', ['controller' => 'Faxes', 'action' => 'add'])->setPass(['id']); + $builder->connect('/faxes/edit/{id}', ['controller' => 'Faxes', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/filters/getFilterInput/{id}', ['controller' => 'Filters', 'action' => 'getFilterInput'])->setPass(['id']); + + $builder->connect('/groups', ['controller' => 'Groups', 'action' => 'index']); + $builder->connect('/groups/index', ['controller' => 'Groups', 'action' => 'index']); + $builder->connect('/groups/add', ['controller' => 'Groups', 'action' => 'add']); + $builder->connect('/groups/view/{id}', ['controller' => 'Groups', 'action' => 'view'])->setPass(['id']); + $builder->connect('/groups/edit/{id}', ['controller' => 'Groups', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/groups/delete/{id}', ['controller' => 'Groups', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/groups/handleCapabilities/{id}', ['controller' => 'Groups', 'action' => 'handleCapabilities'])->setPass(['id']); + + $builder->connect('/maps', ['controller' => 'Maps', 'action' => 'index']); + $builder->connect('/maps/index', ['controller' => 'Maps', 'action' => 'index']); + $builder->connect('/maps/getWfs', ['controller' => 'Maps', 'action' => 'getWfs']); + $builder->connect('/maps/geocode', ['controller' => 'Maps', 'action' => 'geocode']); + + $builder->connect('/mobile_phones/add/{id}', ['controller' => 'MobilePhones', 'action' => 'add'])->setPass(['id']); + $builder->connect('/mobile_phones/edit/{id}', ['controller' => 'MobilePhones', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/notifications', ['controller' => 'Notifications', 'action' => 'index']); + $builder->connect('/notifications/index', ['controller' => 'Notifications', 'action' => 'index']); + $builder->connect('/notifications/readAll', ['controller' => 'Notifications', 'action' => 'readAll']); + $builder->connect('/notifications/testAll', ['controller' => 'Notifications', 'action' => 'testAll']); + $builder->connect('/notifications/view/{id}', ['controller' => 'Notifications', 'action' => 'view'])->setPass(['id']); + + $builder->connect('/organisations', ['controller' => 'Organisations', 'action' => 'index']); + $builder->connect('/organisations/index', ['controller' => 'Organisations', 'action' => 'index']); + $builder->connect('/organisations/add', ['controller' => 'Organisations', 'action' => 'add']); + $builder->connect('/organisations/view/{id}', ['controller' => 'Organisations', 'action' => 'view'])->setPass(['id']); + $builder->connect('/organisations/edit/{id}', ['controller' => 'Organisations', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/organisations/delete/{id}', ['controller' => 'Organisations', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/phones/add/{id}', ['controller' => 'Phones', 'action' => 'add'])->setPass(['id']); + $builder->connect('/phones/edit/{id}', ['controller' => 'Phones', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/telegram_chats/add/{id}', ['controller' => 'TelegramChats', 'action' => 'add'])->setPass(['id']); + $builder->connect('/telegram_chats/edit/{id}', ['controller' => 'TelegramChats', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/users', ['controller' => 'Users', 'action' => 'index']); + $builder->connect('/users/login_oidc', ['controller' => 'Users', 'action' => 'login_oidc']); + $builder->connect('/users/login_oidc_authenticated', ['controller' => 'Users', 'action' => 'login_oidc_authenticated']); + $builder->connect('/users/index', ['controller' => 'Users', 'action' => 'index']); + $builder->connect('/users/add', ['controller' => 'Users', 'action' => 'add']); + $builder->connect('/users/view/{id}', ['controller' => 'Users', 'action' => 'view'])->setPass(['id']); + $builder->connect('/users/edit/{id}', ['controller' => 'Users', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/users/delete/{id}', ['controller' => 'Users', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/users/login', ['controller' => 'Users', 'action' => 'login']); + $builder->connect('/users/logout', ['controller' => 'Users', 'action' => 'logout']); + $builder->connect('/users/passwordRecovery', ['controller' => 'Users', 'action' => 'passwordRecovery']); + $builder->connect('/users/chooseNewPassword/{id}', ['controller' => 'Users', 'action' => 'chooseNewPassword'])->setPass(['id']); + $builder->connect('/users/oneTimePassword/{otp}', ['controller' => 'Users', 'action' => 'oneTimePassword'])->setPass(['otp']); + $builder->connect('/users/getPhoto/{id}', ['controller' => 'Users', 'action' => 'getPhoto'])->setPass(['id']); + $builder->connect('/users/deleteUserPhoto/{id}', ['controller' => 'Users', 'action' => 'deleteUserPhoto'])->setPass(['id']); + $builder->connect('/users/add-citizen', ['controller' => 'Users', 'action' => 'add_citizen']); + $builder->connect('/users/verify-citizen/{token}', ['controller' => 'Users', 'action' => 'verify_citizen'])->setPass(['token']); + + $builder->connect('/water_drawing_paperworks', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index']); + $builder->connect('/water_drawing_paperworks/index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index']); + $builder->connect('/water_drawing_paperworks/index_snapshots/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_paperworks/index_snapshots_all', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all']); + $builder->connect('/water_drawing_paperworks/validate_index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate_index']); + $builder->connect('/water_drawing_paperworks/add_scan', ['controller' => 'WaterDrawingPaperworks', 'action' => 'add_scan']); + $builder->connect('/water_drawing_paperworks/add', ['controller' => 'WaterDrawingPaperworks', 'action' => 'add']); + $builder->connect('/water_drawing_paperworks/view_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/view/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/view_scan_snapshot/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan_snapshot'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/view_snapshot/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_snapshot'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/edit_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'edit_scan'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/edit/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/delete/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/validate_scan/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate_scan'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/validate/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/send_to_drar/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_drar'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/send_to_gc/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_gc'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/submit_antimafia_request/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'submit_antimafia_request'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/antimafia_request_to_anac/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'antimafia_request_to_anac'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/request_self_certification/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'request_self_certification'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/applicants_water_drawing_paperworks_item_block/{id}/{status_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'applicants_water_drawing_paperworks_item_block'])->setPass(['id', 'status_id']); + $builder->connect('/water_drawing_paperworks/applicants_water_drawing_paperworks_item_block/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'applicants_water_drawing_paperworks_item_block'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/intended_uses_water_drawing_paperworks_item_block/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'intended_uses_water_drawing_paperworks_item_block'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/upload_attachment/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_attachment'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/upload_attachment_scan/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_attachment_scan'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/upload_antimafia_attachment/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'upload_antimafia_attachment'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/assign/{id}/{organisation_type_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'assign'])->setPass(['id', 'organisation_type_id']); + $builder->connect('/water_drawing_paperworks/citizen_submission_index', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index']); + $builder->connect('/water_drawing_paperworks/citizen_documentation_index/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/citizen_documentation_requested/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_requested'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/citizen_upload_attachment/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_upload_attachment'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/citizen_submit_paperwork/{applicant_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submit_paperwork'])->setPass(['applicant_id']); + $builder->connect('/water_drawing_paperworks/citizen_request_paperwork', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_request_paperwork']); + $builder->connect('/water_drawing_paperworks/citizen_send_to_validation/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_send_to_validation'])->setPass(['id']); + $builder->connect('/water_drawing_paperworks/delete_attachment/{id}/{attachment_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'delete_attachment'])->setPass(['id', 'attachment_id']); + $builder->connect('/water_drawing_paperworks/send_to_validation/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_validation'])->setPass(['id']); + + $builder->connect('/applicants/search_applicants', ['controller' => 'Applicants', 'action' => 'search_applicants']); + $builder->connect('/applicants/get_applicant/{id}', ['controller' => 'Applicants', 'action' => 'get_applicant'])->setPass(['id']); + $builder->connect('/applicants/edit/{id}', ['controller' => 'Applicants', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/applicants/edit/{id}/{water_id}', ['controller' => 'Applicants', 'action' => 'edit'])->setPass(['id','water_id']); + $builder->connect('/applicants/view/{id}/', ['controller' => 'Applicants', 'action' => 'view'])->setPass(['id']); + $builder->connect('/applicants/citizen_add/', ['controller' => 'Applicants', 'action' => 'citizen_add']); + $builder->connect('/applicants/citizen_edit/{id}', ['controller' => 'Applicants', 'action' => 'citizen_edit'])->setPass(['id']); + $builder->connect('/applicants/citizen_view', ['controller' => 'Applicants', 'action' => 'citizen_view']); + + $builder->connect('/water_drawing_measurements/add/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeasurements', 'action' => 'add'])->setPass(['water_drawing_meter_id']); + $builder->connect('/water_drawing_measurements/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingMeasurements', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + + $builder->connect('/water_drawing_meters/add/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'add'])->setPass(['water_drawing_derivation_id']); + $builder->connect('/water_drawing_meters/edit/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'edit'])->setPass(['water_drawing_meter_id']); + $builder->connect('/water_drawing_meters/view/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'view'])->setPass(['water_drawing_meter_id']); + $builder->connect('/water_drawing_meters/dismiss/{water_drawing_meter_id}', ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss'])->setPass(['water_drawing_meter_id']); + + $builder->connect('/water_drawing_payments/index_all', ['controller' => 'WaterDrawingPayments', 'action' => 'index_all']); + $builder->connect('/water_drawing_payments/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_payments/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_payments/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPayments', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_payments/edit/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_payments/view/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_payments/delete/{id}', ['controller' => 'WaterDrawingPayments', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/water_drawing_derivations/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_derivations/view/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'view'])->setPass(['water_drawing_derivation_id']); + $builder->connect('/water_drawing_derivations/edit/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'edit'])->setPass(['water_drawing_derivation_id']); + $builder->connect('/water_drawing_derivations/delete/{water_drawing_derivation_id}', ['controller' => 'WaterDrawingDerivations', 'action' => 'delete'])->setPass(['water_drawing_derivation_id']); + + $builder->connect('/water_drawing_return_points/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_return_points/view/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_return_points/edit/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_return_points/delete/{id}', ['controller' => 'WaterDrawingReturnPoints', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/water_drawing_articles/', ['controller' => 'WaterDrawingArticles', 'action' => 'index']); + $builder->connect('/water_drawing_articles/add', ['controller' => 'WaterDrawingArticles', 'action' => 'add']); + $builder->connect('/water_drawing_articles/edit/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_articles/view/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_articles/delete/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'delete'])->setPass(['id']); + $builder->connect('/water_drawing_articles/change_status/{id}', ['controller' => 'WaterDrawingArticles', 'action' => 'change_status'])->setPass(['id']); + + $builder->connect('/water_drawing_fees/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingFees', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_fees/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingFees', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_fees/view/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_fees/edit/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_fees/delete/{id}', ['controller' => 'WaterDrawingFees', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/water_drawing_paperwork_pecs/index/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'index'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_paperwork_pecs/add/{water_drawing_paperwork_id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'add'])->setPass(['water_drawing_paperwork_id']); + $builder->connect('/water_drawing_paperwork_pecs/edit/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'edit'])->setPass(['id']); + $builder->connect('/water_drawing_paperwork_pecs/view/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view'])->setPass(['id']); + $builder->connect('/water_drawing_paperwork_pecs/delete/{id}', ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'delete'])->setPass(['id']); + + $builder->connect('/ai_services/autocomplete', ['controller' => 'AiServices', 'action' => 'autocomplete']); + $builder->connect('/pecs/add/{id}', ['controller' => 'Pecs', 'action' => 'add'])->setPass(['id']); + $builder->connect('/pecs/edit/{id}', ['controller' => 'Pecs', 'action' => 'edit'])->setPass(['id']); + + $builder->connect('/privacy/edit/', ['controller' => 'Privacy', 'action' => 'edit']); + $builder->connect('/privacy/view', ['controller' => 'Privacy', 'action' => 'view']); + $builder->connect('/privacy/view_public', ['controller' => 'Privacy', 'action' => 'view_public']); + $builder->connect('/privacy/accept_privacy', ['controller' => 'Privacy', 'action' => 'accept_privacy']); + + $builder->connect('/districts/search_districts', ['controller' => 'Districts', 'action' => 'search_districts']); + $builder->connect('/water_drawing_paperworks/citizen_upload_payment_receipt/{id}/{tag_id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_upload_payment_receipt'])->setPass(['id', 'tag_id']); + $builder->connect('/water_drawing_paperworks/index_csv', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_csv']); + $builder->connect('/water_drawing_paperworks/index_snapshots_all_csv', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all_csv']); + $builder->connect('/water_drawing_paperworks/index_snapshots_csv/{id}', ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_csv'])->setPass(['id']); + + $builder->connect('/tags', ['controller' => 'Tags', 'action' => 'index']); + $builder->connect('/tags/index', ['controller' => 'Tags', 'action' => 'index']); + $builder->connect('/tags/add', ['controller' => 'Tags', 'action' => 'add']); + $builder->connect('/tags/view', ['controller' => 'Tags', 'action' => 'view']); + $builder->connect('/tags/view/{id}', ['controller' => 'Tags', 'action' => 'view'])->setPass(['id']); + $builder->connect('/tags/edit', ['controller' => 'Tags', 'action' => 'edit']); + $builder->connect('/tags/edit/{id}', ['controller' => 'Tags', 'action' => 'edit'])->setPass(['id']); + + }); +}; diff --git a/idrocap_wa/config/schema/i18n.sql b/idrocap_wa/config/schema/i18n.sql new file mode 100644 index 0000000..e59d1e6 --- /dev/null +++ b/idrocap_wa/config/schema/i18n.sql @@ -0,0 +1,18 @@ +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# MIT License (https://opensource.org/licenses/mit-license.php) + +CREATE TABLE i18n ( + id int NOT NULL auto_increment, + locale varchar(6) NOT NULL, + model varchar(255) NOT NULL, + foreign_key int(10) NOT NULL, + field varchar(255) NOT NULL, + content text, + PRIMARY KEY (id), + UNIQUE INDEX I18N_LOCALE_FIELD(locale, model, foreign_key, field), + INDEX I18N_FIELD(model, foreign_key, field) +); diff --git a/idrocap_wa/config/schema/sessions.sql b/idrocap_wa/config/schema/sessions.sql new file mode 100644 index 0000000..1aa0a0f --- /dev/null +++ b/idrocap_wa/config/schema/sessions.sql @@ -0,0 +1,15 @@ +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# MIT License (https://opensource.org/licenses/mit-license.php) + +CREATE TABLE `sessions` ( + `id` char(40) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + `created` datetime DEFAULT CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ + `modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- optional, requires MySQL 5.6.5+ + `data` blob DEFAULT NULL, -- for PostgreSQL use bytea instead of blob + `expires` int(10) unsigned DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/idrocap_wa/dockerfiles/cake b/idrocap_wa/dockerfiles/cake new file mode 100755 index 0000000..bffbd99 --- /dev/null +++ b/idrocap_wa/dockerfiles/cake @@ -0,0 +1,152 @@ +#!/usr/bin/env sh + +if [ -f /run/secrets/sentry_dsn ]; then + export SENTRY_DSN=$(cat /run/secrets/sentry_dsn) +else + echo "Secret file 'sentry_dsn' not found!" >&2 +fi +if [ -f /run/secrets/oidc_client_id ]; then + export OIDC_CLIENT_ID=$(cat /run/secrets/oidc_client_id) +else + echo "Secret file 'oidc_client_id' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_username ]; then + export GEOSERVER_USERNAME=$(cat /run/secrets/geoserver_username) +else + echo "Secret file 'geoserver_username' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_password ]; then + export GEOSERVER_PASSWORD=$(cat /run/secrets/geoserver_password) +else + echo "Secret file 'geoserver_password' not found!" >&2 +fi +if [ -f /run/secrets/minio_access_key ]; then + export MINIO_ACCESS_KEY=$(cat /run/secrets/minio_access_key) +else + echo "Secret file 'minio_access_key' not found!" >&2 +fi +if [ -f /run/secrets/minio_secret_key ]; then + export MINIO_SECRET_KEY=$(cat /run/secrets/minio_secret_key) +else + echo "Secret file 'minio_secret_key' not found!" >&2 +fi +if [ -f /run/secrets/telegram_bot_token ]; then + export TELEGRAM_BOT_TOKEN=$(cat /run/secrets/telegram_bot_token) +else + echo "Secret file 'telegram_bot_token' not found!" >&2 +fi +if [ -f /run/secrets/security_jwuc ]; then + export SECURITY_JWUC=$(cat /run/secrets/security_jwuc) +else + echo "Secret file 'security_jwuc' not found!" >&2 +fi +if [ -f /run/secrets/security_jwac ]; then + export SECURITY_JWAC=$(cat /run/secrets/security_jwac) +else + echo "Secret file 'security_jwac' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_username ]; then + export MYSQL_JIXEL_USERNAME=$(cat /run/secrets/mysql_jixel_username) +else + echo "Secret file 'mysql_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_password ]; then + export MYSQL_JIXEL_PASSWORD=$(cat /run/secrets/mysql_jixel_password) +else + echo "Secret file 'mysql_jixel_password' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_username ]; then + export MYSQL_GEO_JIXEL_USERNAME=$(cat /run/secrets/mysql_geo_jixel_username) +else + echo "Secret file 'mysql_geo_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_password ]; then + export MYSQL_GEO_JIXEL_PASSWORD=$(cat /run/secrets/mysql_geo_jixel_password) +else + echo "Secret file 'mysql_geo_jixel_password' not found!" >&2 +fi + +################################################################################ +# +# Cake is a shell script for invoking CakePHP shell commands +# +# CakePHP(tm) : Rapid Development Framework (https://cakephp.org) +# Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# +# Licensed under The MIT License +# For full copyright and license information, please see the LICENSE.txt +# Redistributions of files must retain the above copyright notice. +# +# @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) +# @link https://cakephp.org CakePHP(tm) Project +# @since 1.2.0 +# @license https://opensource.org/licenses/mit-license.php MIT License +# +################################################################################ + +# Canonicalize by following every symlink of the given name recursively +canonicalize() { + NAME="$1" + if [ -f "$NAME" ] + then + DIR=$(dirname -- "$NAME") + NAME=$(cd -P "$DIR" > /dev/null && pwd -P)/$(basename -- "$NAME") + fi + while [ -h "$NAME" ]; do + DIR=$(dirname -- "$NAME") + SYM=$(readlink "$NAME") + NAME=$(cd "$DIR" > /dev/null && cd "$(dirname -- "$SYM")" > /dev/null && pwd)/$(basename -- "$SYM") + done + echo "$NAME" +} + +# Find a CLI version of PHP +findCliPhp() { + for TESTEXEC in php php-cli /usr/local/bin/php + do + SAPI=$(echo "" | $TESTEXEC 2>/dev/null) + if [ "$SAPI" = "cli" ] + then + echo $TESTEXEC + return + fi + done + echo "Failed to find a CLI version of PHP; falling back to system standard php executable" >&2 + echo "php"; +} + +# If current path is a symlink, resolve to real path +realname="$0" +if [ -L "$realname" ] +then + realname=$(readlink -f "$0") +fi + +CONSOLE=$(dirname -- "$(canonicalize "$realname")") +APP=$(dirname "$CONSOLE") + +# If your CLI PHP is somewhere that this doesn't find, you can define a PHP environment +# variable with the correct path in it. +if [ -z "$PHP" ] +then + PHP=$(findCliPhp) +fi + +if [ "$(basename "$realname")" != 'cake' ] +then + exec "$PHP" "$CONSOLE"/cake.php "$(basename "$realname")" "$@" +else + exec "$PHP" "$CONSOLE"/cake.php "$@" +fi + +exit diff --git a/idrocap_wa/dockerfiles/run b/idrocap_wa/dockerfiles/run new file mode 100755 index 0000000..b5e4d8a --- /dev/null +++ b/idrocap_wa/dockerfiles/run @@ -0,0 +1,93 @@ +#!/bin/bash + +httpd_user=${httpd_user:-apache} +httpd_uid=${httpd_uid:-48} +httpd_group=${httpd_group:-apache} + +useradd -u $httpd_uid -s /sbin/nologin $httpd_user + +export httpd_user +export httpd_group + +if [ -f /run/secrets/sentry_dsn ]; then + export SENTRY_DSN=$(cat /run/secrets/sentry_dsn) +else + echo "Secret file 'sentry_dsn' not found!" >&2 +fi +if [ -f /run/secrets/oidc_client_id ]; then + export OIDC_CLIENT_ID=$(cat /run/secrets/oidc_client_id) +else + echo "Secret file 'oidc_client_id' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_username ]; then + export GEOSERVER_USERNAME=$(cat /run/secrets/geoserver_username) +else + echo "Secret file 'geoserver_username' not found!" >&2 +fi +if [ -f /run/secrets/geoserver_password ]; then + export GEOSERVER_PASSWORD=$(cat /run/secrets/geoserver_password) +else + echo "Secret file 'geoserver_password' not found!" >&2 +fi +if [ -f /run/secrets/minio_access_key ]; then + export MINIO_ACCESS_KEY=$(cat /run/secrets/minio_access_key) +else + echo "Secret file 'minio_access_key' not found!" >&2 +fi +if [ -f /run/secrets/minio_secret_key ]; then + export MINIO_SECRET_KEY=$(cat /run/secrets/minio_secret_key) +else + echo "Secret file 'minio_secret_key' not found!" >&2 +fi +if [ -f /run/secrets/telegram_bot_token ]; then + export TELEGRAM_BOT_TOKEN=$(cat /run/secrets/telegram_bot_token) +else + echo "Secret file 'telegram_bot_token' not found!" >&2 +fi +if [ -f /run/secrets/security_jwuc ]; then + export SECURITY_JWUC=$(cat /run/secrets/security_jwuc) +else + echo "Secret file 'security_jwuc' not found!" >&2 +fi +if [ -f /run/secrets/security_jwac ]; then + export SECURITY_JWAC=$(cat /run/secrets/security_jwac) +else + echo "Secret file 'security_jwac' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_username ]; then + export MYSQL_JIXEL_USERNAME=$(cat /run/secrets/mysql_jixel_username) +else + echo "Secret file 'mysql_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_jixel_password ]; then + export MYSQL_JIXEL_PASSWORD=$(cat /run/secrets/mysql_jixel_password) +else + echo "Secret file 'mysql_jixel_password' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_username ]; then + export MYSQL_GEO_JIXEL_USERNAME=$(cat /run/secrets/mysql_geo_jixel_username) +else + echo "Secret file 'mysql_geo_jixel_username' not found!" >&2 +fi +if [ -f /run/secrets/mysql_geo_jixel_password ]; then + export MYSQL_GEO_JIXEL_PASSWORD=$(cat /run/secrets/mysql_geo_jixel_password) +else + echo "Secret file 'mysql_geo_jixel_password' not found!" >&2 +fi + +chmod -R o+w /var/www/jixel/tmp/ +chmod -R o+w /var/www/jixel/logs/ + +/usr/sbin/php-fpm +chown -R $httpd_user:$httpd_group /run/php-fpm +/usr/sbin/httpd -DFOREGROUND diff --git a/idrocap_wa/dockerfiles/www.conf b/idrocap_wa/dockerfiles/www.conf new file mode 100644 index 0000000..ddc8904 --- /dev/null +++ b/idrocap_wa/dockerfiles/www.conf @@ -0,0 +1,453 @@ +; Start a new pool named 'www'. +; the variable $pool can be used in any directive and will be replaced by the +; pool name ('www' here) +[www] + +; Per pool prefix +; It only applies on the following directives: +; - 'access.log' +; - 'slowlog' +; - 'listen' (unixsocket) +; - 'chroot' +; - 'chdir' +; - 'php_values' +; - 'php_admin_values' +; When not set, the global prefix (or @php_fpm_prefix@) applies instead. +; Note: This directive can also be relative to the global prefix. +; Default Value: none +;prefix = /path/to/pools/$pool + +; Unix user/group of processes +; Note: The user is mandatory. If the group is not set, the default user's group +; will be used. +; RPM: apache user chosen to provide access to the same directories as httpd +user = apache +; RPM: Keep a group allowed to write in log dir. +group = apache + +; The address on which to accept FastCGI requests. +; Valid syntaxes are: +; 'ip.add.re.ss:port' - to listen on a TCP socket to a specific IPv4 address on +; a specific port; +; '[ip:6:addr:ess]:port' - to listen on a TCP socket to a specific IPv6 address on +; a specific port; +; 'port' - to listen on a TCP socket to all addresses +; (IPv6 and IPv4-mapped) on a specific port; +; '/path/to/unix/socket' - to listen on a unix socket. +; Note: This value is mandatory. +listen = /run/php-fpm/www.sock + +; Set listen(2) backlog. +; Default Value: 511 +;listen.backlog = 511 + +; Set permissions for unix socket, if one is used. In Linux, read/write +; permissions must be set in order to allow connections from a web server. +; Default Values: user and group are set as the running user +; mode is set to 0660 +;listen.owner = nobody +;listen.group = nobody +;listen.mode = 0660 + +; When POSIX Access Control Lists are supported you can set them using +; these options, value is a comma separated list of user/group names. +; When set, listen.owner and listen.group are ignored +listen.acl_users = apache,nginx +;listen.acl_groups = + +; List of addresses (IPv4/IPv6) of FastCGI clients which are allowed to connect. +; Equivalent to the FCGI_WEB_SERVER_ADDRS environment variable in the original +; PHP FCGI (5.2.2+). Makes sense only with a tcp listening socket. Each address +; must be separated by a comma. If this value is left blank, connections will be +; accepted from any ip address. +; Default Value: any +listen.allowed_clients = 127.0.0.1 + +; Specify the nice(2) priority to apply to the pool processes (only if set) +; The value can vary from -19 (highest priority) to 20 (lower priority) +; Note: - It will only work if the FPM master process is launched as root +; - The pool processes will inherit the master process priority +; unless it specified otherwise +; Default Value: no set +; process.priority = -19 + +; Set the process dumpable flag (PR_SET_DUMPABLE prctl) even if the process user +; or group is differrent than the master process user. It allows to create process +; core dump and ptrace the process for the pool user. +; Default Value: no +; process.dumpable = yes + +; Choose how the process manager will control the number of child processes. +; Possible Values: +; static - a fixed number (pm.max_children) of child processes; +; dynamic - the number of child processes are set dynamically based on the +; following directives. With this process management, there will be +; always at least 1 children. +; pm.max_children - the maximum number of children that can +; be alive at the same time. +; pm.start_servers - the number of children created on startup. +; pm.min_spare_servers - the minimum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is less than this +; number then some children will be created. +; pm.max_spare_servers - the maximum number of children in 'idle' +; state (waiting to process). If the number +; of 'idle' processes is greater than this +; number then some children will be killed. +; ondemand - no children are created at startup. Children will be forked when +; new requests will connect. The following parameter are used: +; pm.max_children - the maximum number of children that +; can be alive at the same time. +; pm.process_idle_timeout - The number of seconds after which +; an idle process will be killed. +; Note: This value is mandatory. +pm = dynamic + +; The number of child processes to be created when pm is set to 'static' and the +; maximum number of child processes when pm is set to 'dynamic' or 'ondemand'. +; This value sets the limit on the number of simultaneous requests that will be +; served. Equivalent to the ApacheMaxClients directive with mpm_prefork. +; Equivalent to the PHP_FCGI_CHILDREN environment variable in the original PHP +; CGI. The below defaults are based on a server without much resources. Don't +; forget to tweak pm.* to fit your needs. +; Note: Used when pm is set to 'static', 'dynamic' or 'ondemand' +; Note: This value is mandatory. +pm.max_children = 50 + +; The number of child processes created on startup. +; Note: Used only when pm is set to 'dynamic' +; Default Value: min_spare_servers + (max_spare_servers - min_spare_servers) / 2 +pm.start_servers = 5 + +; The desired minimum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.min_spare_servers = 5 + +; The desired maximum number of idle server processes. +; Note: Used only when pm is set to 'dynamic' +; Note: Mandatory when pm is set to 'dynamic' +pm.max_spare_servers = 35 + +; The number of seconds after which an idle process will be killed. +; Note: Used only when pm is set to 'ondemand' +; Default Value: 10s +;pm.process_idle_timeout = 10s; + +; The number of requests each child process should execute before respawning. +; This can be useful to work around memory leaks in 3rd party libraries. For +; endless request processing specify '0'. Equivalent to PHP_FCGI_MAX_REQUESTS. +; Default Value: 0 +;pm.max_requests = 500 + +; The URI to view the FPM status page. If this value is not set, no URI will be +; recognized as a status page. It shows the following informations: +; pool - the name of the pool; +; process manager - static, dynamic or ondemand; +; start time - the date and time FPM has started; +; start since - number of seconds since FPM has started; +; accepted conn - the number of request accepted by the pool; +; listen queue - the number of request in the queue of pending +; connections (see backlog in listen(2)); +; max listen queue - the maximum number of requests in the queue +; of pending connections since FPM has started; +; listen queue len - the size of the socket queue of pending connections; +; idle processes - the number of idle processes; +; active processes - the number of active processes; +; total processes - the number of idle + active processes; +; max active processes - the maximum number of active processes since FPM +; has started; +; max children reached - number of times, the process limit has been reached, +; when pm tries to start more children (works only for +; pm 'dynamic' and 'ondemand'); +; Value are updated in real time. +; Example output: +; pool: www +; process manager: static +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 62636 +; accepted conn: 190460 +; listen queue: 0 +; max listen queue: 1 +; listen queue len: 42 +; idle processes: 4 +; active processes: 11 +; total processes: 15 +; max active processes: 12 +; max children reached: 0 +; +; By default the status page output is formatted as text/plain. Passing either +; 'html', 'xml' or 'json' in the query string will return the corresponding +; output syntax. Example: +; http://www.foo.bar/status +; http://www.foo.bar/status?json +; http://www.foo.bar/status?html +; http://www.foo.bar/status?xml +; +; By default the status page only outputs short status. Passing 'full' in the +; query string will also return status for each pool process. +; Example: +; http://www.foo.bar/status?full +; http://www.foo.bar/status?json&full +; http://www.foo.bar/status?html&full +; http://www.foo.bar/status?xml&full +; The Full status returns for each process: +; pid - the PID of the process; +; state - the state of the process (Idle, Running, ...); +; start time - the date and time the process has started; +; start since - the number of seconds since the process has started; +; requests - the number of requests the process has served; +; request duration - the duration in µs of the requests; +; request method - the request method (GET, POST, ...); +; request URI - the request URI with the query string; +; content length - the content length of the request (only with POST); +; user - the user (PHP_AUTH_USER) (or '-' if not set); +; script - the main script called (or '-' if not set); +; last request cpu - the %cpu the last request consumed +; it's always 0 if the process is not in Idle state +; because CPU calculation is done when the request +; processing has terminated; +; last request memory - the max amount of memory the last request consumed +; it's always 0 if the process is not in Idle state +; because memory calculation is done when the request +; processing has terminated; +; If the process is in Idle state, then informations are related to the +; last request the process has served. Otherwise informations are related to +; the current request being served. +; Example output: +; ************************ +; pid: 31330 +; state: Running +; start time: 01/Jul/2011:17:53:49 +0200 +; start since: 63087 +; requests: 12808 +; request duration: 1250261 +; request method: GET +; request URI: /test_mem.php?N=10000 +; content length: 0 +; user: - +; script: /home/fat/web/docs/php/test_mem.php +; last request cpu: 0.00 +; last request memory: 0 +; +; Note: There is a real-time FPM status monitoring sample web page available +; It's available in: @EXPANDED_DATADIR@/fpm/status.html +; +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;pm.status_path = /status + +; The ping URI to call the monitoring page of FPM. If this value is not set, no +; URI will be recognized as a ping page. This could be used to test from outside +; that FPM is alive and responding, or to +; - create a graph of FPM availability (rrd or such); +; - remove a server from a group if it is not responding (load balancing); +; - trigger alerts for the operating team (24/7). +; Note: The value must start with a leading slash (/). The value can be +; anything, but it may not be a good idea to use the .php extension or it +; may conflict with a real PHP file. +; Default Value: not set +;ping.path = /ping + +; This directive may be used to customize the response of a ping request. The +; response is formatted as text/plain with a 200 response code. +; Default Value: pong +;ping.response = pong + +; The access log file +; Default: not set +;access.log = log/$pool.access.log + +; The access log format. +; The following syntax is allowed +; %%: the '%' character +; %C: %CPU used by the request +; it can accept the following format: +; - %{user}C for user CPU only +; - %{system}C for system CPU only +; - %{total}C for user + system CPU (default) +; %d: time taken to serve the request +; it can accept the following format: +; - %{seconds}d (default) +; - %{miliseconds}d +; - %{mili}d +; - %{microseconds}d +; - %{micro}d +; %e: an environment variable (same as $_ENV or $_SERVER) +; it must be associated with embraces to specify the name of the env +; variable. Some exemples: +; - server specifics like: %{REQUEST_METHOD}e or %{SERVER_PROTOCOL}e +; - HTTP headers like: %{HTTP_HOST}e or %{HTTP_USER_AGENT}e +; %f: script filename +; %l: content-length of the request (for POST request only) +; %m: request method +; %M: peak of memory allocated by PHP +; it can accept the following format: +; - %{bytes}M (default) +; - %{kilobytes}M +; - %{kilo}M +; - %{megabytes}M +; - %{mega}M +; %n: pool name +; %o: output header +; it must be associated with embraces to specify the name of the header: +; - %{Content-Type}o +; - %{X-Powered-By}o +; - %{Transfert-Encoding}o +; - .... +; %p: PID of the child that serviced the request +; %P: PID of the parent of the child that serviced the request +; %q: the query string +; %Q: the '?' character if query string exists +; %r: the request URI (without the query string, see %q and %Q) +; %R: remote IP address +; %s: status (response code) +; %t: server time the request was received +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %T: time the log has been written (the request has finished) +; it can accept a strftime(3) format: +; %d/%b/%Y:%H:%M:%S %z (default) +; The strftime(3) format must be encapsuled in a %{}t tag +; e.g. for a ISO8601 formatted timestring, use: %{%Y-%m-%dT%H:%M:%S%z}t +; %u: remote user +; +; Default: "%R - %u %t \"%m %r\" %s" +;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%" + +; The log file for slow requests +; Default Value: not set +; Note: slowlog is mandatory if request_slowlog_timeout is set +slowlog = /var/log/php-fpm/www-slow.log + +; The timeout for serving a single request after which a PHP backtrace will be +; dumped to the 'slowlog' file. A value of '0s' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_slowlog_timeout = 0 + +; Depth of slow log stack trace. +; Default Value: 20 +;request_slowlog_trace_depth = 20 + +; The timeout for serving a single request after which the worker process will +; be killed. This option should be used when the 'max_execution_time' ini option +; does not stop script execution for some reason. A value of '0' means 'off'. +; Available units: s(econds)(default), m(inutes), h(ours), or d(ays) +; Default Value: 0 +;request_terminate_timeout = 0 + +; Set open file descriptor rlimit. +; Default Value: system defined value +;rlimit_files = 1024 + +; Set max core size rlimit. +; Possible Values: 'unlimited' or an integer greater or equal to 0 +; Default Value: system defined value +;rlimit_core = 0 + +; Chroot to this directory at the start. This value must be defined as an +; absolute path. When this value is not set, chroot is not used. +; Note: you can prefix with '$prefix' to chroot to the pool prefix or one +; of its subdirectories. If the pool prefix is not set, the global prefix +; will be used instead. +; Note: chrooting is a great security feature and should be used whenever +; possible. However, all PHP paths will be relative to the chroot +; (error_log, sessions.save_path, ...). +; Default Value: not set +;chroot = + +; Chdir to this directory at the start. +; Note: relative path can be used. +; Default Value: current directory or / when chroot +;chdir = /var/www + +; Redirect worker stdout and stderr into main error log. If not set, stdout and +; stderr will be redirected to /dev/null according to FastCGI specs. +; Note: on highloaded environement, this can cause some delay in the page +; process time (several ms). +; Default Value: no +;catch_workers_output = yes + +; Clear environment in FPM workers +; Prevents arbitrary environment variables from reaching FPM worker processes +; by clearing the environment in workers before env vars specified in this +; pool configuration are added. +; Setting to "no" will make all environment variables available to PHP code +; via getenv(), $_ENV and $_SERVER. +; Default Value: yes +; clear_env = no + +; Limits the extensions of the main script FPM will allow to parse. This can +; prevent configuration mistakes on the web server side. You should only limit +; FPM to .php extensions to prevent malicious users to use other extensions to +; execute php code. +; Note: set an empty value to allow all extensions. +; Default Value: .php +;security.limit_extensions = .php .php3 .php4 .php5 .php7 + +; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from +; the current environment. +; Default Value: clean env +;env[HOSTNAME] = $HOSTNAME +;env[PATH] = /usr/local/bin:/usr/bin:/bin +;env[TMP] = /tmp +;env[TMPDIR] = /tmp +;env[TEMP] = /tmp +env[SENTRY_DSN] = "${SENTRY_DSN}" +env[OIDC_CLIENT_ID] = "${OIDC_CLIENT_ID}" +env[RABBITMQ_USERNAME] = "${RABBITMQ_USERNAME}" +env[RABBITMQ_PASSWORD] = "${RABBITMQ_PASSWORD}" +env[GEOSERVER_USERNAME] = "${GEOSERVER_USERNAME}" +env[GEOSERVER_PASSWORD] = "${GEOSERVER_PASSWORD}" +env[MINIO_ACCESS_KEY] = "${MINIO_ACCESS_KEY}" +env[MINIO_SECRET_KEY] = "${MINIO_SECRET_KEY}" +env[TELEGRAM_BOT_TOKEN] = "${TELEGRAM_BOT_TOKEN}" +env[SECURITY_JWUC] = "${SECURITY_JWUC}" +env[SECURITY_JWAC] = "${SECURITY_JWAC}" +env[MYSQL_JIXEL_USERNAME] = "${MYSQL_JIXEL_USERNAME}" +env[MYSQL_JIXEL_PASSWORD] = "${MYSQL_JIXEL_PASSWORD}" +env[MYSQL_GEO_JIXEL_USERNAME] = "${MYSQL_GEO_JIXEL_USERNAME}" +env[MYSQL_GEO_JIXEL_PASSWORD] = "${MYSQL_GEO_JIXEL_PASSWORD}" + +; Additional php.ini defines, specific to this pool of workers. These settings +; overwrite the values previously defined in the php.ini. The directives are the +; same as the PHP SAPI: +; php_value/php_flag - you can set classic ini defines which can +; be overwritten from PHP call 'ini_set'. +; php_admin_value/php_admin_flag - these directives won't be overwritten by +; PHP call 'ini_set' +; For php_*flag, valid values are on, off, 1, 0, true, false, yes or no. + +; Defining 'extension' will load the corresponding shared extension from +; extension_dir. Defining 'disable_functions' or 'disable_classes' will not +; overwrite previously defined php.ini values, but will append the new value +; instead. + +; Note: path INI options can be relative and will be expanded with the prefix +; (pool, global or @prefix@) + +; Default Value: nothing is defined by default except the values in php.ini and +; specified at startup with the -d argument +;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com +;php_flag[display_errors] = off +php_admin_value[error_log] = /var/log/php-fpm/www-error.log +php_admin_flag[log_errors] = on +;php_admin_value[memory_limit] = 128M + +; Set the following data paths to directories owned by the FPM process user. +; +; Do not change the ownership of existing system directories, if the process +; user does not have write permission, create dedicated directories for this +; purpose. +; +; See warning about choosing the location of these directories on your system +; at http://php.net/session.save-path +php_value[session.save_handler] = files +php_value[session.save_path] = /var/lib/php/session +php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache +;php_value[opcache.file_cache] = /var/lib/php/opcache \ No newline at end of file diff --git a/idrocap_wa/index.php b/idrocap_wa/index.php new file mode 100644 index 0000000..4591769 --- /dev/null +++ b/idrocap_wa/index.php @@ -0,0 +1,16 @@ + " + self.execution_command + ':\n{}'.format(completed_process.stderr.decode('utf-8'))) + if completed_process.stdout: + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ':\n{}'.format(completed_process.stdout.decode('utf-8'))) + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - RETURN CODE: {}'.format(completed_process.returncode)) + completed_process.check_returncode() + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ': Shell command successfully executed!') + self.result = True + except FileNotFoundError as error: + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - A FileNotFoundError error has occured during shell command execution:', stack_info=False, exc_info=False) + self.logger.exception(error, stack_info=False, exc_info=False) + return False + except subprocess.CalledProcessError as error: + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " -> " + self.execution_command + ' - A CalledProcessError has occured during processing:', stack_info=False, exc_info=False) + self.logger.exception(error, stack_info=False, exc_info=False) + self.result = False + + def __data_processing(self, channel, mr): + self.logger.info(mr) + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - Starting processing thread:') + self.result = None + thread = threading.Thread(target=self.__execute_command, args=(mr,)) + thread.start() + + while thread.is_alive(): + self.connection.process_data_events() + + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Result received:") + self.logger.info(self.result) + if (self.result is not True): + self.__send_error(json.dumps(mr)) + return self.result + + def __send_ack_nack(self, ack, channel, method): + channel.basic_ack(delivery_tag=method.delivery_tag) + if ack is True: + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Ack performed") + else: + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Ack performed BUT ERRORS OCCURRED!") + + def __data_handler(self, channel, method, properties, body): + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + ' - New message received:') + error = False + + try: + mr = json.loads(body.decode()) + error = not self.__data_processing(channel, mr) + except json.JSONDecodeError as error: + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Malformed message", stack_info=False, exc_info=False) + self.logger.exception(error, stack_info=False, exc_info=False) + self.logger.exception(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - This message will be removed from the queue", stack_info=False, exc_info=False) + self.__send_ack_nack(False, channel, method) + time.sleep(60) + return + + if self.result is True and error is False: + self.__send_ack_nack(True, channel, method) + else: + self.logger.error(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - An error has occured during processing") + if self.discarding_mode is True: + self.logger.error(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Discarding mode enabled.") + self.__send_ack_nack(True, channel, method) + else: + self.__send_ack_nack(False, channel, method) + + time.sleep(5) + + self.logger.info(self.rabbitmq_vhost + "/" + self.rabbitmq_queue + " - Data handling complete. Waiting for new messages") + + def __send_error(self, message): + self.channel.basic_publish(exchange='', routing_key=self.rabbitmq_queue+'_errors', body=message) + +if __name__ == '__main__': + formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") + handler = logging.handlers.TimedRotatingFileHandler("{}{}".format(os.environ['logging_file_path'], os.environ['logging_name']), when=os.environ['logging_file_rotate_when'], interval=int(os.environ['logging_file_rotate_interval']), backupCount=int(os.environ['logging_file_backup_count'])) + handler.setFormatter(formatter) + logger = logging.getLogger(os.environ['logging_name']) + logger.addHandler(handler) + logger.setLevel(logging.DEBUG) + + app = JixelGeneralPurposeRabbitConsumer( + os.environ['RABBITMQ_USERNAME'], + os.environ['RABBITMQ_PASSWORD'], + os.environ['rabbitmq_host'], + os.environ['rabbitmq_vhost'], + os.environ['rabbitmq_port'], + os.environ['rabbitmq_queue'], + os.environ['rabbitmq_heartbeat'], + os.environ['execution_path'], + os.environ['execution_command'], + logger, + os.environ['discarding_mode'] + ) + app.consume() diff --git a/idrocap_wa/jixel-background-task-handler/jgprc.sh b/idrocap_wa/jixel-background-task-handler/jgprc.sh new file mode 100755 index 0000000..63e583b --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jgprc.sh @@ -0,0 +1,26 @@ +export rabbitmq_username='jixel' +export rabbitmq_password='jixel' +export rabbitmq_host='rabbitmq' +export rabbitmq_vhost='gp' +export rabbitmq_queue='gp' +export rabbitmq_port='5672' +export execution_path='/var/www/jixel/bin/' +export execution_command='gp' +export rabbitmq_heartbeat=60 +export discarding_mode='False' + +# Log file rotation policy: +# Current 'when' events supported: +# 'S' - Seconds +# 'M' - Minutes +# 'H' - Hours +# 'D' - Days +# 'midnight' - roll over at midnight +# 'W{0-6}' - roll over on a certain day; W0 - Monday, W1 - Tuesday, etc +export logging_file_rotate_when='H' +export logging_file_rotate_interval=24 +export logging_name='JixelGeneralPurposeRabbitConsumer' +export logging_file_path='/general_purpose_rabbit_consumer/logs/' +export logging_file_backup_count=30 + +python3 ./jgprc.py diff --git a/idrocap_wa/jixel-background-task-handler/jixel-background-task-handler.sh b/idrocap_wa/jixel-background-task-handler/jixel-background-task-handler.sh new file mode 100755 index 0000000..031bfff --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-background-task-handler.sh @@ -0,0 +1,12 @@ +#!/bin/bash +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +/usr/bin/python3 /usr/local/ies-solutions/jixel-background-task-handler/jbth.py diff --git a/idrocap_wa/jixel-background-task-handler/jixel-cron.log b/idrocap_wa/jixel-background-task-handler/jixel-cron.log new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/jixel-background-task-handler/jixel-cron.sh b/idrocap_wa/jixel-background-task-handler/jixel-cron.sh new file mode 100755 index 0000000..d99d9d3 --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-cron.sh @@ -0,0 +1,5 @@ +#!/bin/bash +crond +crontab /usr/local/ies-solutions/jixel-cron/jixel-cron.txt +tail -f /usr/local/ies-solutions/jixel-cron/jixel-cron.txt + diff --git a/idrocap_wa/jixel-background-task-handler/jixel-cron.txt b/idrocap_wa/jixel-background-task-handler/jixel-cron.txt new file mode 100644 index 0000000..3dcf589 --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-cron.txt @@ -0,0 +1,6 @@ +# always put 3 rows: service called, date and the actual service called output: +* * * * * echo "/var/www/jixel/bin/cake" >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log +* * * * * date >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log +* * * * * /var/www/jixel/bin/cake >> /usr/local/ies-solutions/jixel-cron/jixel-cron.log +0 0 * * 0 rm -f /usr/local/ies-solutions/jixel-cron/jixel-cron.log +# keep this line empty! \ No newline at end of file diff --git a/idrocap_wa/jixel-background-task-handler/jixel-general-purpose-rabbit-consumer.sh b/idrocap_wa/jixel-background-task-handler/jixel-general-purpose-rabbit-consumer.sh new file mode 100755 index 0000000..ce79ed6 --- /dev/null +++ b/idrocap_wa/jixel-background-task-handler/jixel-general-purpose-rabbit-consumer.sh @@ -0,0 +1,12 @@ +#!/bin/bash +if [ -f /run/secrets/rabbitmq_username ]; then + export RABBITMQ_USERNAME=$(cat /run/secrets/rabbitmq_username) +else + echo "Secret file 'rabbitmq_username' not found!" >&2 +fi +if [ -f /run/secrets/rabbitmq_password ]; then + export RABBITMQ_PASSWORD=$(cat /run/secrets/rabbitmq_password) +else + echo "Secret file 'rabbitmq_password' not found!" >&2 +fi +/usr/bin/python3 /usr/local/ies-solutions/jixel-general-purpose-rabbit-consumer/jgprc.py diff --git a/idrocap_wa/phpcs.xml b/idrocap_wa/phpcs.xml new file mode 100644 index 0000000..cb4c2dc --- /dev/null +++ b/idrocap_wa/phpcs.xml @@ -0,0 +1,12 @@ + + + + + + + */src/Controller/* + + + src/ + tests/ + diff --git a/idrocap_wa/phpstan.neon b/idrocap_wa/phpstan.neon new file mode 100644 index 0000000..c131dec --- /dev/null +++ b/idrocap_wa/phpstan.neon @@ -0,0 +1,6 @@ +parameters: + level: 8 + treatPhpDocTypesAsCertain: false + checkGenericClassInNonGenericObjectType: false + paths: + - src/ diff --git a/idrocap_wa/phpunit.xml.dist b/idrocap_wa/phpunit.xml.dist new file mode 100644 index 0000000..4dfd186 --- /dev/null +++ b/idrocap_wa/phpunit.xml.dist @@ -0,0 +1,37 @@ + + + + + + + + + + + tests/TestCase/ + + + + + + + + + + + + + src/ + plugins/*/src/ + + + src/Console/Installer.php + + + diff --git a/idrocap_wa/plugins/.gitkeep b/idrocap_wa/plugins/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/psalm.xml b/idrocap_wa/psalm.xml new file mode 100644 index 0000000..4e9226b --- /dev/null +++ b/idrocap_wa/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/idrocap_wa/resources/.gitkeep b/idrocap_wa/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/resources/locales/cake.pot b/idrocap_wa/resources/locales/cake.pot new file mode 100644 index 0000000..6f1c7d7 --- /dev/null +++ b/idrocap_wa/resources/locales/cake.pot @@ -0,0 +1,279 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: CakePHP 4.4.5\n" +"POT-Creation-Date: 2023-02-28 09:27+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./templates/Error/error400.php:39 +#: ./templates/Error/error500.php:43 +msgid "Error" +msgstr "" + +#: ./templates/Error/error400.php:40 +msgid "The requested address {0} was not found on this server." +msgstr "" + +#: ./templates/Error/error500.php:41 +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:361 +msgid "An Internal Error Has Occurred." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php:462 +msgid "You are not authorized to access that location." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:359 +msgid "Not Found" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:390 +msgid "Missing or incorrect CSRF cookie type." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:394 +msgid "Missing or invalid CSRF cookie." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:417 +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:265 +msgid "CSRF token from either the request body or request headers did not match or is missing." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:247 +msgid "Missing or incorrect CSRF session key" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1489 +msgid "The requested file contains `..` and will not be read." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1497 +msgid "The requested file was not found" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:116 +msgid "{0,number,#,###.##} KB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:118 +msgid "{0,number,#,###.##} MB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:120 +msgid "{0,number,#,###.##} GB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:122 +msgid "{0,number,#,###.##} TB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:114 +msgid "{0,number,integer} Byte" +msgid_plural "{0,number,integer} Bytes" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} from now" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} after" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} before" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:120 +msgid "just now" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:157 +msgid "about a second ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:158 +msgid "about a minute ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:159 +msgid "about an hour ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:160 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:370 +msgid "about a day ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:161 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:371 +msgid "about a week ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:162 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:372 +msgid "about a month ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:163 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:373 +msgid "about a year ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:174 +msgid "in about a second" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:175 +msgid "in about a minute" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:176 +msgid "in about an hour" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:177 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:384 +msgid "in about a day" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:178 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:385 +msgid "in about a week" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:179 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:386 +msgid "in about a month" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:180 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:387 +msgid "in about a year" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:342 +msgid "today" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:409 +msgid "%s ago" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:410 +msgid "on %s" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:53 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:132 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:354 +msgid "{0} year" +msgid_plural "{0} years" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:57 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:135 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:357 +msgid "{0} month" +msgid_plural "{0} months" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:63 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:138 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:360 +msgid "{0} week" +msgid_plural "{0} weeks" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:65 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:141 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:363 +msgid "{0} day" +msgid_plural "{0} days" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:70 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:144 +msgid "{0} hour" +msgid_plural "{0} hours" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:74 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:147 +msgid "{0} minute" +msgid_plural "{0} minutes" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:78 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:150 +msgid "{0} second" +msgid_plural "{0} seconds" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:63 +msgid "This value is already in use" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:110 +msgid "This value does not exist" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:232 +msgid "Cannot modify row: a constraint for the `{0}` association fails." +msgstr "" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:270 +msgid "The count does not match {0}{1}" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Utility/Text.php:923 +msgid "and" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2539 +msgid "This field is required" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2559 +#: ./vendor/cakephp/cakephp/src/View/Form/ArrayContext.php:249 +msgid "This field cannot be left empty" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2711 +msgid "The provided value is invalid" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:979 +msgid "Edit {0}" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:981 +msgid "New {0}" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:1917 +msgid "Submit" +msgstr "" + diff --git a/idrocap_wa/resources/locales/default.pot b/idrocap_wa/resources/locales/default.pot new file mode 100644 index 0000000..4c05ce9 --- /dev/null +++ b/idrocap_wa/resources/locales/default.pot @@ -0,0 +1,1709 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2023-03-03 14:35+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./src/Controller/Api/AttachmentsController.php:36 +#: ./src/Controller/AttachmentsController.php:38 +#: ./src/Controller/AttachmentsController.php:68 +msgid "Allegato non trovato" +msgstr "" + +#: ./src/Controller/Api/AttachmentsController.php:37 +#: ./src/Controller/AttachmentsController.php:39 +#: ./src/Controller/AttachmentsController.php:69 +msgid "Non hai i permessi necessari per visionare l'allegato" +msgstr "" + +#: ./src/Controller/Api/OrganisationsController.php:104 +msgid "Organizzazione non trovata!" +msgstr "" + +#: ./src/Controller/Api/UsersController.php:160 +msgid "Utente non trovato!" +msgstr "" + +#: ./src/Controller/AppController.php:95 +msgid "SYSADMIN" +msgstr "" + +#: ./src/Controller/AppController.php:99 +#: ./templates/Capabilities/index.php:13 +#: ./templates/Groups/handle_capabilities.php:23 +#: ./templates/Groups/view.php:42 +msgid "Gestione competenze" +msgstr "" + +#: ./src/Controller/AppController.php:104 +msgid "Test notifiche" +msgstr "" + +#: ./src/Controller/AppController.php:107 +msgid "Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:24 +#: ./src/Controller/CapabilitiesController.php:54 +#: ./src/Controller/CapabilitiesController.php:97 +#: ./src/Controller/CapabilitiesController.php:135 +#: ./src/Controller/CapabilitiesController.php:177 +#: ./src/Controller/GroupsController.php:31 +#: ./src/Controller/GroupsController.php:54 +#: ./src/Controller/GroupsController.php:92 +#: ./src/Controller/GroupsController.php:112 +#: ./src/Controller/GroupsController.php:136 +#: ./src/Controller/GroupsController.php:160 +#: ./src/Controller/GroupsController.php:183 +#: ./src/Controller/OrganisationsController.php:32 +#: ./src/Controller/OrganisationsController.php:60 +#: ./src/Controller/OrganisationsController.php:109 +#: ./src/Controller/OrganisationsController.php:131 +#: ./src/Controller/OrganisationsController.php:155 +#: ./src/Controller/OrganisationsController.php:181 +#: ./src/Controller/UsersController.php:38 +#: ./src/Controller/UsersController.php:70 +#: ./src/Controller/UsersController.php:113 +#: ./src/Controller/UsersController.php:119 +#: ./src/Controller/UsersController.php:136 +#: ./src/Controller/UsersController.php:177 +#: ./src/Controller/UsersController.php:211 +#: ./src/Controller/UsersController.php:216 +msgid "Non hai i permessi necessari" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:79 +msgid "Competenza \"{0}\" nascosta con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:82 +msgid "Errore durante il tentativo di nascondere la Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:117 +msgid "Competenza \"{0}\" resa visibile con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:120 +msgid "Errore durante il tentativo di rendere visibile la Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:159 +msgid "Competenza \"{0}\" cancellata con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:162 +msgid "Errore durante la cancellazione della Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:197 +msgid "Competenza \"{0}\" ripristinata con successo!" +msgstr "" + +#: ./src/Controller/CapabilitiesController.php:200 +msgid "Errore durante il ripristino della Competenza \"{0}\"!" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:27 +#: ./src/Controller/DeliveriesController.php:125 +#: ./src/Controller/EmailsController.php:25 +#: ./src/Controller/EmailsController.php:64 +#: ./src/Controller/FaxesController.php:25 +#: ./src/Controller/FaxesController.php:64 +#: ./src/Controller/MobilePhonesController.php:26 +#: ./src/Controller/MobilePhonesController.php:65 +#: ./src/Controller/PhonesController.php:25 +#: ./src/Controller/PhonesController.php:64 +#: ./src/Controller/TelegramChatsController.php:25 +#: ./src/Controller/TelegramChatsController.php:63 +msgid "Gestione recapiti non prevista per questa tipologia di oggetto" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questa organizzazione" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questo utente" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:30 +msgid "Non hai i permessi per visualizzare i recapiti per {0}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:128 +msgid "Non hai i permessi per eliminare i recapiti di questo tipo per {0}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:134 +#: ./src/Model/Entity/Actor.php:87 +msgid "Cellulare ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:137 +#: ./src/Model/Entity/Actor.php:97 +msgid "Fax ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:140 +#: ./src/Model/Entity/Actor.php:107 +msgid "Email ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:143 +#: ./src/Model/Entity/Actor.php:117 +msgid "Telefono ({0}): {1}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:146 +#: ./src/Model/Entity/Actor.php:127 +msgid "Telegram Chat ID: {0}" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:154 +msgid "Il recapito \"{0}\" è stato cancellato con successo" +msgstr "" + +#: ./src/Controller/DeliveriesController.php:156 +msgid "Errore durante la cancellazione del recapito {0}. Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/EmailsController.php:27 +#: ./src/Controller/FaxesController.php:27 +#: ./src/Controller/MobilePhonesController.php:28 +#: ./src/Controller/PhonesController.php:27 +#: ./src/Controller/TelegramChatsController.php:27 +msgid "Non hai i permessi per aggiungere i recapiti di questo tipo per {0}" +msgstr "" + +#: ./src/Controller/EmailsController.php:39 +msgid "L'Email è stata aggiunta con successo." +msgstr "" + +#: ./src/Controller/EmailsController.php:43 +msgid "Errore durante l'aggiunta dell'Email: {0}" +msgstr "" + +#: ./src/Controller/EmailsController.php:66 +#: ./src/Controller/FaxesController.php:66 +#: ./src/Controller/MobilePhonesController.php:67 +#: ./src/Controller/PhonesController.php:66 +#: ./src/Controller/TelegramChatsController.php:65 +msgid "Non hai i permessi per modificare i recapiti di questo tipo per {0}" +msgstr "" + +#: ./src/Controller/EmailsController.php:71 +msgid "L'Email è stata modificata con successo." +msgstr "" + +#: ./src/Controller/EmailsController.php:75 +msgid "Errore durante la modifica dell'Email. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/FaxesController.php:39 +msgid "Il Fax è stato aggiunto con successo." +msgstr "" + +#: ./src/Controller/FaxesController.php:43 +msgid "Errore durante l'aggiunta del Fax: {0}" +msgstr "" + +#: ./src/Controller/FaxesController.php:71 +msgid "Il Fax è stato modificato con successo." +msgstr "" + +#: ./src/Controller/FaxesController.php:75 +msgid "Errore durante la modifica del Fax. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/GroupsController.php:57 +#: ./src/Controller/OrganisationsController.php:63 +#: ./templates/Capabilities/index.php:41 +#: ./templates/Deliveries/index.php:49 +#: ./templates/Deliveries/index.php:91 +#: ./templates/Deliveries/index.php:133 +#: ./templates/Deliveries/index.php:175 +#: ./templates/Emails/add.php:48 +#: ./templates/Emails/edit.php:48 +#: ./templates/Faxes/add.php:48 +#: ./templates/Faxes/edit.php:48 +#: ./templates/Groups/add.php:38 +#: ./templates/Groups/edit.php:43 +#: ./templates/Groups/index.php:31 +#: ./templates/Groups/view.php:35 +#: ./templates/MobilePhones/add.php:48 +#: ./templates/MobilePhones/edit.php:48 +#: ./templates/Organisations/index.php:29 +#: ./templates/Phones/add.php:48 +#: ./templates/Phones/edit.php:48 +msgid "Descrizione" +msgstr "" + +#: ./src/Controller/GroupsController.php:58 +#: ./templates/Groups/add.php:39 +#: ./templates/Groups/edit.php:44 +#: ./templates/Groups/index.php:32 +#: ./templates/Groups/view.php:37 +msgid "Profilo Default" +msgstr "" + +#: ./src/Controller/GroupsController.php:59 +#: ./templates/Groups/add.php:40 +#: ./templates/Groups/edit.php:45 +#: ./templates/Groups/index.php:33 +#: ./templates/Groups/view.php:39 +msgid "Profilo Amministratore" +msgstr "" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "SI" +msgstr "" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "NO" +msgstr "" + +#: ./src/Controller/GroupsController.php:118 +msgid "Profilo Utente creato con successo." +msgstr "" + +#: ./src/Controller/GroupsController.php:122 +msgid "Errore durante la creazione del Profilo Utente: {0}" +msgstr "" + +#: ./src/Controller/GroupsController.php:142 +#: ./src/Controller/GroupsController.php:206 +msgid "Profilo Utente \"{0}\" modificato con successo." +msgstr "" + +#: ./src/Controller/GroupsController.php:146 +#: ./src/Controller/GroupsController.php:209 +msgid "Errore durante la modifica del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/GroupsController.php:166 +msgid "Il Profilo Utente \"{0}\" è stato cancellato con successo" +msgstr "" + +#: ./src/Controller/GroupsController.php:168 +msgid "Errore durante la cancellazione del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/MapsController.php:131 +msgid "Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}" +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:40 +msgid "Il Cellulare è stato aggiunto con successo." +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:44 +msgid "Errore durante l'aggiunta del Cellulare: {0}" +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:72 +msgid "Il Cellulare è stato modificato con successo." +msgstr "" + +#: ./src/Controller/MobilePhonesController.php:76 +msgid "Errore durante la modifica del Cellulare. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/NotificationsController.php:51 +msgid "Errore durante la cancellazione della notifica: " +msgstr "" + +#: ./src/Controller/OrganisationsController.php:64 +#: ./templates/Organisations/add.php:38 +#: ./templates/Organisations/edit.php:42 +#: ./templates/Organisations/index.php:30 +#: ./templates/Organisations/view.php:37 +msgid "Acronimo" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:65 +#: ./templates/Organisations/index.php:31 +msgid "Tipologia" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:66 +#: ./templates/Maps/index.php:131 +#: ./templates/Organisations/add.php:140 +#: ./templates/Organisations/add.php:159 +#: ./templates/Organisations/edit.php:63 +#: ./templates/Organisations/index.php:32 +#: ./templates/Organisations/view.php:52 +#: ./templates/Users/add.php:46 +#: ./templates/Users/edit.php:51 +#: ./templates/Users/view.php:55 +msgid "Indirizzo" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:67 +#: ./templates/Maps/index.php:120 +#: ./templates/Organisations/add.php:129 +#: ./templates/Organisations/add.php:161 +#: ./templates/Organisations/edit.php:65 +#: ./templates/Organisations/index.php:34 +#: ./templates/Organisations/view.php:54 +msgid "Comune" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:68 +#: ./templates/Organisations/add.php:160 +#: ./templates/Organisations/edit.php:64 +#: ./templates/Organisations/index.php:33 +#: ./templates/Organisations/view.php:53 +#: ./templates/Users/add.php:48 +#: ./templates/Users/edit.php:53 +#: ./templates/Users/view.php:59 +msgid "CAP" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:69 +#: ./templates/Maps/index.php:109 +#: ./templates/Organisations/add.php:118 +#: ./templates/Organisations/add.php:162 +#: ./templates/Organisations/edit.php:66 +#: ./templates/Organisations/index.php:35 +#: ./templates/Organisations/view.php:55 +msgid "Provincia" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:70 +#: ./src/Controller/UsersController.php:76 +#: ./templates/Organisations/index.php:36 +#: ./templates/Organisations/view.php:56 +#: ./templates/Users/index.php:32 +msgid "Recapiti" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:137 +msgid "Organizzazione creata con successo." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:141 +msgid "Errore durante la creazione dell'organizzazione: {0}" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:163 +msgid "Organizzazione \"{0}\" modificata con successo." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:167 +msgid "Errore durante la modifica dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:188 +msgid "Impossibile eliminare l'organizzazione \"{0}\". Ci sono {1} utenti collegati ad essa." +msgstr "" + +#: ./src/Controller/OrganisationsController.php:193 +msgid "L'organizzazione \"{0}\" è stata cancellata con successo" +msgstr "" + +#: ./src/Controller/OrganisationsController.php:195 +msgid "Errore durante la cancellazione dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/PhonesController.php:39 +msgid "Il Telefono è stato aggiunto con successo." +msgstr "" + +#: ./src/Controller/PhonesController.php:43 +msgid "Errore durante l'aggiunta del Telefono: {0}" +msgstr "" + +#: ./src/Controller/PhonesController.php:71 +msgid "Il Telefono è stato modificato con successo." +msgstr "" + +#: ./src/Controller/PhonesController.php:75 +msgid "Errore durante la modifica del Telefono. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:39 +msgid "La Chat Telegram è stata aggiunta con successo." +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:43 +msgid "Errore durante l'aggiunta della Chat Telegram: {0}" +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:70 +msgid "La Chat Telegram è stata modificata con successo." +msgstr "" + +#: ./src/Controller/TelegramChatsController.php:74 +msgid "Errore durante la modifica della Chat Telegram. Riprovare di nuovo" +msgstr "" + +#: ./src/Controller/UsersController.php:73 +#: ./templates/Users/add.php:41 +#: ./templates/Users/edit.php:46 +#: ./templates/Users/index.php:29 +#: ./templates/Users/view.php:45 +msgid "Cognome" +msgstr "" + +#: ./src/Controller/UsersController.php:74 +#: ./templates/ControllableObjects/get_attachments.php:59 +#: ./templates/Organisations/add.php:37 +#: ./templates/Organisations/edit.php:41 +#: ./templates/Organisations/view.php:36 +#: ./templates/Users/add.php:40 +#: ./templates/Users/edit.php:45 +#: ./templates/Users/index.php:30 +#: ./templates/Users/view.php:43 +msgid "Nome" +msgstr "" + +#: ./src/Controller/UsersController.php:75 +#: ./templates/Users/index.php:31 +msgid "Username" +msgstr "" + +#: ./src/Controller/UsersController.php:77 +#: ./templates/Users/add.php:52 +#: ./templates/Users/edit.php:57 +#: ./templates/Users/index.php:33 +#: ./templates/Users/view.php:65 +msgid "Profili" +msgstr "" + +#: ./src/Controller/UsersController.php:78 +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +#: ./templates/Users/add.php:50 +#: ./templates/Users/edit.php:55 +#: ./templates/Users/index.php:34 +#: ./templates/Users/view.php:63 +msgid "Organizzazione" +msgstr "" + +#: ./src/Controller/UsersController.php:156 +msgid "Utente creato con successo." +msgstr "" + +#: ./src/Controller/UsersController.php:160 +msgid "Errore durante la creazione dell'utente: {0}" +msgstr "" + +#: ./src/Controller/UsersController.php:190 +msgid "Utente \"{0}\" modificato con successo." +msgstr "" + +#: ./src/Controller/UsersController.php:194 +msgid "Errore durante la modifica dell'utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/UsersController.php:219 +msgid "L'utente \"{0}\" è stato cancellato con successo" +msgstr "" + +#: ./src/Controller/UsersController.php:221 +msgid "Errore durante la cancellazione dell'utente \"{0}\". Riprovare di nuovo." +msgstr "" + +#: ./src/Controller/UsersController.php:244 +msgid "Ho dimenticato la mia password" +msgstr "" + +#: ./src/Controller/UsersController.php:256 +msgid "Logout eseguito con successo." +msgstr "" + +#: ./src/Controller/UsersController.php:294 +msgid "Inserire un indirizzo email valido!" +msgstr "" + +#: ./src/Controller/UsersController.php:306 +msgid "A breve riceverai un'email all'indirizzo \"{0}\" con le istruzioni per eseguire il reset della password per il tuo account con username \"{1}\"." +msgstr "" + +#: ./src/Controller/UsersController.php:311 +msgid "L'indirizzo email inserito non risulta presente" +msgstr "" + +#: ./src/Controller/UsersController.php:316 +#: ./src/Controller/UsersController.php:364 +msgid "Ritorna al login" +msgstr "" + +#: ./src/Controller/UsersController.php:332 +msgid "Impossibile completare la procedura di recupero password." +msgstr "" + +#: ./src/Controller/UsersController.php:355 +msgid "Impossibile cambiare la password" +msgstr "" + +#: ./src/Controller/UsersController.php:359 +msgid "La nuova password non è valida e/o le 2 password non coincidono" +msgstr "" + +#: ./src/Controller/UsersController.php:397 +msgid "Errore durante l'eliminazione della foto utente!" +msgstr "" + +#: ./src/Controller/UsersController.php:399 +msgid "Foto utente eliminata con successo" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:41 +msgid "Test Test Test" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:43 +msgid "Hai ricevuto questo messaggio di test perchè sei registrato/a sulla piattaforma {0} ed hai almeno un recapito abilitato alla ricezione delle notifiche" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:46 +msgid "Recupero password {0}" +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:50 +msgid "Hai ricevuto questo messaggio perchè sei registrato/a sulla piattaforma {0} ed è stata richiesta la procedura di recupero credenziali per il tuo account. Se non hai richiesto tale procedura ti preghiamo di ignorare questo messaggio. Per accedere a {0} utilizza il seguente username: \" {1} \" . Clicca sul seguente link per impostare una nuova password " +msgstr "" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:53 +msgid "{0} mancante" +msgstr "" + +#: ./src/Model/Behavior/AttachmentsBehavior.php:132 +msgid "L'allegato è obbligatorio!" +msgstr "" + +#: ./src/Model/Entity/ControllableObject.php:241 +msgid "Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "" + +#: ./src/Model/Table/EmailsTable.php:107 +msgid "Indirizzo email già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/FaxesTable.php:103 +msgid "Fax già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/MobilePhonesTable.php:107 +msgid "Cellulare già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/OrganisationsTable.php:169 +msgid "Le geometrie inserite per georeferenziare l'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "" + +#: ./src/Model/Table/PhonesTable.php:99 +msgid "Telefono già presente a sistema!" +msgstr "" + +#: ./src/Model/Table/PushNotificationsTable.php:97 +msgid "Non puoi associare nuovamente questo token allo stesso utente" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:106 +msgid "La password deve contenere almeno {0} caratteri" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:111 +msgid "La password deve contenere almeno {0} carattere/i maiuscolo/i" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:117 +msgid "La password deve contenere almeno {0} numero/i" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:131 +msgid "La password deve contenere almeno {1} carattere/i speciale/i tra \"{0}\"" +msgstr "" + +#: ./src/Model/Table/UsersTable.php:256 +msgid "Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)" +msgstr "" + +#: ./src/View/Cell/MapCell.php:182 +msgid "Geometrie disegnate" +msgstr "" + +#: ./templates/Capabilities/index.php:9 +#: ./templates/Deliveries/index.php:9 +#: ./templates/Emails/add.php:9 +#: ./templates/Emails/edit.php:9 +#: ./templates/Faxes/add.php:9 +#: ./templates/Faxes/edit.php:9 +#: ./templates/Groups/add.php:9 +#: ./templates/Groups/edit.php:9 +#: ./templates/Groups/handle_capabilities.php:9 +#: ./templates/Groups/index.php:9 +#: ./templates/Groups/view.php:9 +#: ./templates/Maps/index.php:9 +#: ./templates/MobilePhones/add.php:9 +#: ./templates/MobilePhones/edit.php:9 +#: ./templates/Organisations/add.php:9 +#: ./templates/Organisations/edit.php:9 +#: ./templates/Organisations/index.php:9 +#: ./templates/Organisations/view.php:9 +#: ./templates/Phones/add.php:9 +#: ./templates/Phones/edit.php:9 +#: ./templates/TelegramChats/add.php:9 +#: ./templates/TelegramChats/edit.php:9 +#: ./templates/Users/add.php:9 +#: ./templates/Users/edit.php:9 +#: ./templates/Users/index.php:9 +#: ./templates/Users/view.php:9 +msgid "Configurazioni" +msgstr "" + +#: ./templates/Capabilities/index.php:24 +msgid "Lista delle competenze" +msgstr "" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca per descrizione competenza o codice o nome del gruppo di competenze" +msgstr "" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca" +msgstr "" + +#: ./templates/Capabilities/index.php:42 +msgid "Codice" +msgstr "" + +#: ./templates/Capabilities/index.php:43 +msgid "Priorità" +msgstr "" + +#: ./templates/Capabilities/index.php:44 +msgid "Gruppo" +msgstr "" + +#: ./templates/Capabilities/index.php:45 +#: ./templates/ControllableObjects/get_attachments.php:66 +#: ./templates/Deliveries/index.php:52 +#: ./templates/Deliveries/index.php:94 +#: ./templates/Deliveries/index.php:136 +#: ./templates/Deliveries/index.php:177 +#: ./templates/Deliveries/index.php:217 +#: ./templates/Groups/index.php:34 +#: ./templates/Organisations/index.php:37 +#: ./templates/Users/index.php:35 +msgid "Azioni" +msgstr "" + +#: ./templates/Capabilities/index.php:57 +#: ./templates/Groups/handle_capabilities.php:57 +#: ./templates/Groups/handle_capabilities.php:58 +#: ./templates/Groups/handle_capabilities.php:59 +msgid "Competenza non visibile e non configurabile dai non SYSADMIN" +msgstr "" + +#: ./templates/Capabilities/index.php:58 +msgid "Competenza eliminata dal sistema" +msgstr "" + +#: ./templates/Capabilities/index.php:67 +msgid "Nascondi" +msgstr "" + +#: ./templates/Capabilities/index.php:67 +msgid "Mostra" +msgstr "" + +#: ./templates/Capabilities/index.php:68 +msgid "Ripristina" +msgstr "" + +#: ./templates/Capabilities/index.php:68 +#: ./templates/Deliveries/index.php:63 +#: ./templates/Deliveries/index.php:105 +#: ./templates/Deliveries/index.php:147 +#: ./templates/Deliveries/index.php:187 +#: ./templates/Deliveries/index.php:227 +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Cancella" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Allegati presenti: {0}" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Nessun Allegato presente" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:60 +msgid "Georeferenziazione" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:62 +msgid "Dimensione" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:63 +msgid "Tipo" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:64 +msgid "Caricato il" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:65 +#: ./templates/cell/Filters/display.php:57 +msgid "Da" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:80 +msgid "File pubblico" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:83 +msgid "File privato" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:106 +msgid "Visualizza" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:110 +msgid "Segna da eliminare" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come non rilevante" +msgstr "" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come rilevante" +msgstr "" + +#: ./templates/Dashboard/index.php:16 +msgid "Jixel Dashboard" +msgstr "" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Lista {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Organizzazioni" +msgstr "" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Utenti" +msgstr "" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Dettaglio {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Utente" +msgstr "" + +#: ./templates/Deliveries/index.php:23 +#: ./templates/Emails/add.php:23 +#: ./templates/Emails/edit.php:23 +#: ./templates/Faxes/add.php:23 +#: ./templates/Faxes/edit.php:23 +#: ./templates/MobilePhones/add.php:23 +#: ./templates/MobilePhones/edit.php:23 +#: ./templates/Organisations/view.php:69 +#: ./templates/Phones/add.php:23 +#: ./templates/Phones/edit.php:23 +#: ./templates/TelegramChats/add.php:23 +#: ./templates/TelegramChats/edit.php:23 +#: ./templates/Users/view.php:70 +msgid "Gestione recapiti" +msgstr "" + +#: ./templates/Deliveries/index.php:31 +msgid "Recapiti associati a {0} \"{1}\"" +msgstr "" + +#: ./templates/Deliveries/index.php:41 +msgid "Cellulare: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:50 +#: ./templates/MobilePhones/add.php:47 +#: ./templates/MobilePhones/edit.php:47 +msgid "Cellulare" +msgstr "" + +#: ./templates/Deliveries/index.php:51 +#: ./templates/Deliveries/index.php:93 +#: ./templates/Deliveries/index.php:135 +#: ./templates/Deliveries/index.php:216 +#: ./templates/Emails/add.php:49 +#: ./templates/Emails/edit.php:49 +#: ./templates/Faxes/add.php:49 +#: ./templates/Faxes/edit.php:49 +#: ./templates/MobilePhones/add.php:49 +#: ./templates/MobilePhones/edit.php:49 +#: ./templates/TelegramChats/add.php:48 +#: ./templates/TelegramChats/edit.php:48 +msgid "Ricevi notifiche a questo recapito" +msgstr "" + +#: ./templates/Deliveries/index.php:62 +#: ./templates/Deliveries/index.php:104 +#: ./templates/Deliveries/index.php:146 +#: ./templates/Deliveries/index.php:186 +#: ./templates/Deliveries/index.php:226 +#: ./templates/Groups/index.php:45 +#: ./templates/Groups/view.php:43 +#: ./templates/Organisations/index.php:53 +#: ./templates/Organisations/view.php:70 +#: ./templates/Users/index.php:49 +#: ./templates/Users/view.php:71 +msgid "Modifica" +msgstr "" + +#: ./templates/Deliveries/index.php:63 +msgid "Sei sicuro che vuoi cancellare il Cellulare \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:73 +#: ./templates/MobilePhones/add.php:28 +msgid "Aggiungi Cellulare" +msgstr "" + +#: ./templates/Deliveries/index.php:84 +msgid "Fax: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:92 +#: ./templates/Faxes/add.php:47 +#: ./templates/Faxes/edit.php:47 +msgid "Fax" +msgstr "" + +#: ./templates/Deliveries/index.php:105 +msgid "Sei sicuro che vuoi cancellare il Fax \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:115 +#: ./templates/Faxes/add.php:28 +msgid "Aggiungi Fax" +msgstr "" + +#: ./templates/Deliveries/index.php:126 +msgid "Email: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:134 +#: ./templates/Emails/add.php:47 +#: ./templates/Emails/edit.php:47 +msgid "Email" +msgstr "" + +#: ./templates/Deliveries/index.php:147 +msgid "Sei sicuro che vuoi cancellare l'Email \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:157 +#: ./templates/Emails/add.php:28 +msgid "Aggiungi Email" +msgstr "" + +#: ./templates/Deliveries/index.php:168 +msgid "Telefono: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:176 +#: ./templates/Phones/add.php:47 +#: ./templates/Phones/edit.php:47 +msgid "Telefono" +msgstr "" + +#: ./templates/Deliveries/index.php:187 +msgid "Sei sicuro che vuoi cancellare il Telefono \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:197 +#: ./templates/Phones/add.php:28 +msgid "Aggiungi Telefono" +msgstr "" + +#: ./templates/Deliveries/index.php:208 +msgid "Chat Telegram: {0}" +msgstr "" + +#: ./templates/Deliveries/index.php:215 +msgid "ID" +msgstr "" + +#: ./templates/Deliveries/index.php:227 +msgid "Sei sicuro che vuoi cancellare la Chat Telegram con ID \"{0}\" ?" +msgstr "" + +#: ./templates/Deliveries/index.php:237 +#: ./templates/TelegramChats/add.php:28 +msgid "Aggiungi Chat Telegram" +msgstr "" + +#: ./templates/Emails/add.php:40 +msgid "Aggiungi Email per {0} \"{1}\"" +msgstr "" + +#: ./templates/Emails/add.php:54 +#: ./templates/Emails/edit.php:54 +#: ./templates/Faxes/add.php:54 +#: ./templates/Faxes/edit.php:54 +#: ./templates/Groups/add.php:45 +#: ./templates/Groups/edit.php:50 +#: ./templates/Groups/handle_capabilities.php:71 +#: ./templates/MobilePhones/add.php:54 +#: ./templates/MobilePhones/edit.php:54 +#: ./templates/Organisations/add.php:172 +#: ./templates/Organisations/edit.php:86 +#: ./templates/Phones/add.php:53 +#: ./templates/Phones/edit.php:53 +#: ./templates/TelegramChats/add.php:53 +#: ./templates/TelegramChats/edit.php:53 +#: ./templates/Users/add.php:57 +#: ./templates/Users/choose_new_password.php:8 +#: ./templates/Users/edit.php:62 +msgid "Salva" +msgstr "" + +#: ./templates/Emails/edit.php:28 +msgid "Modifica Email" +msgstr "" + +#: ./templates/Emails/edit.php:40 +msgid "Modifica Email per {0} \"{1}\"" +msgstr "" + +#: ./templates/Faxes/add.php:40 +msgid "Aggiungi Fax per {0} \"{1}\"" +msgstr "" + +#: ./templates/Faxes/edit.php:28 +msgid "Modifica Fax" +msgstr "" + +#: ./templates/Faxes/edit.php:40 +msgid "Modifica Fax per {0} \"{1}\"" +msgstr "" + +#: ./templates/Groups/add.php:13 +#: ./templates/Groups/edit.php:13 +#: ./templates/Groups/handle_capabilities.php:13 +#: ./templates/Groups/index.php:13 +#: ./templates/Groups/index.php:24 +#: ./templates/Groups/view.php:13 +msgid "Lista dei Profili Utente" +msgstr "" + +#: ./templates/Groups/add.php:18 +#: ./templates/Groups/add.php:31 +msgid "Nuovo Profilo Utente" +msgstr "" + +#: ./templates/Groups/edit.php:18 +#: ./templates/Groups/handle_capabilities.php:18 +#: ./templates/Groups/view.php:18 +msgid "Dettaglio Profilo Utente" +msgstr "" + +#: ./templates/Groups/edit.php:23 +#: ./templates/Groups/edit.php:36 +msgid "Modifica Profilo Utente" +msgstr "" + +#: ./templates/Groups/handle_capabilities.php:35 +msgid "Competenze associate al Profilo Utente \"{0}\"" +msgstr "" + +#: ./templates/Groups/handle_capabilities.php:45 +msgid "Gruppo di competenze non visibile e non configurabile dai non SYSADMIN" +msgstr "" + +#: ./templates/Groups/handle_capabilities.php:52 +msgid "Gruppo di competenze \"{0}\"" +msgstr "" + +#: ./templates/Groups/index.php:44 +#: ./templates/Organisations/index.php:52 +#: ./templates/Users/index.php:48 +#: ./templates/plugin/AdminLTE/element/nav-top.php:118 +msgid "Dettaglio" +msgstr "" + +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +msgid "Sei sicuro che vuoi cancellare il profilo \"{0}\" ?" +msgstr "" + +#: ./templates/Groups/view.php:30 +msgid "Informazioni Profilo Utente" +msgstr "" + +#: ./templates/Maps/index.php:25 +msgid "Mappa" +msgstr "" + +#: ./templates/Maps/index.php:30 +msgid "Campo esistente appartenente al form ospite" +msgstr "" + +#: ./templates/Maps/index.php:37 +msgid "Posizione Evento" +msgstr "" + +#: ./templates/Maps/index.php:54 +msgid "Collezione di geometrie" +msgstr "" + +#: ./templates/Maps/index.php:65 +#: ./templates/Organisations/add.php:74 +msgid "Longitudine" +msgstr "" + +#: ./templates/Maps/index.php:76 +#: ./templates/Organisations/add.php:85 +msgid "Latitudine" +msgstr "" + +#: ./templates/Maps/index.php:87 +#: ./templates/Organisations/add.php:96 +#: ./templates/Organisations/add.php:158 +#: ./templates/Organisations/edit.php:62 +#: ./templates/Organisations/view.php:51 +msgid "Coordinate (Longitudine Latitudine)" +msgstr "" + +#: ./templates/Maps/index.php:98 +#: ./templates/Organisations/add.php:107 +msgid "Cap" +msgstr "" + +#: ./templates/Maps/index.php:142 +#: ./templates/Organisations/add.php:151 +msgid "Descrizione luogo" +msgstr "" + +#: ./templates/MobilePhones/add.php:40 +msgid "Aggiungi Cellulare per {0} \"{1}\"" +msgstr "" + +#: ./templates/MobilePhones/edit.php:28 +msgid "Modifica Cellulare" +msgstr "" + +#: ./templates/MobilePhones/edit.php:40 +msgid "Modifica Cellulare per {0} \"{1}\"" +msgstr "" + +#: ./templates/Organisations/add.php:13 +#: ./templates/Organisations/edit.php:13 +#: ./templates/Organisations/index.php:13 +#: ./templates/Organisations/view.php:13 +msgid "Lista Organizzazioni" +msgstr "" + +#: ./templates/Organisations/add.php:18 +#: ./templates/Organisations/add.php:30 +msgid "Nuova Organizzazione" +msgstr "" + +#: ./templates/Organisations/add.php:39 +#: ./templates/Organisations/edit.php:43 +#: ./templates/Organisations/view.php:38 +msgid "Tipo organizzazione" +msgstr "" + +#: ./templates/Organisations/add.php:46 +#: ./templates/Organisations/edit.php:50 +#: ./templates/Organisations/view.php:45 +msgid "Posizione Organizzazione" +msgstr "" + +#: ./templates/Organisations/edit.php:18 +#: ./templates/Organisations/view.php:18 +#: ./templates/Organisations/view.php:29 +msgid "Dettaglio Organizzazione" +msgstr "" + +#: ./templates/Organisations/edit.php:23 +#: ./templates/Organisations/edit.php:34 +msgid "Modifica Organizzazione" +msgstr "" + +#: ./templates/Organisations/index.php:23 +msgid "Lista delle {0} Organizzazioni" +msgstr "" + +#: ./templates/Organisations/index.php:23 +#: ./templates/Users/index.php:23 +msgid "{0} su {1}" +msgstr "" + +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +msgid "Sei sicuro che vuoi cancellare l'organizzazione \"{0}\" ?" +msgstr "" + +#: ./templates/Phones/add.php:40 +msgid "Aggiungi Telefono per {0} \"{1}\"" +msgstr "" + +#: ./templates/Phones/edit.php:28 +msgid "Modifica Telefono" +msgstr "" + +#: ./templates/Phones/edit.php:40 +msgid "Modifica Telefono per {0} \"{1}\"" +msgstr "" + +#: ./templates/TelegramChats/add.php:40 +msgid "Aggiungi Chat Telegram per {0} \"{1}\"" +msgstr "" + +#: ./templates/TelegramChats/add.php:47 +#: ./templates/TelegramChats/edit.php:47 +msgid "Chat Telegram ID" +msgstr "" + +#: ./templates/TelegramChats/edit.php:28 +msgid "Modifica Chat Telegram" +msgstr "" + +#: ./templates/TelegramChats/edit.php:40 +msgid "Modifica Chat Telegram per {0} \"{1}\"" +msgstr "" + +#: ./templates/Users/add.php:13 +#: ./templates/Users/edit.php:13 +#: ./templates/Users/index.php:13 +#: ./templates/Users/view.php:13 +msgid "Lista Utenti" +msgstr "" + +#: ./templates/Users/add.php:18 +#: ./templates/Users/add.php:31 +msgid "Nuovo Utente" +msgstr "" + +#: ./templates/Users/add.php:38 +#: ./templates/Users/edit.php:43 +#: ./templates/Users/view.php:41 +msgid "Nome utente" +msgstr "" + +#: ./templates/Users/add.php:39 +#: ./templates/Users/edit.php:44 +msgid "Password" +msgstr "" + +#: ./templates/Users/add.php:42 +#: ./templates/Users/edit.php:47 +#: ./templates/Users/view.php:47 +msgid "Codice Fiscale" +msgstr "" + +#: ./templates/Users/add.php:43 +#: ./templates/Users/edit.php:48 +#: ./templates/Users/view.php:49 +msgid "Data di nascita" +msgstr "" + +#: ./templates/Users/add.php:44 +#: ./templates/Users/edit.php:49 +#: ./templates/Users/view.php:51 +msgid "Luogo di nascita" +msgstr "" + +#: ./templates/Users/add.php:45 +#: ./templates/Users/edit.php:50 +#: ./templates/Users/view.php:53 +msgid "Sesso" +msgstr "" + +#: ./templates/Users/add.php:47 +#: ./templates/Users/edit.php:52 +#: ./templates/Users/view.php:57 +msgid "Città" +msgstr "" + +#: ./templates/Users/add.php:49 +#: ./templates/Users/edit.php:54 +#: ./templates/Users/view.php:61 +msgid "Lingua preferita" +msgstr "" + +#: ./templates/Users/add.php:51 +#: ./templates/Users/edit.php:56 +msgid "Foto del profilo (solo jpeg di dimensioni 160x160!)" +msgstr "" + +#: ./templates/Users/choose_new_password.php:4 +msgid "Imposta una nuova password" +msgstr "" + +#: ./templates/Users/choose_new_password.php:5 +msgid "Digita la nuova password" +msgstr "" + +#: ./templates/Users/choose_new_password.php:6 +msgid "Ridigita la nuova password" +msgstr "" + +#: ./templates/Users/edit.php:18 +#: ./templates/Users/view.php:18 +msgid "Dettaglio Utente" +msgstr "" + +#: ./templates/Users/edit.php:23 +#: ./templates/Users/edit.php:36 +msgid "Modifica Utente" +msgstr "" + +#: ./templates/Users/index.php:23 +msgid "Lista dei {0} Utenti" +msgstr "" + +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Sei sicuro che vuoi cancellare l'utente \"{0}\" ?" +msgstr "" + +#: ./templates/Users/login.php:4 +msgid "Accedi" +msgstr "" + +#: ./templates/Users/login.php:8 +msgid "Login" +msgstr "" + +#: ./templates/Users/password_recovery.php:4 +msgid "Inserisci un indirizzo email associato alla tua utenza" +msgstr "" + +#: ./templates/Users/password_recovery.php:7 +msgid "Richiedi reset password" +msgstr "" + +#: ./templates/Users/view.php:30 +msgid "Informazioni Utente" +msgstr "" + +#: ./templates/Users/view.php:34 +msgid "Elimina foto" +msgstr "" + +#: ./templates/Users/view.php:34 +msgid "Sei sicuro che vuoi eliminare la foto ?" +msgstr "" + +#: ./templates/Users/view.php:62 +msgid "Non specificata" +msgstr "" + +#: ./templates/Users/view.php:67 +msgid "Recapiti:" +msgstr "" + +#: ./templates/cell/FilterInput/display.php:9 +#: ./templates/element/attachments.php:127 +msgid "Rimuovi" +msgstr "" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:113 +msgid "Filtri attivi" +msgstr "" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:116 +msgid "Filtri disattivati" +msgstr "" + +#: ./templates/cell/Filters/display.php:15 +msgid "Aggiungi un filtro" +msgstr "" + +#: ./templates/cell/Filters/display.php:34 +#: ./templates/cell/Filters/display.php:55 +msgid "Applica" +msgstr "" + +#: ./templates/cell/Filters/display.php:39 +msgid "Reset" +msgstr "" + +#: ./templates/cell/Filters/display.php:56 +msgid "Annulla" +msgstr "" + +#: ./templates/cell/Filters/display.php:58 +msgid "A" +msgstr "" + +#: ./templates/cell/Filters/display.php:59 +msgid "Dal Al" +msgstr "" + +#: ./templates/cell/Filters/display.php:60 +#: ./templates/cell/Filters/display.php:87 +msgid "Oggi" +msgstr "" + +#: ./templates/cell/Filters/display.php:62 +msgid "Dom" +msgstr "" + +#: ./templates/cell/Filters/display.php:63 +msgid "Lun" +msgstr "" + +#: ./templates/cell/Filters/display.php:64 +msgid "Mar" +msgstr "" + +#: ./templates/cell/Filters/display.php:65 +msgid "Mer" +msgstr "" + +#: ./templates/cell/Filters/display.php:66 +msgid "Gio" +msgstr "" + +#: ./templates/cell/Filters/display.php:67 +msgid "Ven" +msgstr "" + +#: ./templates/cell/Filters/display.php:68 +msgid "Sab" +msgstr "" + +#: ./templates/cell/Filters/display.php:71 +msgid "Gennaio" +msgstr "" + +#: ./templates/cell/Filters/display.php:72 +msgid "Febbraio" +msgstr "" + +#: ./templates/cell/Filters/display.php:73 +msgid "Marzo" +msgstr "" + +#: ./templates/cell/Filters/display.php:74 +msgid "Aprile" +msgstr "" + +#: ./templates/cell/Filters/display.php:75 +msgid "Maggio" +msgstr "" + +#: ./templates/cell/Filters/display.php:76 +msgid "Giugno" +msgstr "" + +#: ./templates/cell/Filters/display.php:77 +msgid "Luglio" +msgstr "" + +#: ./templates/cell/Filters/display.php:78 +msgid "Agosto" +msgstr "" + +#: ./templates/cell/Filters/display.php:79 +msgid "Settembre" +msgstr "" + +#: ./templates/cell/Filters/display.php:80 +msgid "Ottobre" +msgstr "" + +#: ./templates/cell/Filters/display.php:81 +msgid "Novembre" +msgstr "" + +#: ./templates/cell/Filters/display.php:82 +msgid "Dicembre" +msgstr "" + +#: ./templates/cell/Filters/display.php:88 +msgid "Ieri" +msgstr "" + +#: ./templates/cell/Filters/display.php:89 +msgid "Questa settimana" +msgstr "" + +#: ./templates/cell/Filters/display.php:90 +msgid "Questo mese" +msgstr "" + +#: ./templates/cell/Filters/display.php:91 +msgid "Lo scorso mese" +msgstr "" + +#: ./templates/cell/Filters/display.php:92 +msgid "Ultimi 7 giorni" +msgstr "" + +#: ./templates/cell/Filters/display.php:93 +msgid "Ultimi 15 giorni" +msgstr "" + +#: ./templates/cell/Filters/display.php:94 +msgid "Ultimi 30 giorni" +msgstr "" + +#: ./templates/cell/Filters/display.php:131 +msgid "Errore durante il recupero del filtro selezionato. Riprovare di nuovo" +msgstr "" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:118 +#: ./templates/element/Map.php:122 +msgid "OpenStreetMap ONLINE" +msgstr "" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:127 +#: ./templates/element/Map.php:131 +msgid "OpenStreetMap OFFLINE" +msgstr "" + +#: ./templates/element/Map.php:312 +#: ./templates/element/Map.php:541 +msgid "Indirizzo non trovato o fuori dall'area di competenza" +msgstr "" + +#: ./templates/element/Map.php:530 +msgid "Punto alle coordinate (EPSG:4326) Latitudine:" +msgstr "" + +#: ./templates/element/Map.php:530 +msgid "Longitudine:" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:10 +msgid "Scegli un risultato:" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:30 +msgid "Inserisci un indirizzo o le coordinate (in formato EPSG:4326)" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:31 +msgid "Cerca un indirizzo" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:36 +msgid "Inserisci un punto in mappa" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:41 +msgid "Inserisci un poligono in mappa" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:46 +msgid "Inserisci un cerchio in mappa" +msgstr "" + +#: ./templates/element/MapCore/MapPrimitives.php:51 +msgid "Cancella una geometria" +msgstr "" + +#: ./templates/element/attachmentPreview.php:16 +msgid "Il tuo browser non supporta HTML5 video tag. Prova ad aggiornare il tuo browser." +msgstr "" + +#: ./templates/element/attachmentPreview.php:35 +msgid "Anteprima non disponibile" +msgstr "" + +#: ./templates/element/attachments.php:30 +msgid "di tipo: \"{0}\"" +msgstr "" + +#: ./templates/element/attachments.php:39 +msgid "Mostra allegati correlati" +msgstr "" + +#: ./templates/element/attachments.php:48 +msgid "Allega un file " +msgstr "" + +#: ./templates/element/attachments.php:48 +msgid "Allega files " +msgstr "" + +#: ./templates/element/attachments.php:54 +msgid "Allega file pubblico " +msgstr "" + +#: ./templates/element/attachments.php:54 +msgid "Allega un file privato " +msgstr "" + +#: ./templates/element/attachments.php:54 +msgid "Allega files privati " +msgstr "" + +#: ./templates/element/attachments.php:58 +msgid "Allega files..." +msgstr "" + +#: ./templates/element/attachments.php:65 +msgid "Allega files {1} {0}" +msgstr "" + +#: ./templates/element/attachments.php:118 +msgid "latitudine" +msgstr "" + +#: ./templates/element/attachments.php:119 +msgid "longitudine" +msgstr "" + +#: ./templates/layout/error.php:38 +msgid "Back" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/aside-control-sidebar.php:4 +msgid "Notifiche" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/footer.php:6 +msgid "Versione" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/footer.php:9 +msgid "Tutti i diritti riservati" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:67 +msgid "Nuove notifiche: {0}" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:91 +msgid "Segna tutte le notifiche come lette" +msgstr "" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:121 +msgid "Esci" +msgstr "" + diff --git a/idrocap_wa/resources/locales/en/default.po b/idrocap_wa/resources/locales/en/default.po new file mode 100644 index 0000000..bd63efb --- /dev/null +++ b/idrocap_wa/resources/locales/en/default.po @@ -0,0 +1,1709 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2023-03-03 14:35+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./src/Controller/Api/AttachmentsController.php:36 +#: ./src/Controller/AttachmentsController.php:38 +#: ./src/Controller/AttachmentsController.php:68 +msgid "Allegato non trovato" +msgstr "Attachment not found" + +#: ./src/Controller/Api/AttachmentsController.php:37 +#: ./src/Controller/AttachmentsController.php:39 +#: ./src/Controller/AttachmentsController.php:69 +msgid "Non hai i permessi necessari per visionare l'allegato" +msgstr "You do not have permission to view the attachment" + +#: ./src/Controller/Api/OrganisationsController.php:104 +msgid "Organizzazione non trovata!" +msgstr "Organisation not found!" + +#: ./src/Controller/Api/UsersController.php:160 +msgid "Utente non trovato!" +msgstr "User not found!" + +#: ./src/Controller/AppController.php:95 +msgid "SYSADMIN" +msgstr "SYSADMIN" + +#: ./src/Controller/AppController.php:99 +#: ./templates/Capabilities/index.php:13 +#: ./templates/Groups/handle_capabilities.php:23 +#: ./templates/Groups/view.php:42 +msgid "Gestione competenze" +msgstr "Handle capabilities" + +#: ./src/Controller/AppController.php:104 +msgid "Test notifiche" +msgstr "Test notification system" + +#: ./src/Controller/AppController.php:107 +msgid "Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?" +msgstr "Notifications will be sent to all users and organisations that have at least one notification enabled contact! Are you sure you want to proceed ?" + +#: ./src/Controller/CapabilitiesController.php:24 +#: ./src/Controller/CapabilitiesController.php:54 +#: ./src/Controller/CapabilitiesController.php:97 +#: ./src/Controller/CapabilitiesController.php:135 +#: ./src/Controller/CapabilitiesController.php:177 +#: ./src/Controller/GroupsController.php:31 +#: ./src/Controller/GroupsController.php:54 +#: ./src/Controller/GroupsController.php:92 +#: ./src/Controller/GroupsController.php:112 +#: ./src/Controller/GroupsController.php:136 +#: ./src/Controller/GroupsController.php:160 +#: ./src/Controller/GroupsController.php:183 +#: ./src/Controller/OrganisationsController.php:32 +#: ./src/Controller/OrganisationsController.php:60 +#: ./src/Controller/OrganisationsController.php:109 +#: ./src/Controller/OrganisationsController.php:131 +#: ./src/Controller/OrganisationsController.php:155 +#: ./src/Controller/OrganisationsController.php:181 +#: ./src/Controller/UsersController.php:38 +#: ./src/Controller/UsersController.php:70 +#: ./src/Controller/UsersController.php:113 +#: ./src/Controller/UsersController.php:119 +#: ./src/Controller/UsersController.php:136 +#: ./src/Controller/UsersController.php:177 +#: ./src/Controller/UsersController.php:211 +#: ./src/Controller/UsersController.php:216 +msgid "Non hai i permessi necessari" +msgstr "You do not have needed permissions" + +#: ./src/Controller/CapabilitiesController.php:79 +msgid "Competenza \"{0}\" nascosta con successo!" +msgstr "Capability \"{0}\" successfully hidden!" + +#: ./src/Controller/CapabilitiesController.php:82 +msgid "Errore durante il tentativo di nascondere la Competenza \"{0}\"!" +msgstr "Error trying to hide the capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:117 +msgid "Competenza \"{0}\" resa visibile con successo!" +msgstr "Capability \"{0}\" successfully set unhidden!" + +#: ./src/Controller/CapabilitiesController.php:120 +msgid "Errore durante il tentativo di rendere visibile la Competenza \"{0}\"!" +msgstr "Error trying to set the capability \"{0}\" unhidden!" + +#: ./src/Controller/CapabilitiesController.php:159 +msgid "Competenza \"{0}\" cancellata con successo!" +msgstr "Capability \"{0}\" successfully deleted!" + +#: ./src/Controller/CapabilitiesController.php:162 +msgid "Errore durante la cancellazione della Competenza \"{0}\"!" +msgstr "Error trying to delete the Capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:197 +msgid "Competenza \"{0}\" ripristinata con successo!" +msgstr "Capability \"{0}\" successfully restored!" + +#: ./src/Controller/CapabilitiesController.php:200 +msgid "Errore durante il ripristino della Competenza \"{0}\"!" +msgstr "Error trying to restore the capability \"{0}\"!" + +#: ./src/Controller/DeliveriesController.php:27 +#: ./src/Controller/DeliveriesController.php:125 +#: ./src/Controller/EmailsController.php:25 +#: ./src/Controller/EmailsController.php:64 +#: ./src/Controller/FaxesController.php:25 +#: ./src/Controller/FaxesController.php:64 +#: ./src/Controller/MobilePhonesController.php:26 +#: ./src/Controller/MobilePhonesController.php:65 +#: ./src/Controller/PhonesController.php:25 +#: ./src/Controller/PhonesController.php:64 +#: ./src/Controller/TelegramChatsController.php:25 +#: ./src/Controller/TelegramChatsController.php:63 +msgid "Gestione recapiti non prevista per questa tipologia di oggetto" +msgstr "Contacts management is not expected for this type of object" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questa organizzazione" +msgstr "this organisation" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questo utente" +msgstr "this user" + +#: ./src/Controller/DeliveriesController.php:30 +msgid "Non hai i permessi per visualizzare i recapiti per {0}" +msgstr "You do not have permission to view contacts for {0}" + +#: ./src/Controller/DeliveriesController.php:128 +msgid "Non hai i permessi per eliminare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to delete contacts of this type for {0}" + +#: ./src/Controller/DeliveriesController.php:134 +#: ./src/Model/Entity/Actor.php:87 +msgid "Cellulare ({0}): {1}" +msgstr "Mobile Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:137 +#: ./src/Model/Entity/Actor.php:97 +msgid "Fax ({0}): {1}" +msgstr "Fax ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:140 +#: ./src/Model/Entity/Actor.php:107 +msgid "Email ({0}): {1}" +msgstr "Email ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:143 +#: ./src/Model/Entity/Actor.php:117 +msgid "Telefono ({0}): {1}" +msgstr "Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:146 +#: ./src/Model/Entity/Actor.php:127 +msgid "Telegram Chat ID: {0}" +msgstr "Telegram Chat ID: {0}" + +#: ./src/Controller/DeliveriesController.php:154 +msgid "Il recapito \"{0}\" è stato cancellato con successo" +msgstr "Contact \"{0}\" successfully deleted" + +#: ./src/Controller/DeliveriesController.php:156 +msgid "Errore durante la cancellazione del recapito {0}. Riprovare di nuovo." +msgstr "Error trying to delete contact {0}. Please try again." + +#: ./src/Controller/EmailsController.php:27 +#: ./src/Controller/FaxesController.php:27 +#: ./src/Controller/MobilePhonesController.php:28 +#: ./src/Controller/PhonesController.php:27 +#: ./src/Controller/TelegramChatsController.php:27 +msgid "Non hai i permessi per aggiungere i recapiti di questo tipo per {0}" +msgstr "You do not have permission to add this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:39 +msgid "L'Email è stata aggiunta con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:43 +msgid "Errore durante l'aggiunta dell'Email: {0}" +msgstr "Error trying adding Email: {0}" + +#: ./src/Controller/EmailsController.php:66 +#: ./src/Controller/FaxesController.php:66 +#: ./src/Controller/MobilePhonesController.php:67 +#: ./src/Controller/PhonesController.php:66 +#: ./src/Controller/TelegramChatsController.php:65 +msgid "Non hai i permessi per modificare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to edit this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:71 +msgid "L'Email è stata modificata con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:75 +msgid "Errore durante la modifica dell'Email. Riprovare di nuovo" +msgstr "Error trying to edit Email contact. Please try again" + +#: ./src/Controller/FaxesController.php:39 +msgid "Il Fax è stato aggiunto con successo." +msgstr "Fax successfully added." + +#: ./src/Controller/FaxesController.php:43 +msgid "Errore durante l'aggiunta del Fax: {0}" +msgstr "Error trying to add Fax: {0}" + +#: ./src/Controller/FaxesController.php:71 +msgid "Il Fax è stato modificato con successo." +msgstr "Fax successfully updated." + +#: ./src/Controller/FaxesController.php:75 +msgid "Errore durante la modifica del Fax. Riprovare di nuovo" +msgstr "Error trying to edit Fax. Please try again" + +#: ./src/Controller/GroupsController.php:57 +#: ./src/Controller/OrganisationsController.php:63 +#: ./templates/Capabilities/index.php:41 +#: ./templates/Deliveries/index.php:49 +#: ./templates/Deliveries/index.php:91 +#: ./templates/Deliveries/index.php:133 +#: ./templates/Deliveries/index.php:175 +#: ./templates/Emails/add.php:48 +#: ./templates/Emails/edit.php:48 +#: ./templates/Faxes/add.php:48 +#: ./templates/Faxes/edit.php:48 +#: ./templates/Groups/add.php:38 +#: ./templates/Groups/edit.php:43 +#: ./templates/Groups/index.php:31 +#: ./templates/Groups/view.php:35 +#: ./templates/MobilePhones/add.php:48 +#: ./templates/MobilePhones/edit.php:48 +#: ./templates/Organisations/index.php:29 +#: ./templates/Phones/add.php:48 +#: ./templates/Phones/edit.php:48 +msgid "Descrizione" +msgstr "Description" + +#: ./src/Controller/GroupsController.php:58 +#: ./templates/Groups/add.php:39 +#: ./templates/Groups/edit.php:44 +#: ./templates/Groups/index.php:32 +#: ./templates/Groups/view.php:37 +msgid "Profilo Default" +msgstr "Default Profile" + +#: ./src/Controller/GroupsController.php:59 +#: ./templates/Groups/add.php:40 +#: ./templates/Groups/edit.php:45 +#: ./templates/Groups/index.php:33 +#: ./templates/Groups/view.php:39 +msgid "Profilo Amministratore" +msgstr "Admin Profile" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "SI" +msgstr "YES" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "NO" +msgstr "NO" + +#: ./src/Controller/GroupsController.php:118 +msgid "Profilo Utente creato con successo." +msgstr "User Profile successfully created." + +#: ./src/Controller/GroupsController.php:122 +msgid "Errore durante la creazione del Profilo Utente: {0}" +msgstr "Error trying to create User Profile: {0}" + +#: ./src/Controller/GroupsController.php:142 +#: ./src/Controller/GroupsController.php:206 +msgid "Profilo Utente \"{0}\" modificato con successo." +msgstr "User Profile \"{0}\" successfully updated." + +#: ./src/Controller/GroupsController.php:146 +#: ./src/Controller/GroupsController.php:209 +msgid "Errore durante la modifica del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/GroupsController.php:166 +msgid "Il Profilo Utente \"{0}\" è stato cancellato con successo" +msgstr "\"{0}\" User Profile successfully deleted" + +#: ./src/Controller/GroupsController.php:168 +msgid "Errore durante la cancellazione del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/MapsController.php:131 +msgid "Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}" +msgstr "Point at coordinates (EPSG:4326) Latitude: {0}, Longitude: {1}" + +#: ./src/Controller/MobilePhonesController.php:40 +msgid "Il Cellulare è stato aggiunto con successo." +msgstr "Mobile Phone contact successfully created." + +#: ./src/Controller/MobilePhonesController.php:44 +msgid "Errore durante l'aggiunta del Cellulare: {0}" +msgstr "Error trying to create Mobile Phone: {0}" + +#: ./src/Controller/MobilePhonesController.php:72 +msgid "Il Cellulare è stato modificato con successo." +msgstr "Mobile Phone successfully updated." + +#: ./src/Controller/MobilePhonesController.php:76 +msgid "Errore durante la modifica del Cellulare. Riprovare di nuovo" +msgstr "Error trying to edit Mobile Phone. Please try again" + +#: ./src/Controller/NotificationsController.php:51 +msgid "Errore durante la cancellazione della notifica: " +msgstr "Error trying to delete the notification: " + +#: ./src/Controller/OrganisationsController.php:64 +#: ./templates/Organisations/add.php:38 +#: ./templates/Organisations/edit.php:42 +#: ./templates/Organisations/index.php:30 +#: ./templates/Organisations/view.php:37 +msgid "Acronimo" +msgstr "Acronym" + +#: ./src/Controller/OrganisationsController.php:65 +#: ./templates/Organisations/index.php:31 +msgid "Tipologia" +msgstr "Typology" + +#: ./src/Controller/OrganisationsController.php:66 +#: ./templates/Maps/index.php:131 +#: ./templates/Organisations/add.php:140 +#: ./templates/Organisations/add.php:159 +#: ./templates/Organisations/edit.php:63 +#: ./templates/Organisations/index.php:32 +#: ./templates/Organisations/view.php:52 +#: ./templates/Users/add.php:46 +#: ./templates/Users/edit.php:51 +#: ./templates/Users/view.php:55 +msgid "Indirizzo" +msgstr "Address" + +#: ./src/Controller/OrganisationsController.php:67 +#: ./templates/Maps/index.php:120 +#: ./templates/Organisations/add.php:129 +#: ./templates/Organisations/add.php:161 +#: ./templates/Organisations/edit.php:65 +#: ./templates/Organisations/index.php:34 +#: ./templates/Organisations/view.php:54 +msgid "Comune" +msgstr "District" + +#: ./src/Controller/OrganisationsController.php:68 +#: ./templates/Organisations/add.php:160 +#: ./templates/Organisations/edit.php:64 +#: ./templates/Organisations/index.php:33 +#: ./templates/Organisations/view.php:53 +#: ./templates/Users/add.php:48 +#: ./templates/Users/edit.php:53 +#: ./templates/Users/view.php:59 +msgid "CAP" +msgstr "ZIP code" + +#: ./src/Controller/OrganisationsController.php:69 +#: ./templates/Maps/index.php:109 +#: ./templates/Organisations/add.php:118 +#: ./templates/Organisations/add.php:162 +#: ./templates/Organisations/edit.php:66 +#: ./templates/Organisations/index.php:35 +#: ./templates/Organisations/view.php:55 +msgid "Provincia" +msgstr "Province" + +#: ./src/Controller/OrganisationsController.php:70 +#: ./src/Controller/UsersController.php:76 +#: ./templates/Organisations/index.php:36 +#: ./templates/Organisations/view.php:56 +#: ./templates/Users/index.php:32 +msgid "Recapiti" +msgstr "Contacts" + +#: ./src/Controller/OrganisationsController.php:137 +msgid "Organizzazione creata con successo." +msgstr "Organisation successfully created." + +#: ./src/Controller/OrganisationsController.php:141 +msgid "Errore durante la creazione dell'organizzazione: {0}" +msgstr "Error trying to create the organisation: {0}" + +#: ./src/Controller/OrganisationsController.php:163 +msgid "Organizzazione \"{0}\" modificata con successo." +msgstr "Organisation \"{0}\" successfully updated." + +#: ./src/Controller/OrganisationsController.php:167 +msgid "Errore durante la modifica dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the organisation \"{0}\". Please try again." + +#: ./src/Controller/OrganisationsController.php:188 +msgid "Impossibile eliminare l'organizzazione \"{0}\". Ci sono {1} utenti collegati ad essa." +msgstr "Unable to delete the organisation \"{0}\". There are {1} belonging users." + +#: ./src/Controller/OrganisationsController.php:193 +msgid "L'organizzazione \"{0}\" è stata cancellata con successo" +msgstr "Organisation \"{0}\" successfully deleted" + +#: ./src/Controller/OrganisationsController.php:195 +msgid "Errore durante la cancellazione dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the organisation \"{0}\". Please try again." + +#: ./src/Controller/PhonesController.php:39 +msgid "Il Telefono è stato aggiunto con successo." +msgstr "Phone successfully created." + +#: ./src/Controller/PhonesController.php:43 +msgid "Errore durante l'aggiunta del Telefono: {0}" +msgstr "Error trying to create Phone: {0}" + +#: ./src/Controller/PhonesController.php:71 +msgid "Il Telefono è stato modificato con successo." +msgstr "Phone successfully updated." + +#: ./src/Controller/PhonesController.php:75 +msgid "Errore durante la modifica del Telefono. Riprovare di nuovo" +msgstr "Error trying to edit Phone. Please try again" + +#: ./src/Controller/TelegramChatsController.php:39 +msgid "La Chat Telegram è stata aggiunta con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:43 +msgid "Errore durante l'aggiunta della Chat Telegram: {0}" +msgstr "Error trying to create Telegram Chat: {0}" + +#: ./src/Controller/TelegramChatsController.php:70 +msgid "La Chat Telegram è stata modificata con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:74 +msgid "Errore durante la modifica della Chat Telegram. Riprovare di nuovo" +msgstr "Error trying to edit Telegram Chat. Please try again" + +#: ./src/Controller/UsersController.php:73 +#: ./templates/Users/add.php:41 +#: ./templates/Users/edit.php:46 +#: ./templates/Users/index.php:29 +#: ./templates/Users/view.php:45 +msgid "Cognome" +msgstr "Surname" + +#: ./src/Controller/UsersController.php:74 +#: ./templates/ControllableObjects/get_attachments.php:59 +#: ./templates/Organisations/add.php:37 +#: ./templates/Organisations/edit.php:41 +#: ./templates/Organisations/view.php:36 +#: ./templates/Users/add.php:40 +#: ./templates/Users/edit.php:45 +#: ./templates/Users/index.php:30 +#: ./templates/Users/view.php:43 +msgid "Nome" +msgstr "Name" + +#: ./src/Controller/UsersController.php:75 +#: ./templates/Users/index.php:31 +msgid "Username" +msgstr "Username" + +#: ./src/Controller/UsersController.php:77 +#: ./templates/Users/add.php:52 +#: ./templates/Users/edit.php:57 +#: ./templates/Users/index.php:33 +#: ./templates/Users/view.php:65 +msgid "Profili" +msgstr "Profiles" + +#: ./src/Controller/UsersController.php:78 +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +#: ./templates/Users/add.php:50 +#: ./templates/Users/edit.php:55 +#: ./templates/Users/index.php:34 +#: ./templates/Users/view.php:63 +msgid "Organizzazione" +msgstr "Organisation" + +#: ./src/Controller/UsersController.php:156 +msgid "Utente creato con successo." +msgstr "User successfully created." + +#: ./src/Controller/UsersController.php:160 +msgid "Errore durante la creazione dell'utente: {0}" +msgstr "Error trying to create user: {0}" + +#: ./src/Controller/UsersController.php:190 +msgid "Utente \"{0}\" modificato con successo." +msgstr "User \"{0}\" successfully updated." + +#: ./src/Controller/UsersController.php:194 +msgid "Errore durante la modifica dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:219 +msgid "L'utente \"{0}\" è stato cancellato con successo" +msgstr "User \"{0}\" successfully deleted" + +#: ./src/Controller/UsersController.php:221 +msgid "Errore durante la cancellazione dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:244 +msgid "Ho dimenticato la mia password" +msgstr "I forgot my password" + +#: ./src/Controller/UsersController.php:256 +msgid "Logout eseguito con successo." +msgstr "Successfully logged out." + +#: ./src/Controller/UsersController.php:294 +msgid "Inserire un indirizzo email valido!" +msgstr "Insert a valid email address!" + +#: ./src/Controller/UsersController.php:306 +msgid "A breve riceverai un'email all'indirizzo \"{0}\" con le istruzioni per eseguire il reset della password per il tuo account con username \"{1}\"." +msgstr "You will receive shortly an email at \"{0}\" with the instructions to reset the password for your account with username \"{1}\"." + +#: ./src/Controller/UsersController.php:311 +msgid "L'indirizzo email inserito non risulta presente" +msgstr "The email address you inserted is not valid or does not exists" + +#: ./src/Controller/UsersController.php:316 +#: ./src/Controller/UsersController.php:364 +msgid "Ritorna al login" +msgstr "Back to login" + +#: ./src/Controller/UsersController.php:332 +msgid "Impossibile completare la procedura di recupero password." +msgstr "Unable to complete reset password procedure. Please try again." + +#: ./src/Controller/UsersController.php:355 +msgid "Impossibile cambiare la password" +msgstr "Unable to change the password" + +#: ./src/Controller/UsersController.php:359 +msgid "La nuova password non è valida e/o le 2 password non coincidono" +msgstr "Either the new password is invalid or the two passwords don't match" + +#: ./src/Controller/UsersController.php:397 +msgid "Errore durante l'eliminazione della foto utente!" +msgstr "Error trying to delete the user photo!" + +#: ./src/Controller/UsersController.php:399 +msgid "Foto utente eliminata con successo" +msgstr "User photo successfully deleted" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:41 +msgid "Test Test Test" +msgstr "Test Test Test" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:43 +msgid "Hai ricevuto questo messaggio di test perchè sei registrato/a sulla piattaforma {0} ed hai almeno un recapito abilitato alla ricezione delle notifiche" +msgstr "You're receiving this message because you are a registered user to {0} platform and you have at least one notification enabled contact" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:46 +msgid "Recupero password {0}" +msgstr "{0} password reset" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:50 +msgid "Hai ricevuto questo messaggio perchè sei registrato/a sulla piattaforma {0} ed è stata richiesta la procedura di recupero credenziali per il tuo account. Se non hai richiesto tale procedura ti preghiamo di ignorare questo messaggio. Per accedere a {0} utilizza il seguente username: \" {1} \" . Clicca sul seguente link per impostare una nuova password " +msgstr "You're receiving this message because you are a registered user to {0} platform and you requested a password reset for your account. Plese disregard this message if you didn't request it or if you changed your mind. Please use the following username to gain access to your account: \" {1} \" . Follow this link to reset your password instead " + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:53 +msgid "{0} mancante" +msgstr "Missing \"{0}\" notification code" + +#: ./src/Model/Behavior/AttachmentsBehavior.php:132 +msgid "L'allegato è obbligatorio!" +msgstr "The attachment is mandatory!" + +#: ./src/Model/Entity/ControllableObject.php:241 +msgid "Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The given coordinates used to georeferencing one or more attachments are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/EmailsTable.php:107 +msgid "Indirizzo email già presente a sistema!" +msgstr "Email address already exists!" + +#: ./src/Model/Table/FaxesTable.php:103 +msgid "Fax già presente a sistema!" +msgstr "Fax already exists!" + +#: ./src/Model/Table/MobilePhonesTable.php:107 +msgid "Cellulare già presente a sistema!" +msgstr "Mobile Phone already exists!" + +#: ./src/Model/Table/OrganisationsTable.php:169 +msgid "Le geometrie inserite per georeferenziare l'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The inserted geometries used to georeferenciate the organisation, are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/PhonesTable.php:99 +msgid "Telefono già presente a sistema!" +msgstr "Phone already exists!" + +#: ./src/Model/Table/PushNotificationsTable.php:97 +msgid "Non puoi associare nuovamente questo token allo stesso utente" +msgstr "You cannot use this push notification token again with this user" + +#: ./src/Model/Table/UsersTable.php:106 +msgid "La password deve contenere almeno {0} caratteri" +msgstr "The password must contain at least {0} characters" + +#: ./src/Model/Table/UsersTable.php:111 +msgid "La password deve contenere almeno {0} carattere/i maiuscolo/i" +msgstr "The password must contain at least {0} uppercase characters" + +#: ./src/Model/Table/UsersTable.php:117 +msgid "La password deve contenere almeno {0} numero/i" +msgstr "The password must contain at least {0} numbers" + +#: ./src/Model/Table/UsersTable.php:131 +msgid "La password deve contenere almeno {1} carattere/i speciale/i tra \"{0}\"" +msgstr "The password must contain at least {1} special characters to be chosen among \"{0}\"" + +#: ./src/Model/Table/UsersTable.php:256 +msgid "Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)" +msgstr "Error trying to save user photo. Please make sure that the photo you are trying to save is in the correct format and size (jpeg 160x160)" + +#: ./src/View/Cell/MapCell.php:182 +msgid "Geometrie disegnate" +msgstr "Drawn geometries" + +#: ./templates/Capabilities/index.php:9 +#: ./templates/Deliveries/index.php:9 +#: ./templates/Emails/add.php:9 +#: ./templates/Emails/edit.php:9 +#: ./templates/Faxes/add.php:9 +#: ./templates/Faxes/edit.php:9 +#: ./templates/Groups/add.php:9 +#: ./templates/Groups/edit.php:9 +#: ./templates/Groups/handle_capabilities.php:9 +#: ./templates/Groups/index.php:9 +#: ./templates/Groups/view.php:9 +#: ./templates/Maps/index.php:9 +#: ./templates/MobilePhones/add.php:9 +#: ./templates/MobilePhones/edit.php:9 +#: ./templates/Organisations/add.php:9 +#: ./templates/Organisations/edit.php:9 +#: ./templates/Organisations/index.php:9 +#: ./templates/Organisations/view.php:9 +#: ./templates/Phones/add.php:9 +#: ./templates/Phones/edit.php:9 +#: ./templates/TelegramChats/add.php:9 +#: ./templates/TelegramChats/edit.php:9 +#: ./templates/Users/add.php:9 +#: ./templates/Users/edit.php:9 +#: ./templates/Users/index.php:9 +#: ./templates/Users/view.php:9 +msgid "Configurazioni" +msgstr "Configurations" + +#: ./templates/Capabilities/index.php:24 +msgid "Lista delle competenze" +msgstr "Capabilities list" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca per descrizione competenza o codice o nome del gruppo di competenze" +msgstr "Search by capability description, code or capability group name" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca" +msgstr "Search" + +#: ./templates/Capabilities/index.php:42 +msgid "Codice" +msgstr "Code" + +#: ./templates/Capabilities/index.php:43 +msgid "Priorità" +msgstr "Priority" + +#: ./templates/Capabilities/index.php:44 +msgid "Gruppo" +msgstr "Group" + +#: ./templates/Capabilities/index.php:45 +#: ./templates/ControllableObjects/get_attachments.php:66 +#: ./templates/Deliveries/index.php:52 +#: ./templates/Deliveries/index.php:94 +#: ./templates/Deliveries/index.php:136 +#: ./templates/Deliveries/index.php:177 +#: ./templates/Deliveries/index.php:217 +#: ./templates/Groups/index.php:34 +#: ./templates/Organisations/index.php:37 +#: ./templates/Users/index.php:35 +msgid "Azioni" +msgstr "Actions" + +#: ./templates/Capabilities/index.php:57 +#: ./templates/Groups/handle_capabilities.php:57 +#: ./templates/Groups/handle_capabilities.php:58 +#: ./templates/Groups/handle_capabilities.php:59 +msgid "Competenza non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability not visible and not configurable by non SYSADMIN users" + +#: ./templates/Capabilities/index.php:58 +msgid "Competenza eliminata dal sistema" +msgstr "Capability successfully deleted" + +#: ./templates/Capabilities/index.php:67 +msgid "Nascondi" +msgstr "Hide" + +#: ./templates/Capabilities/index.php:67 +msgid "Mostra" +msgstr "Show" + +#: ./templates/Capabilities/index.php:68 +msgid "Ripristina" +msgstr "Restore" + +#: ./templates/Capabilities/index.php:68 +#: ./templates/Deliveries/index.php:63 +#: ./templates/Deliveries/index.php:105 +#: ./templates/Deliveries/index.php:147 +#: ./templates/Deliveries/index.php:187 +#: ./templates/Deliveries/index.php:227 +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Cancella" +msgstr "Delete" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Allegati presenti: {0}" +msgstr "Attachments: {0}" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Nessun Allegato presente" +msgstr "No Attachments" + +#: ./templates/ControllableObjects/get_attachments.php:60 +msgid "Georeferenziazione" +msgstr "Georeferencing" + +#: ./templates/ControllableObjects/get_attachments.php:62 +msgid "Dimensione" +msgstr "Size" + +#: ./templates/ControllableObjects/get_attachments.php:63 +msgid "Tipo" +msgstr "Type" + +#: ./templates/ControllableObjects/get_attachments.php:64 +msgid "Caricato il" +msgstr "Uploaded" + +#: ./templates/ControllableObjects/get_attachments.php:65 +#: ./templates/cell/Filters/display.php:57 +msgid "Da" +msgstr "From" + +#: ./templates/ControllableObjects/get_attachments.php:80 +msgid "File pubblico" +msgstr "Public file" + +#: ./templates/ControllableObjects/get_attachments.php:83 +msgid "File privato" +msgstr "Private file" + +#: ./templates/ControllableObjects/get_attachments.php:106 +msgid "Visualizza" +msgstr "View" + +#: ./templates/ControllableObjects/get_attachments.php:110 +msgid "Segna da eliminare" +msgstr "Mark as to be deleted" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come non rilevante" +msgstr "Mark as not relevant" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come rilevante" +msgstr "Mark as relevant" + +#: ./templates/Dashboard/index.php:16 +msgid "Jixel Dashboard" +msgstr "Jixel Dashboard" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Lista {0}" +msgstr "List {0}" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Organizzazioni" +msgstr "Organisations" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Utenti" +msgstr "Users" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Dettaglio {0}" +msgstr "{0} Details" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Utente" +msgstr "User" + +#: ./templates/Deliveries/index.php:23 +#: ./templates/Emails/add.php:23 +#: ./templates/Emails/edit.php:23 +#: ./templates/Faxes/add.php:23 +#: ./templates/Faxes/edit.php:23 +#: ./templates/MobilePhones/add.php:23 +#: ./templates/MobilePhones/edit.php:23 +#: ./templates/Organisations/view.php:69 +#: ./templates/Phones/add.php:23 +#: ./templates/Phones/edit.php:23 +#: ./templates/TelegramChats/add.php:23 +#: ./templates/TelegramChats/edit.php:23 +#: ./templates/Users/view.php:70 +msgid "Gestione recapiti" +msgstr "Contacts management" + +#: ./templates/Deliveries/index.php:31 +msgid "Recapiti associati a {0} \"{1}\"" +msgstr "Associated contacts to {0} \"{1}\"" + +#: ./templates/Deliveries/index.php:41 +msgid "Cellulare: {0}" +msgstr "Mobile Phone {0}" + +#: ./templates/Deliveries/index.php:50 +#: ./templates/MobilePhones/add.php:47 +#: ./templates/MobilePhones/edit.php:47 +msgid "Cellulare" +msgstr "Mobile Phone" + +#: ./templates/Deliveries/index.php:51 +#: ./templates/Deliveries/index.php:93 +#: ./templates/Deliveries/index.php:135 +#: ./templates/Deliveries/index.php:216 +#: ./templates/Emails/add.php:49 +#: ./templates/Emails/edit.php:49 +#: ./templates/Faxes/add.php:49 +#: ./templates/Faxes/edit.php:49 +#: ./templates/MobilePhones/add.php:49 +#: ./templates/MobilePhones/edit.php:49 +#: ./templates/TelegramChats/add.php:48 +#: ./templates/TelegramChats/edit.php:48 +msgid "Ricevi notifiche a questo recapito" +msgstr "Receive notifications at this contact" + +#: ./templates/Deliveries/index.php:62 +#: ./templates/Deliveries/index.php:104 +#: ./templates/Deliveries/index.php:146 +#: ./templates/Deliveries/index.php:186 +#: ./templates/Deliveries/index.php:226 +#: ./templates/Groups/index.php:45 +#: ./templates/Groups/view.php:43 +#: ./templates/Organisations/index.php:53 +#: ./templates/Organisations/view.php:70 +#: ./templates/Users/index.php:49 +#: ./templates/Users/view.php:71 +msgid "Modifica" +msgstr "Edit" + +#: ./templates/Deliveries/index.php:63 +msgid "Sei sicuro che vuoi cancellare il Cellulare \"{0}\" ?" +msgstr "Are you sure you want to delete the Mobile Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:73 +#: ./templates/MobilePhones/add.php:28 +msgid "Aggiungi Cellulare" +msgstr "Add Mobile Phone" + +#: ./templates/Deliveries/index.php:84 +msgid "Fax: {0}" +msgstr "Fax: {0}" + +#: ./templates/Deliveries/index.php:92 +#: ./templates/Faxes/add.php:47 +#: ./templates/Faxes/edit.php:47 +msgid "Fax" +msgstr "Fax" + +#: ./templates/Deliveries/index.php:105 +msgid "Sei sicuro che vuoi cancellare il Fax \"{0}\" ?" +msgstr "Are you sure you want to delete the Fax \"{0}\" ?" + +#: ./templates/Deliveries/index.php:115 +#: ./templates/Faxes/add.php:28 +msgid "Aggiungi Fax" +msgstr "Add Fax" + +#: ./templates/Deliveries/index.php:126 +msgid "Email: {0}" +msgstr "Email: {0}" + +#: ./templates/Deliveries/index.php:134 +#: ./templates/Emails/add.php:47 +#: ./templates/Emails/edit.php:47 +msgid "Email" +msgstr "Email" + +#: ./templates/Deliveries/index.php:147 +msgid "Sei sicuro che vuoi cancellare l'Email \"{0}\" ?" +msgstr "Are you sure you want to delete the Email \"{0}\" ?" + +#: ./templates/Deliveries/index.php:157 +#: ./templates/Emails/add.php:28 +msgid "Aggiungi Email" +msgstr "Add Email" + +#: ./templates/Deliveries/index.php:168 +msgid "Telefono: {0}" +msgstr "Phone {0}" + +#: ./templates/Deliveries/index.php:176 +#: ./templates/Phones/add.php:47 +#: ./templates/Phones/edit.php:47 +msgid "Telefono" +msgstr "Phone" + +#: ./templates/Deliveries/index.php:187 +msgid "Sei sicuro che vuoi cancellare il Telefono \"{0}\" ?" +msgstr "Are you sure you want to delete the Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:197 +#: ./templates/Phones/add.php:28 +msgid "Aggiungi Telefono" +msgstr "Add Phone" + +#: ./templates/Deliveries/index.php:208 +msgid "Chat Telegram: {0}" +msgstr "Telegram Chat: {0}" + +#: ./templates/Deliveries/index.php:215 +msgid "ID" +msgstr "ID" + +#: ./templates/Deliveries/index.php:227 +msgid "Sei sicuro che vuoi cancellare la Chat Telegram con ID \"{0}\" ?" +msgstr "Are you sure you want to delete the Telegram Chat with ID \"{0}\" ?" + +#: ./templates/Deliveries/index.php:237 +#: ./templates/TelegramChats/add.php:28 +msgid "Aggiungi Chat Telegram" +msgstr "Add Telegram Chat" + +#: ./templates/Emails/add.php:40 +msgid "Aggiungi Email per {0} \"{1}\"" +msgstr "Add Email for {0} \"{1}\"" + +#: ./templates/Emails/add.php:54 +#: ./templates/Emails/edit.php:54 +#: ./templates/Faxes/add.php:54 +#: ./templates/Faxes/edit.php:54 +#: ./templates/Groups/add.php:45 +#: ./templates/Groups/edit.php:50 +#: ./templates/Groups/handle_capabilities.php:71 +#: ./templates/MobilePhones/add.php:54 +#: ./templates/MobilePhones/edit.php:54 +#: ./templates/Organisations/add.php:172 +#: ./templates/Organisations/edit.php:86 +#: ./templates/Phones/add.php:53 +#: ./templates/Phones/edit.php:53 +#: ./templates/TelegramChats/add.php:53 +#: ./templates/TelegramChats/edit.php:53 +#: ./templates/Users/add.php:57 +#: ./templates/Users/choose_new_password.php:8 +#: ./templates/Users/edit.php:62 +msgid "Salva" +msgstr "Save" + +#: ./templates/Emails/edit.php:28 +msgid "Modifica Email" +msgstr "Edit Email" + +#: ./templates/Emails/edit.php:40 +msgid "Modifica Email per {0} \"{1}\"" +msgstr "Edit Email for {0} \"{1}\"" + +#: ./templates/Faxes/add.php:40 +msgid "Aggiungi Fax per {0} \"{1}\"" +msgstr "Add Fax for {0} \"{1}\"" + +#: ./templates/Faxes/edit.php:28 +msgid "Modifica Fax" +msgstr "Edit Fax" + +#: ./templates/Faxes/edit.php:40 +msgid "Modifica Fax per {0} \"{1}\"" +msgstr "Edit Fax for {0} \"{1}\"" + +#: ./templates/Groups/add.php:13 +#: ./templates/Groups/edit.php:13 +#: ./templates/Groups/handle_capabilities.php:13 +#: ./templates/Groups/index.php:13 +#: ./templates/Groups/index.php:24 +#: ./templates/Groups/view.php:13 +msgid "Lista dei Profili Utente" +msgstr "User Profiles List" + +#: ./templates/Groups/add.php:18 +#: ./templates/Groups/add.php:31 +msgid "Nuovo Profilo Utente" +msgstr "New User Profile" + +#: ./templates/Groups/edit.php:18 +#: ./templates/Groups/handle_capabilities.php:18 +#: ./templates/Groups/view.php:18 +msgid "Dettaglio Profilo Utente" +msgstr "User Profile Details" + +#: ./templates/Groups/edit.php:23 +#: ./templates/Groups/edit.php:36 +msgid "Modifica Profilo Utente" +msgstr "Edit User Profile" + +#: ./templates/Groups/handle_capabilities.php:35 +msgid "Competenze associate al Profilo Utente \"{0}\"" +msgstr "User Profile \"{0}\" associated capabilities" + +#: ./templates/Groups/handle_capabilities.php:45 +msgid "Gruppo di competenze non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability Groups not visible and not configurable by non SYSADMIN users" + +#: ./templates/Groups/handle_capabilities.php:52 +msgid "Gruppo di competenze \"{0}\"" +msgstr "Capability Group \"{0}\"" + +#: ./templates/Groups/index.php:44 +#: ./templates/Organisations/index.php:52 +#: ./templates/Users/index.php:48 +#: ./templates/plugin/AdminLTE/element/nav-top.php:118 +msgid "Dettaglio" +msgstr "Details" + +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +msgid "Sei sicuro che vuoi cancellare il profilo \"{0}\" ?" +msgstr "Are you sure you want to delete the user profile \"{0}\" ?" + +#: ./templates/Groups/view.php:30 +msgid "Informazioni Profilo Utente" +msgstr "User Profile Informations" + +#: ./templates/Maps/index.php:25 +msgid "Mappa" +msgstr "Map" + +#: ./templates/Maps/index.php:30 +msgid "Campo esistente appartenente al form ospite" +msgstr "Existing field that belongs to the hosting form" + +#: ./templates/Maps/index.php:37 +msgid "Posizione Evento" +msgstr "Incident location" + +#: ./templates/Maps/index.php:54 +msgid "Collezione di geometrie" +msgstr "Geometry collection" + +#: ./templates/Maps/index.php:65 +#: ./templates/Organisations/add.php:74 +msgid "Longitudine" +msgstr "Longitude" + +#: ./templates/Maps/index.php:76 +#: ./templates/Organisations/add.php:85 +msgid "Latitudine" +msgstr "Latitude" + +#: ./templates/Maps/index.php:87 +#: ./templates/Organisations/add.php:96 +#: ./templates/Organisations/add.php:158 +#: ./templates/Organisations/edit.php:62 +#: ./templates/Organisations/view.php:51 +msgid "Coordinate (Longitudine Latitudine)" +msgstr "Coordinates (Longitude Latitude)" + +#: ./templates/Maps/index.php:98 +#: ./templates/Organisations/add.php:107 +msgid "Cap" +msgstr "ZIP code" + +#: ./templates/Maps/index.php:142 +#: ./templates/Organisations/add.php:151 +msgid "Descrizione luogo" +msgstr "Location description" + +#: ./templates/MobilePhones/add.php:40 +msgid "Aggiungi Cellulare per {0} \"{1}\"" +msgstr "Add Mobile Phone for {0} \"{1}\"" + +#: ./templates/MobilePhones/edit.php:28 +msgid "Modifica Cellulare" +msgstr "Edit Mobile Phone" + +#: ./templates/MobilePhones/edit.php:40 +msgid "Modifica Cellulare per {0} \"{1}\"" +msgstr "Edit Mobile Phone for {0} \"{1}\"" + +#: ./templates/Organisations/add.php:13 +#: ./templates/Organisations/edit.php:13 +#: ./templates/Organisations/index.php:13 +#: ./templates/Organisations/view.php:13 +msgid "Lista Organizzazioni" +msgstr "Organisations List" + +#: ./templates/Organisations/add.php:18 +#: ./templates/Organisations/add.php:30 +msgid "Nuova Organizzazione" +msgstr "New Organisation" + +#: ./templates/Organisations/add.php:39 +#: ./templates/Organisations/edit.php:43 +#: ./templates/Organisations/view.php:38 +msgid "Tipo organizzazione" +msgstr "Organisation type" + +#: ./templates/Organisations/add.php:46 +#: ./templates/Organisations/edit.php:50 +#: ./templates/Organisations/view.php:45 +msgid "Posizione Organizzazione" +msgstr "Organisation Location" + +#: ./templates/Organisations/edit.php:18 +#: ./templates/Organisations/view.php:18 +#: ./templates/Organisations/view.php:29 +msgid "Dettaglio Organizzazione" +msgstr "Organisation Details" + +#: ./templates/Organisations/edit.php:23 +#: ./templates/Organisations/edit.php:34 +msgid "Modifica Organizzazione" +msgstr "Edit Organisation" + +#: ./templates/Organisations/index.php:23 +msgid "Lista delle {0} Organizzazioni" +msgstr "List of {0} Organisations" + +#: ./templates/Organisations/index.php:23 +#: ./templates/Users/index.php:23 +msgid "{0} su {1}" +msgstr "{0} out of {1}" + +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +msgid "Sei sicuro che vuoi cancellare l'organizzazione \"{0}\" ?" +msgstr "Are you sure you want to delete the organisation \"{0}\" ?" + +#: ./templates/Phones/add.php:40 +msgid "Aggiungi Telefono per {0} \"{1}\"" +msgstr "Add Phone for {0} \"{1}\"" + +#: ./templates/Phones/edit.php:28 +msgid "Modifica Telefono" +msgstr "Edit Phone" + +#: ./templates/Phones/edit.php:40 +msgid "Modifica Telefono per {0} \"{1}\"" +msgstr "Edit Phone for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:40 +msgid "Aggiungi Chat Telegram per {0} \"{1}\"" +msgstr "Add Telegram Chat for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:47 +#: ./templates/TelegramChats/edit.php:47 +msgid "Chat Telegram ID" +msgstr "Telegram Chat ID" + +#: ./templates/TelegramChats/edit.php:28 +msgid "Modifica Chat Telegram" +msgstr "Edit Telegram Chat" + +#: ./templates/TelegramChats/edit.php:40 +msgid "Modifica Chat Telegram per {0} \"{1}\"" +msgstr "Edit Telegram Chat for {0} \"{1}\"" + +#: ./templates/Users/add.php:13 +#: ./templates/Users/edit.php:13 +#: ./templates/Users/index.php:13 +#: ./templates/Users/view.php:13 +msgid "Lista Utenti" +msgstr "Users List" + +#: ./templates/Users/add.php:18 +#: ./templates/Users/add.php:31 +msgid "Nuovo Utente" +msgstr "New User" + +#: ./templates/Users/add.php:38 +#: ./templates/Users/edit.php:43 +#: ./templates/Users/view.php:41 +msgid "Nome utente" +msgstr "Username" + +#: ./templates/Users/add.php:39 +#: ./templates/Users/edit.php:44 +msgid "Password" +msgstr "Password" + +#: ./templates/Users/add.php:42 +#: ./templates/Users/edit.php:47 +#: ./templates/Users/view.php:47 +msgid "Codice Fiscale" +msgstr "Tax ID code" + +#: ./templates/Users/add.php:43 +#: ./templates/Users/edit.php:48 +#: ./templates/Users/view.php:49 +msgid "Data di nascita" +msgstr "Date of birth" + +#: ./templates/Users/add.php:44 +#: ./templates/Users/edit.php:49 +#: ./templates/Users/view.php:51 +msgid "Luogo di nascita" +msgstr "Birth place" + +#: ./templates/Users/add.php:45 +#: ./templates/Users/edit.php:50 +#: ./templates/Users/view.php:53 +msgid "Sesso" +msgstr "Gender" + +#: ./templates/Users/add.php:47 +#: ./templates/Users/edit.php:52 +#: ./templates/Users/view.php:57 +msgid "Città" +msgstr "City" + +#: ./templates/Users/add.php:49 +#: ./templates/Users/edit.php:54 +#: ./templates/Users/view.php:61 +msgid "Lingua preferita" +msgstr "Favourite language" + +#: ./templates/Users/add.php:51 +#: ./templates/Users/edit.php:56 +msgid "Foto del profilo (solo jpeg di dimensioni 160x160!)" +msgstr "Photo (160x160 sized jpeg only!)" + +#: ./templates/Users/choose_new_password.php:4 +msgid "Imposta una nuova password" +msgstr "Set a new password" + +#: ./templates/Users/choose_new_password.php:5 +msgid "Digita la nuova password" +msgstr "Enter the new password" + +#: ./templates/Users/choose_new_password.php:6 +msgid "Ridigita la nuova password" +msgstr "Retype the previous entered password" + +#: ./templates/Users/edit.php:18 +#: ./templates/Users/view.php:18 +msgid "Dettaglio Utente" +msgstr "User Details" + +#: ./templates/Users/edit.php:23 +#: ./templates/Users/edit.php:36 +msgid "Modifica Utente" +msgstr "Edit User" + +#: ./templates/Users/index.php:23 +msgid "Lista dei {0} Utenti" +msgstr "List of {0} Users" + +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Sei sicuro che vuoi cancellare l'utente \"{0}\" ?" +msgstr "Are you sure you wanto to delete the user \"{0}\" ?" + +#: ./templates/Users/login.php:4 +msgid "Accedi" +msgstr "Gain access" + +#: ./templates/Users/login.php:8 +msgid "Login" +msgstr "Login" + +#: ./templates/Users/password_recovery.php:4 +msgid "Inserisci un indirizzo email associato alla tua utenza" +msgstr "Insert an email that is currently associated with your account" + +#: ./templates/Users/password_recovery.php:7 +msgid "Richiedi reset password" +msgstr "Request password reset" + +#: ./templates/Users/view.php:30 +msgid "Informazioni Utente" +msgstr "User Informations" + +#: ./templates/Users/view.php:34 +msgid "Elimina foto" +msgstr "Delete photo" + +#: ./templates/Users/view.php:34 +msgid "Sei sicuro che vuoi eliminare la foto ?" +msgstr "Are you sure you want to delete the photo ?" + +#: ./templates/Users/view.php:62 +msgid "Non specificata" +msgstr "Not specified" + +#: ./templates/Users/view.php:67 +msgid "Recapiti:" +msgstr "Contacts" + +#: ./templates/cell/FilterInput/display.php:9 +#: ./templates/element/attachments.php:127 +msgid "Rimuovi" +msgstr "Remove" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:113 +msgid "Filtri attivi" +msgstr "Filters applied" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:116 +msgid "Filtri disattivati" +msgstr "No Filters applied" + +#: ./templates/cell/Filters/display.php:15 +msgid "Aggiungi un filtro" +msgstr "Add a filter" + +#: ./templates/cell/Filters/display.php:34 +#: ./templates/cell/Filters/display.php:55 +msgid "Applica" +msgstr "Apply" + +#: ./templates/cell/Filters/display.php:39 +msgid "Reset" +msgstr "Reset" + +#: ./templates/cell/Filters/display.php:56 +msgid "Annulla" +msgstr "Cancel" + +#: ./templates/cell/Filters/display.php:58 +msgid "A" +msgstr "TO" + +#: ./templates/cell/Filters/display.php:59 +msgid "Dal Al" +msgstr "From To" + +#: ./templates/cell/Filters/display.php:60 +#: ./templates/cell/Filters/display.php:87 +msgid "Oggi" +msgstr "Today" + +#: ./templates/cell/Filters/display.php:62 +msgid "Dom" +msgstr "Sun" + +#: ./templates/cell/Filters/display.php:63 +msgid "Lun" +msgstr "Mon" + +#: ./templates/cell/Filters/display.php:64 +msgid "Mar" +msgstr "Tue" + +#: ./templates/cell/Filters/display.php:65 +msgid "Mer" +msgstr "Wed" + +#: ./templates/cell/Filters/display.php:66 +msgid "Gio" +msgstr "Thu" + +#: ./templates/cell/Filters/display.php:67 +msgid "Ven" +msgstr "Fri" + +#: ./templates/cell/Filters/display.php:68 +msgid "Sab" +msgstr "Sat" + +#: ./templates/cell/Filters/display.php:71 +msgid "Gennaio" +msgstr "January" + +#: ./templates/cell/Filters/display.php:72 +msgid "Febbraio" +msgstr "February" + +#: ./templates/cell/Filters/display.php:73 +msgid "Marzo" +msgstr "March" + +#: ./templates/cell/Filters/display.php:74 +msgid "Aprile" +msgstr "April" + +#: ./templates/cell/Filters/display.php:75 +msgid "Maggio" +msgstr "May" + +#: ./templates/cell/Filters/display.php:76 +msgid "Giugno" +msgstr "June" + +#: ./templates/cell/Filters/display.php:77 +msgid "Luglio" +msgstr "July" + +#: ./templates/cell/Filters/display.php:78 +msgid "Agosto" +msgstr "August" + +#: ./templates/cell/Filters/display.php:79 +msgid "Settembre" +msgstr "September" + +#: ./templates/cell/Filters/display.php:80 +msgid "Ottobre" +msgstr "October" + +#: ./templates/cell/Filters/display.php:81 +msgid "Novembre" +msgstr "November" + +#: ./templates/cell/Filters/display.php:82 +msgid "Dicembre" +msgstr "December" + +#: ./templates/cell/Filters/display.php:88 +msgid "Ieri" +msgstr "Yesterday" + +#: ./templates/cell/Filters/display.php:89 +msgid "Questa settimana" +msgstr "This week" + +#: ./templates/cell/Filters/display.php:90 +msgid "Questo mese" +msgstr "This month" + +#: ./templates/cell/Filters/display.php:91 +msgid "Lo scorso mese" +msgstr "Last month" + +#: ./templates/cell/Filters/display.php:92 +msgid "Ultimi 7 giorni" +msgstr "Last 7 days" + +#: ./templates/cell/Filters/display.php:93 +msgid "Ultimi 15 giorni" +msgstr "Last 15 days" + +#: ./templates/cell/Filters/display.php:94 +msgid "Ultimi 30 giorni" +msgstr "Last 30 days" + +#: ./templates/cell/Filters/display.php:131 +msgid "Errore durante il recupero del filtro selezionato. Riprovare di nuovo" +msgstr "Error trying to retrieve the selected filter. Pleas try again" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:118 +#: ./templates/element/Map.php:122 +msgid "OpenStreetMap ONLINE" +msgstr "OpenStreetMap ONLINE" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:127 +#: ./templates/element/Map.php:131 +msgid "OpenStreetMap OFFLINE" +msgstr "OpenStreetMap OFFLINE" + +#: ./templates/element/Map.php:312 +#: ./templates/element/Map.php:541 +msgid "Indirizzo non trovato o fuori dall'area di competenza" +msgstr "Address not found or out of the platform configured bounding box" + +#: ./templates/element/Map.php:530 +msgid "Punto alle coordinate (EPSG:4326) Latitudine:" +msgstr "Point of coordinates (EPSG:4326) Latitude:" + +#: ./templates/element/Map.php:530 +msgid "Longitudine:" +msgstr "Longitude:" + +#: ./templates/element/MapCore/MapPrimitives.php:10 +msgid "Scegli un risultato:" +msgstr "Pick a result" + +#: ./templates/element/MapCore/MapPrimitives.php:30 +msgid "Inserisci un indirizzo o le coordinate (in formato EPSG:4326)" +msgstr "Insert an address or coordinates (EPSG:4326)" + +#: ./templates/element/MapCore/MapPrimitives.php:31 +msgid "Cerca un indirizzo" +msgstr "Look up for an address" + +#: ./templates/element/MapCore/MapPrimitives.php:36 +msgid "Inserisci un punto in mappa" +msgstr "Insert a point on map" + +#: ./templates/element/MapCore/MapPrimitives.php:41 +msgid "Inserisci un poligono in mappa" +msgstr "Draw a polygon on map" + +#: ./templates/element/MapCore/MapPrimitives.php:46 +msgid "Inserisci un cerchio in mappa" +msgstr "Draw a circle on map" + +#: ./templates/element/MapCore/MapPrimitives.php:51 +msgid "Cancella una geometria" +msgstr "Delete a geometry" + +#: ./templates/element/attachmentPreview.php:16 +msgid "Il tuo browser non supporta HTML5 video tag. Prova ad aggiornare il tuo browser." +msgstr "Your browser doesn't seem to support HTML5 video tag. Please try and update your browser to a more recent version." + +#: ./templates/element/attachmentPreview.php:35 +msgid "Anteprima non disponibile" +msgstr "Preview not available" + +#: ./templates/element/attachments.php:30 +msgid "di tipo: \"{0}\"" +msgstr "of type \"{0}\"" + +#: ./templates/element/attachments.php:39 +msgid "Mostra allegati correlati" +msgstr "Show also linked attachments" + +#: ./templates/element/attachments.php:48 +msgid "Allega un file " +msgstr "Attach a file" + +#: ./templates/element/attachments.php:48 +msgid "Allega files " +msgstr "Attach files" + +#: ./templates/element/attachments.php:54 +msgid "Allega file pubblico " +msgstr "Attach public file" + +#: ./templates/element/attachments.php:54 +msgid "Allega un file privato " +msgstr "Attach a private file" + +#: ./templates/element/attachments.php:54 +msgid "Allega files privati " +msgstr "Attach private files " + +#: ./templates/element/attachments.php:58 +msgid "Allega files..." +msgstr "Attach files..." + +#: ./templates/element/attachments.php:65 +msgid "Allega files {1} {0}" +msgstr "Attach files {1} {0}" + +#: ./templates/element/attachments.php:118 +msgid "latitudine" +msgstr "latitude" + +#: ./templates/element/attachments.php:119 +msgid "longitudine" +msgstr "longitude" + +#: ./templates/layout/error.php:38 +msgid "Back" +msgstr "Back" + +#: ./templates/plugin/AdminLTE/element/aside-control-sidebar.php:4 +msgid "Notifiche" +msgstr "Notifications" + +#: ./templates/plugin/AdminLTE/element/footer.php:6 +msgid "Versione" +msgstr "Version" + +#: ./templates/plugin/AdminLTE/element/footer.php:9 +msgid "Tutti i diritti riservati" +msgstr "All rights reserved" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:67 +msgid "Nuove notifiche: {0}" +msgstr "New notifications: {0}" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:91 +msgid "Segna tutte le notifiche come lette" +msgstr "Mark all new notifications as read" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:121 +msgid "Esci" +msgstr "Logout" + diff --git a/idrocap_wa/resources/locales/en/previous_default.po b/idrocap_wa/resources/locales/en/previous_default.po new file mode 100644 index 0000000..bd63efb --- /dev/null +++ b/idrocap_wa/resources/locales/en/previous_default.po @@ -0,0 +1,1709 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"POT-Creation-Date: 2023-03-03 14:35+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./src/Controller/Api/AttachmentsController.php:36 +#: ./src/Controller/AttachmentsController.php:38 +#: ./src/Controller/AttachmentsController.php:68 +msgid "Allegato non trovato" +msgstr "Attachment not found" + +#: ./src/Controller/Api/AttachmentsController.php:37 +#: ./src/Controller/AttachmentsController.php:39 +#: ./src/Controller/AttachmentsController.php:69 +msgid "Non hai i permessi necessari per visionare l'allegato" +msgstr "You do not have permission to view the attachment" + +#: ./src/Controller/Api/OrganisationsController.php:104 +msgid "Organizzazione non trovata!" +msgstr "Organisation not found!" + +#: ./src/Controller/Api/UsersController.php:160 +msgid "Utente non trovato!" +msgstr "User not found!" + +#: ./src/Controller/AppController.php:95 +msgid "SYSADMIN" +msgstr "SYSADMIN" + +#: ./src/Controller/AppController.php:99 +#: ./templates/Capabilities/index.php:13 +#: ./templates/Groups/handle_capabilities.php:23 +#: ./templates/Groups/view.php:42 +msgid "Gestione competenze" +msgstr "Handle capabilities" + +#: ./src/Controller/AppController.php:104 +msgid "Test notifiche" +msgstr "Test notification system" + +#: ./src/Controller/AppController.php:107 +msgid "Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?" +msgstr "Notifications will be sent to all users and organisations that have at least one notification enabled contact! Are you sure you want to proceed ?" + +#: ./src/Controller/CapabilitiesController.php:24 +#: ./src/Controller/CapabilitiesController.php:54 +#: ./src/Controller/CapabilitiesController.php:97 +#: ./src/Controller/CapabilitiesController.php:135 +#: ./src/Controller/CapabilitiesController.php:177 +#: ./src/Controller/GroupsController.php:31 +#: ./src/Controller/GroupsController.php:54 +#: ./src/Controller/GroupsController.php:92 +#: ./src/Controller/GroupsController.php:112 +#: ./src/Controller/GroupsController.php:136 +#: ./src/Controller/GroupsController.php:160 +#: ./src/Controller/GroupsController.php:183 +#: ./src/Controller/OrganisationsController.php:32 +#: ./src/Controller/OrganisationsController.php:60 +#: ./src/Controller/OrganisationsController.php:109 +#: ./src/Controller/OrganisationsController.php:131 +#: ./src/Controller/OrganisationsController.php:155 +#: ./src/Controller/OrganisationsController.php:181 +#: ./src/Controller/UsersController.php:38 +#: ./src/Controller/UsersController.php:70 +#: ./src/Controller/UsersController.php:113 +#: ./src/Controller/UsersController.php:119 +#: ./src/Controller/UsersController.php:136 +#: ./src/Controller/UsersController.php:177 +#: ./src/Controller/UsersController.php:211 +#: ./src/Controller/UsersController.php:216 +msgid "Non hai i permessi necessari" +msgstr "You do not have needed permissions" + +#: ./src/Controller/CapabilitiesController.php:79 +msgid "Competenza \"{0}\" nascosta con successo!" +msgstr "Capability \"{0}\" successfully hidden!" + +#: ./src/Controller/CapabilitiesController.php:82 +msgid "Errore durante il tentativo di nascondere la Competenza \"{0}\"!" +msgstr "Error trying to hide the capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:117 +msgid "Competenza \"{0}\" resa visibile con successo!" +msgstr "Capability \"{0}\" successfully set unhidden!" + +#: ./src/Controller/CapabilitiesController.php:120 +msgid "Errore durante il tentativo di rendere visibile la Competenza \"{0}\"!" +msgstr "Error trying to set the capability \"{0}\" unhidden!" + +#: ./src/Controller/CapabilitiesController.php:159 +msgid "Competenza \"{0}\" cancellata con successo!" +msgstr "Capability \"{0}\" successfully deleted!" + +#: ./src/Controller/CapabilitiesController.php:162 +msgid "Errore durante la cancellazione della Competenza \"{0}\"!" +msgstr "Error trying to delete the Capability \"{0}\"!" + +#: ./src/Controller/CapabilitiesController.php:197 +msgid "Competenza \"{0}\" ripristinata con successo!" +msgstr "Capability \"{0}\" successfully restored!" + +#: ./src/Controller/CapabilitiesController.php:200 +msgid "Errore durante il ripristino della Competenza \"{0}\"!" +msgstr "Error trying to restore the capability \"{0}\"!" + +#: ./src/Controller/DeliveriesController.php:27 +#: ./src/Controller/DeliveriesController.php:125 +#: ./src/Controller/EmailsController.php:25 +#: ./src/Controller/EmailsController.php:64 +#: ./src/Controller/FaxesController.php:25 +#: ./src/Controller/FaxesController.php:64 +#: ./src/Controller/MobilePhonesController.php:26 +#: ./src/Controller/MobilePhonesController.php:65 +#: ./src/Controller/PhonesController.php:25 +#: ./src/Controller/PhonesController.php:64 +#: ./src/Controller/TelegramChatsController.php:25 +#: ./src/Controller/TelegramChatsController.php:63 +msgid "Gestione recapiti non prevista per questa tipologia di oggetto" +msgstr "Contacts management is not expected for this type of object" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questa organizzazione" +msgstr "this organisation" + +#: ./src/Controller/DeliveriesController.php:29 +#: ./src/Controller/DeliveriesController.php:127 +#: ./src/Controller/EmailsController.php:26 +#: ./src/Controller/EmailsController.php:65 +#: ./src/Controller/FaxesController.php:26 +#: ./src/Controller/FaxesController.php:65 +#: ./src/Controller/MobilePhonesController.php:27 +#: ./src/Controller/MobilePhonesController.php:66 +#: ./src/Controller/PhonesController.php:26 +#: ./src/Controller/PhonesController.php:65 +#: ./src/Controller/TelegramChatsController.php:26 +#: ./src/Controller/TelegramChatsController.php:64 +msgid "questo utente" +msgstr "this user" + +#: ./src/Controller/DeliveriesController.php:30 +msgid "Non hai i permessi per visualizzare i recapiti per {0}" +msgstr "You do not have permission to view contacts for {0}" + +#: ./src/Controller/DeliveriesController.php:128 +msgid "Non hai i permessi per eliminare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to delete contacts of this type for {0}" + +#: ./src/Controller/DeliveriesController.php:134 +#: ./src/Model/Entity/Actor.php:87 +msgid "Cellulare ({0}): {1}" +msgstr "Mobile Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:137 +#: ./src/Model/Entity/Actor.php:97 +msgid "Fax ({0}): {1}" +msgstr "Fax ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:140 +#: ./src/Model/Entity/Actor.php:107 +msgid "Email ({0}): {1}" +msgstr "Email ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:143 +#: ./src/Model/Entity/Actor.php:117 +msgid "Telefono ({0}): {1}" +msgstr "Phone ({0}): {1}" + +#: ./src/Controller/DeliveriesController.php:146 +#: ./src/Model/Entity/Actor.php:127 +msgid "Telegram Chat ID: {0}" +msgstr "Telegram Chat ID: {0}" + +#: ./src/Controller/DeliveriesController.php:154 +msgid "Il recapito \"{0}\" è stato cancellato con successo" +msgstr "Contact \"{0}\" successfully deleted" + +#: ./src/Controller/DeliveriesController.php:156 +msgid "Errore durante la cancellazione del recapito {0}. Riprovare di nuovo." +msgstr "Error trying to delete contact {0}. Please try again." + +#: ./src/Controller/EmailsController.php:27 +#: ./src/Controller/FaxesController.php:27 +#: ./src/Controller/MobilePhonesController.php:28 +#: ./src/Controller/PhonesController.php:27 +#: ./src/Controller/TelegramChatsController.php:27 +msgid "Non hai i permessi per aggiungere i recapiti di questo tipo per {0}" +msgstr "You do not have permission to add this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:39 +msgid "L'Email è stata aggiunta con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:43 +msgid "Errore durante l'aggiunta dell'Email: {0}" +msgstr "Error trying adding Email: {0}" + +#: ./src/Controller/EmailsController.php:66 +#: ./src/Controller/FaxesController.php:66 +#: ./src/Controller/MobilePhonesController.php:67 +#: ./src/Controller/PhonesController.php:66 +#: ./src/Controller/TelegramChatsController.php:65 +msgid "Non hai i permessi per modificare i recapiti di questo tipo per {0}" +msgstr "You do not have permission to edit this type of contact for {0}" + +#: ./src/Controller/EmailsController.php:71 +msgid "L'Email è stata modificata con successo." +msgstr "Email successfully updated." + +#: ./src/Controller/EmailsController.php:75 +msgid "Errore durante la modifica dell'Email. Riprovare di nuovo" +msgstr "Error trying to edit Email contact. Please try again" + +#: ./src/Controller/FaxesController.php:39 +msgid "Il Fax è stato aggiunto con successo." +msgstr "Fax successfully added." + +#: ./src/Controller/FaxesController.php:43 +msgid "Errore durante l'aggiunta del Fax: {0}" +msgstr "Error trying to add Fax: {0}" + +#: ./src/Controller/FaxesController.php:71 +msgid "Il Fax è stato modificato con successo." +msgstr "Fax successfully updated." + +#: ./src/Controller/FaxesController.php:75 +msgid "Errore durante la modifica del Fax. Riprovare di nuovo" +msgstr "Error trying to edit Fax. Please try again" + +#: ./src/Controller/GroupsController.php:57 +#: ./src/Controller/OrganisationsController.php:63 +#: ./templates/Capabilities/index.php:41 +#: ./templates/Deliveries/index.php:49 +#: ./templates/Deliveries/index.php:91 +#: ./templates/Deliveries/index.php:133 +#: ./templates/Deliveries/index.php:175 +#: ./templates/Emails/add.php:48 +#: ./templates/Emails/edit.php:48 +#: ./templates/Faxes/add.php:48 +#: ./templates/Faxes/edit.php:48 +#: ./templates/Groups/add.php:38 +#: ./templates/Groups/edit.php:43 +#: ./templates/Groups/index.php:31 +#: ./templates/Groups/view.php:35 +#: ./templates/MobilePhones/add.php:48 +#: ./templates/MobilePhones/edit.php:48 +#: ./templates/Organisations/index.php:29 +#: ./templates/Phones/add.php:48 +#: ./templates/Phones/edit.php:48 +msgid "Descrizione" +msgstr "Description" + +#: ./src/Controller/GroupsController.php:58 +#: ./templates/Groups/add.php:39 +#: ./templates/Groups/edit.php:44 +#: ./templates/Groups/index.php:32 +#: ./templates/Groups/view.php:37 +msgid "Profilo Default" +msgstr "Default Profile" + +#: ./src/Controller/GroupsController.php:59 +#: ./templates/Groups/add.php:40 +#: ./templates/Groups/edit.php:45 +#: ./templates/Groups/index.php:33 +#: ./templates/Groups/view.php:39 +msgid "Profilo Amministratore" +msgstr "Admin Profile" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "SI" +msgstr "YES" + +#: ./src/Controller/GroupsController.php:64 +#: ./src/Controller/GroupsController.php:67 +#: ./templates/Deliveries/index.php:60 +#: ./templates/Deliveries/index.php:102 +#: ./templates/Deliveries/index.php:144 +#: ./templates/Deliveries/index.php:224 +#: ./templates/Groups/index.php:41 +#: ./templates/Groups/index.php:42 +#: ./templates/Groups/view.php:38 +#: ./templates/Groups/view.php:40 +msgid "NO" +msgstr "NO" + +#: ./src/Controller/GroupsController.php:118 +msgid "Profilo Utente creato con successo." +msgstr "User Profile successfully created." + +#: ./src/Controller/GroupsController.php:122 +msgid "Errore durante la creazione del Profilo Utente: {0}" +msgstr "Error trying to create User Profile: {0}" + +#: ./src/Controller/GroupsController.php:142 +#: ./src/Controller/GroupsController.php:206 +msgid "Profilo Utente \"{0}\" modificato con successo." +msgstr "User Profile \"{0}\" successfully updated." + +#: ./src/Controller/GroupsController.php:146 +#: ./src/Controller/GroupsController.php:209 +msgid "Errore durante la modifica del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/GroupsController.php:166 +msgid "Il Profilo Utente \"{0}\" è stato cancellato con successo" +msgstr "\"{0}\" User Profile successfully deleted" + +#: ./src/Controller/GroupsController.php:168 +msgid "Errore durante la cancellazione del Profilo Utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the \"{0}\" User Profile. Please try again." + +#: ./src/Controller/MapsController.php:131 +msgid "Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}" +msgstr "Point at coordinates (EPSG:4326) Latitude: {0}, Longitude: {1}" + +#: ./src/Controller/MobilePhonesController.php:40 +msgid "Il Cellulare è stato aggiunto con successo." +msgstr "Mobile Phone contact successfully created." + +#: ./src/Controller/MobilePhonesController.php:44 +msgid "Errore durante l'aggiunta del Cellulare: {0}" +msgstr "Error trying to create Mobile Phone: {0}" + +#: ./src/Controller/MobilePhonesController.php:72 +msgid "Il Cellulare è stato modificato con successo." +msgstr "Mobile Phone successfully updated." + +#: ./src/Controller/MobilePhonesController.php:76 +msgid "Errore durante la modifica del Cellulare. Riprovare di nuovo" +msgstr "Error trying to edit Mobile Phone. Please try again" + +#: ./src/Controller/NotificationsController.php:51 +msgid "Errore durante la cancellazione della notifica: " +msgstr "Error trying to delete the notification: " + +#: ./src/Controller/OrganisationsController.php:64 +#: ./templates/Organisations/add.php:38 +#: ./templates/Organisations/edit.php:42 +#: ./templates/Organisations/index.php:30 +#: ./templates/Organisations/view.php:37 +msgid "Acronimo" +msgstr "Acronym" + +#: ./src/Controller/OrganisationsController.php:65 +#: ./templates/Organisations/index.php:31 +msgid "Tipologia" +msgstr "Typology" + +#: ./src/Controller/OrganisationsController.php:66 +#: ./templates/Maps/index.php:131 +#: ./templates/Organisations/add.php:140 +#: ./templates/Organisations/add.php:159 +#: ./templates/Organisations/edit.php:63 +#: ./templates/Organisations/index.php:32 +#: ./templates/Organisations/view.php:52 +#: ./templates/Users/add.php:46 +#: ./templates/Users/edit.php:51 +#: ./templates/Users/view.php:55 +msgid "Indirizzo" +msgstr "Address" + +#: ./src/Controller/OrganisationsController.php:67 +#: ./templates/Maps/index.php:120 +#: ./templates/Organisations/add.php:129 +#: ./templates/Organisations/add.php:161 +#: ./templates/Organisations/edit.php:65 +#: ./templates/Organisations/index.php:34 +#: ./templates/Organisations/view.php:54 +msgid "Comune" +msgstr "District" + +#: ./src/Controller/OrganisationsController.php:68 +#: ./templates/Organisations/add.php:160 +#: ./templates/Organisations/edit.php:64 +#: ./templates/Organisations/index.php:33 +#: ./templates/Organisations/view.php:53 +#: ./templates/Users/add.php:48 +#: ./templates/Users/edit.php:53 +#: ./templates/Users/view.php:59 +msgid "CAP" +msgstr "ZIP code" + +#: ./src/Controller/OrganisationsController.php:69 +#: ./templates/Maps/index.php:109 +#: ./templates/Organisations/add.php:118 +#: ./templates/Organisations/add.php:162 +#: ./templates/Organisations/edit.php:66 +#: ./templates/Organisations/index.php:35 +#: ./templates/Organisations/view.php:55 +msgid "Provincia" +msgstr "Province" + +#: ./src/Controller/OrganisationsController.php:70 +#: ./src/Controller/UsersController.php:76 +#: ./templates/Organisations/index.php:36 +#: ./templates/Organisations/view.php:56 +#: ./templates/Users/index.php:32 +msgid "Recapiti" +msgstr "Contacts" + +#: ./src/Controller/OrganisationsController.php:137 +msgid "Organizzazione creata con successo." +msgstr "Organisation successfully created." + +#: ./src/Controller/OrganisationsController.php:141 +msgid "Errore durante la creazione dell'organizzazione: {0}" +msgstr "Error trying to create the organisation: {0}" + +#: ./src/Controller/OrganisationsController.php:163 +msgid "Organizzazione \"{0}\" modificata con successo." +msgstr "Organisation \"{0}\" successfully updated." + +#: ./src/Controller/OrganisationsController.php:167 +msgid "Errore durante la modifica dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit the organisation \"{0}\". Please try again." + +#: ./src/Controller/OrganisationsController.php:188 +msgid "Impossibile eliminare l'organizzazione \"{0}\". Ci sono {1} utenti collegati ad essa." +msgstr "Unable to delete the organisation \"{0}\". There are {1} belonging users." + +#: ./src/Controller/OrganisationsController.php:193 +msgid "L'organizzazione \"{0}\" è stata cancellata con successo" +msgstr "Organisation \"{0}\" successfully deleted" + +#: ./src/Controller/OrganisationsController.php:195 +msgid "Errore durante la cancellazione dell'organizzazione \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete the organisation \"{0}\". Please try again." + +#: ./src/Controller/PhonesController.php:39 +msgid "Il Telefono è stato aggiunto con successo." +msgstr "Phone successfully created." + +#: ./src/Controller/PhonesController.php:43 +msgid "Errore durante l'aggiunta del Telefono: {0}" +msgstr "Error trying to create Phone: {0}" + +#: ./src/Controller/PhonesController.php:71 +msgid "Il Telefono è stato modificato con successo." +msgstr "Phone successfully updated." + +#: ./src/Controller/PhonesController.php:75 +msgid "Errore durante la modifica del Telefono. Riprovare di nuovo" +msgstr "Error trying to edit Phone. Please try again" + +#: ./src/Controller/TelegramChatsController.php:39 +msgid "La Chat Telegram è stata aggiunta con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:43 +msgid "Errore durante l'aggiunta della Chat Telegram: {0}" +msgstr "Error trying to create Telegram Chat: {0}" + +#: ./src/Controller/TelegramChatsController.php:70 +msgid "La Chat Telegram è stata modificata con successo." +msgstr "Telegram Chat successfully created." + +#: ./src/Controller/TelegramChatsController.php:74 +msgid "Errore durante la modifica della Chat Telegram. Riprovare di nuovo" +msgstr "Error trying to edit Telegram Chat. Please try again" + +#: ./src/Controller/UsersController.php:73 +#: ./templates/Users/add.php:41 +#: ./templates/Users/edit.php:46 +#: ./templates/Users/index.php:29 +#: ./templates/Users/view.php:45 +msgid "Cognome" +msgstr "Surname" + +#: ./src/Controller/UsersController.php:74 +#: ./templates/ControllableObjects/get_attachments.php:59 +#: ./templates/Organisations/add.php:37 +#: ./templates/Organisations/edit.php:41 +#: ./templates/Organisations/view.php:36 +#: ./templates/Users/add.php:40 +#: ./templates/Users/edit.php:45 +#: ./templates/Users/index.php:30 +#: ./templates/Users/view.php:43 +msgid "Nome" +msgstr "Name" + +#: ./src/Controller/UsersController.php:75 +#: ./templates/Users/index.php:31 +msgid "Username" +msgstr "Username" + +#: ./src/Controller/UsersController.php:77 +#: ./templates/Users/add.php:52 +#: ./templates/Users/edit.php:57 +#: ./templates/Users/index.php:33 +#: ./templates/Users/view.php:65 +msgid "Profili" +msgstr "Profiles" + +#: ./src/Controller/UsersController.php:78 +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +#: ./templates/Users/add.php:50 +#: ./templates/Users/edit.php:55 +#: ./templates/Users/index.php:34 +#: ./templates/Users/view.php:63 +msgid "Organizzazione" +msgstr "Organisation" + +#: ./src/Controller/UsersController.php:156 +msgid "Utente creato con successo." +msgstr "User successfully created." + +#: ./src/Controller/UsersController.php:160 +msgid "Errore durante la creazione dell'utente: {0}" +msgstr "Error trying to create user: {0}" + +#: ./src/Controller/UsersController.php:190 +msgid "Utente \"{0}\" modificato con successo." +msgstr "User \"{0}\" successfully updated." + +#: ./src/Controller/UsersController.php:194 +msgid "Errore durante la modifica dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to edit user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:219 +msgid "L'utente \"{0}\" è stato cancellato con successo" +msgstr "User \"{0}\" successfully deleted" + +#: ./src/Controller/UsersController.php:221 +msgid "Errore durante la cancellazione dell'utente \"{0}\". Riprovare di nuovo." +msgstr "Error trying to delete user \"{0}\". Please try again." + +#: ./src/Controller/UsersController.php:244 +msgid "Ho dimenticato la mia password" +msgstr "I forgot my password" + +#: ./src/Controller/UsersController.php:256 +msgid "Logout eseguito con successo." +msgstr "Successfully logged out." + +#: ./src/Controller/UsersController.php:294 +msgid "Inserire un indirizzo email valido!" +msgstr "Insert a valid email address!" + +#: ./src/Controller/UsersController.php:306 +msgid "A breve riceverai un'email all'indirizzo \"{0}\" con le istruzioni per eseguire il reset della password per il tuo account con username \"{1}\"." +msgstr "You will receive shortly an email at \"{0}\" with the instructions to reset the password for your account with username \"{1}\"." + +#: ./src/Controller/UsersController.php:311 +msgid "L'indirizzo email inserito non risulta presente" +msgstr "The email address you inserted is not valid or does not exists" + +#: ./src/Controller/UsersController.php:316 +#: ./src/Controller/UsersController.php:364 +msgid "Ritorna al login" +msgstr "Back to login" + +#: ./src/Controller/UsersController.php:332 +msgid "Impossibile completare la procedura di recupero password." +msgstr "Unable to complete reset password procedure. Please try again." + +#: ./src/Controller/UsersController.php:355 +msgid "Impossibile cambiare la password" +msgstr "Unable to change the password" + +#: ./src/Controller/UsersController.php:359 +msgid "La nuova password non è valida e/o le 2 password non coincidono" +msgstr "Either the new password is invalid or the two passwords don't match" + +#: ./src/Controller/UsersController.php:397 +msgid "Errore durante l'eliminazione della foto utente!" +msgstr "Error trying to delete the user photo!" + +#: ./src/Controller/UsersController.php:399 +msgid "Foto utente eliminata con successo" +msgstr "User photo successfully deleted" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:41 +msgid "Test Test Test" +msgstr "Test Test Test" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:43 +msgid "Hai ricevuto questo messaggio di test perchè sei registrato/a sulla piattaforma {0} ed hai almeno un recapito abilitato alla ricezione delle notifiche" +msgstr "You're receiving this message because you are a registered user to {0} platform and you have at least one notification enabled contact" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:46 +msgid "Recupero password {0}" +msgstr "{0} password reset" + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:50 +msgid "Hai ricevuto questo messaggio perchè sei registrato/a sulla piattaforma {0} ed è stata richiesta la procedura di recupero credenziali per il tuo account. Se non hai richiesto tale procedura ti preghiamo di ignorare questo messaggio. Per accedere a {0} utilizza il seguente username: \" {1} \" . Clicca sul seguente link per impostare una nuova password " +msgstr "You're receiving this message because you are a registered user to {0} platform and you requested a password reset for your account. Plese disregard this message if you didn't request it or if you changed your mind. Please use the following username to gain access to your account: \" {1} \" . Follow this link to reset your password instead " + +#: ./src/Ies/NotificationsHandler/NotificationGenerator.php:53 +msgid "{0} mancante" +msgstr "Missing \"{0}\" notification code" + +#: ./src/Model/Behavior/AttachmentsBehavior.php:132 +msgid "L'allegato è obbligatorio!" +msgstr "The attachment is mandatory!" + +#: ./src/Model/Entity/ControllableObject.php:241 +msgid "Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The given coordinates used to georeferencing one or more attachments are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/EmailsTable.php:107 +msgid "Indirizzo email già presente a sistema!" +msgstr "Email address already exists!" + +#: ./src/Model/Table/FaxesTable.php:103 +msgid "Fax già presente a sistema!" +msgstr "Fax already exists!" + +#: ./src/Model/Table/MobilePhonesTable.php:107 +msgid "Cellulare già presente a sistema!" +msgstr "Mobile Phone already exists!" + +#: ./src/Model/Table/OrganisationsTable.php:169 +msgid "Le geometrie inserite per georeferenziare l'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell'area di competenza della piattaforma." +msgstr "The inserted geometries used to georeferenciate the organisation, are not valid. Please check that they are in the expected format (WGS84) and that they identify a point inside the platform configured bounding box." + +#: ./src/Model/Table/PhonesTable.php:99 +msgid "Telefono già presente a sistema!" +msgstr "Phone already exists!" + +#: ./src/Model/Table/PushNotificationsTable.php:97 +msgid "Non puoi associare nuovamente questo token allo stesso utente" +msgstr "You cannot use this push notification token again with this user" + +#: ./src/Model/Table/UsersTable.php:106 +msgid "La password deve contenere almeno {0} caratteri" +msgstr "The password must contain at least {0} characters" + +#: ./src/Model/Table/UsersTable.php:111 +msgid "La password deve contenere almeno {0} carattere/i maiuscolo/i" +msgstr "The password must contain at least {0} uppercase characters" + +#: ./src/Model/Table/UsersTable.php:117 +msgid "La password deve contenere almeno {0} numero/i" +msgstr "The password must contain at least {0} numbers" + +#: ./src/Model/Table/UsersTable.php:131 +msgid "La password deve contenere almeno {1} carattere/i speciale/i tra \"{0}\"" +msgstr "The password must contain at least {1} special characters to be chosen among \"{0}\"" + +#: ./src/Model/Table/UsersTable.php:256 +msgid "Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)" +msgstr "Error trying to save user photo. Please make sure that the photo you are trying to save is in the correct format and size (jpeg 160x160)" + +#: ./src/View/Cell/MapCell.php:182 +msgid "Geometrie disegnate" +msgstr "Drawn geometries" + +#: ./templates/Capabilities/index.php:9 +#: ./templates/Deliveries/index.php:9 +#: ./templates/Emails/add.php:9 +#: ./templates/Emails/edit.php:9 +#: ./templates/Faxes/add.php:9 +#: ./templates/Faxes/edit.php:9 +#: ./templates/Groups/add.php:9 +#: ./templates/Groups/edit.php:9 +#: ./templates/Groups/handle_capabilities.php:9 +#: ./templates/Groups/index.php:9 +#: ./templates/Groups/view.php:9 +#: ./templates/Maps/index.php:9 +#: ./templates/MobilePhones/add.php:9 +#: ./templates/MobilePhones/edit.php:9 +#: ./templates/Organisations/add.php:9 +#: ./templates/Organisations/edit.php:9 +#: ./templates/Organisations/index.php:9 +#: ./templates/Organisations/view.php:9 +#: ./templates/Phones/add.php:9 +#: ./templates/Phones/edit.php:9 +#: ./templates/TelegramChats/add.php:9 +#: ./templates/TelegramChats/edit.php:9 +#: ./templates/Users/add.php:9 +#: ./templates/Users/edit.php:9 +#: ./templates/Users/index.php:9 +#: ./templates/Users/view.php:9 +msgid "Configurazioni" +msgstr "Configurations" + +#: ./templates/Capabilities/index.php:24 +msgid "Lista delle competenze" +msgstr "Capabilities list" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca per descrizione competenza o codice o nome del gruppo di competenze" +msgstr "Search by capability description, code or capability group name" + +#: ./templates/Capabilities/index.php:29 +msgid "Cerca" +msgstr "Search" + +#: ./templates/Capabilities/index.php:42 +msgid "Codice" +msgstr "Code" + +#: ./templates/Capabilities/index.php:43 +msgid "Priorità" +msgstr "Priority" + +#: ./templates/Capabilities/index.php:44 +msgid "Gruppo" +msgstr "Group" + +#: ./templates/Capabilities/index.php:45 +#: ./templates/ControllableObjects/get_attachments.php:66 +#: ./templates/Deliveries/index.php:52 +#: ./templates/Deliveries/index.php:94 +#: ./templates/Deliveries/index.php:136 +#: ./templates/Deliveries/index.php:177 +#: ./templates/Deliveries/index.php:217 +#: ./templates/Groups/index.php:34 +#: ./templates/Organisations/index.php:37 +#: ./templates/Users/index.php:35 +msgid "Azioni" +msgstr "Actions" + +#: ./templates/Capabilities/index.php:57 +#: ./templates/Groups/handle_capabilities.php:57 +#: ./templates/Groups/handle_capabilities.php:58 +#: ./templates/Groups/handle_capabilities.php:59 +msgid "Competenza non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability not visible and not configurable by non SYSADMIN users" + +#: ./templates/Capabilities/index.php:58 +msgid "Competenza eliminata dal sistema" +msgstr "Capability successfully deleted" + +#: ./templates/Capabilities/index.php:67 +msgid "Nascondi" +msgstr "Hide" + +#: ./templates/Capabilities/index.php:67 +msgid "Mostra" +msgstr "Show" + +#: ./templates/Capabilities/index.php:68 +msgid "Ripristina" +msgstr "Restore" + +#: ./templates/Capabilities/index.php:68 +#: ./templates/Deliveries/index.php:63 +#: ./templates/Deliveries/index.php:105 +#: ./templates/Deliveries/index.php:147 +#: ./templates/Deliveries/index.php:187 +#: ./templates/Deliveries/index.php:227 +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Cancella" +msgstr "Delete" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Allegati presenti: {0}" +msgstr "Attachments: {0}" + +#: ./templates/ControllableObjects/get_attachments.php:45 +msgid "Nessun Allegato presente" +msgstr "No Attachments" + +#: ./templates/ControllableObjects/get_attachments.php:60 +msgid "Georeferenziazione" +msgstr "Georeferencing" + +#: ./templates/ControllableObjects/get_attachments.php:62 +msgid "Dimensione" +msgstr "Size" + +#: ./templates/ControllableObjects/get_attachments.php:63 +msgid "Tipo" +msgstr "Type" + +#: ./templates/ControllableObjects/get_attachments.php:64 +msgid "Caricato il" +msgstr "Uploaded" + +#: ./templates/ControllableObjects/get_attachments.php:65 +#: ./templates/cell/Filters/display.php:57 +msgid "Da" +msgstr "From" + +#: ./templates/ControllableObjects/get_attachments.php:80 +msgid "File pubblico" +msgstr "Public file" + +#: ./templates/ControllableObjects/get_attachments.php:83 +msgid "File privato" +msgstr "Private file" + +#: ./templates/ControllableObjects/get_attachments.php:106 +msgid "Visualizza" +msgstr "View" + +#: ./templates/ControllableObjects/get_attachments.php:110 +msgid "Segna da eliminare" +msgstr "Mark as to be deleted" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come non rilevante" +msgstr "Mark as not relevant" + +#: ./templates/ControllableObjects/get_attachments.php:112 +msgid "Segna come rilevante" +msgstr "Mark as relevant" + +#: ./templates/Dashboard/index.php:16 +msgid "Jixel Dashboard" +msgstr "Jixel Dashboard" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Lista {0}" +msgstr "List {0}" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Organizzazioni" +msgstr "Organisations" + +#: ./templates/Deliveries/index.php:13 +#: ./templates/Emails/add.php:13 +#: ./templates/Emails/edit.php:13 +#: ./templates/Faxes/add.php:13 +#: ./templates/Faxes/edit.php:13 +#: ./templates/MobilePhones/add.php:13 +#: ./templates/MobilePhones/edit.php:13 +#: ./templates/Phones/add.php:13 +#: ./templates/Phones/edit.php:13 +#: ./templates/TelegramChats/add.php:13 +#: ./templates/TelegramChats/edit.php:13 +msgid "Utenti" +msgstr "Users" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Dettaglio {0}" +msgstr "{0} Details" + +#: ./templates/Deliveries/index.php:18 +#: ./templates/Emails/add.php:18 +#: ./templates/Emails/edit.php:18 +#: ./templates/Faxes/add.php:18 +#: ./templates/Faxes/edit.php:18 +#: ./templates/MobilePhones/add.php:18 +#: ./templates/MobilePhones/edit.php:18 +#: ./templates/Phones/add.php:18 +#: ./templates/Phones/edit.php:18 +#: ./templates/TelegramChats/add.php:18 +#: ./templates/TelegramChats/edit.php:18 +msgid "Utente" +msgstr "User" + +#: ./templates/Deliveries/index.php:23 +#: ./templates/Emails/add.php:23 +#: ./templates/Emails/edit.php:23 +#: ./templates/Faxes/add.php:23 +#: ./templates/Faxes/edit.php:23 +#: ./templates/MobilePhones/add.php:23 +#: ./templates/MobilePhones/edit.php:23 +#: ./templates/Organisations/view.php:69 +#: ./templates/Phones/add.php:23 +#: ./templates/Phones/edit.php:23 +#: ./templates/TelegramChats/add.php:23 +#: ./templates/TelegramChats/edit.php:23 +#: ./templates/Users/view.php:70 +msgid "Gestione recapiti" +msgstr "Contacts management" + +#: ./templates/Deliveries/index.php:31 +msgid "Recapiti associati a {0} \"{1}\"" +msgstr "Associated contacts to {0} \"{1}\"" + +#: ./templates/Deliveries/index.php:41 +msgid "Cellulare: {0}" +msgstr "Mobile Phone {0}" + +#: ./templates/Deliveries/index.php:50 +#: ./templates/MobilePhones/add.php:47 +#: ./templates/MobilePhones/edit.php:47 +msgid "Cellulare" +msgstr "Mobile Phone" + +#: ./templates/Deliveries/index.php:51 +#: ./templates/Deliveries/index.php:93 +#: ./templates/Deliveries/index.php:135 +#: ./templates/Deliveries/index.php:216 +#: ./templates/Emails/add.php:49 +#: ./templates/Emails/edit.php:49 +#: ./templates/Faxes/add.php:49 +#: ./templates/Faxes/edit.php:49 +#: ./templates/MobilePhones/add.php:49 +#: ./templates/MobilePhones/edit.php:49 +#: ./templates/TelegramChats/add.php:48 +#: ./templates/TelegramChats/edit.php:48 +msgid "Ricevi notifiche a questo recapito" +msgstr "Receive notifications at this contact" + +#: ./templates/Deliveries/index.php:62 +#: ./templates/Deliveries/index.php:104 +#: ./templates/Deliveries/index.php:146 +#: ./templates/Deliveries/index.php:186 +#: ./templates/Deliveries/index.php:226 +#: ./templates/Groups/index.php:45 +#: ./templates/Groups/view.php:43 +#: ./templates/Organisations/index.php:53 +#: ./templates/Organisations/view.php:70 +#: ./templates/Users/index.php:49 +#: ./templates/Users/view.php:71 +msgid "Modifica" +msgstr "Edit" + +#: ./templates/Deliveries/index.php:63 +msgid "Sei sicuro che vuoi cancellare il Cellulare \"{0}\" ?" +msgstr "Are you sure you want to delete the Mobile Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:73 +#: ./templates/MobilePhones/add.php:28 +msgid "Aggiungi Cellulare" +msgstr "Add Mobile Phone" + +#: ./templates/Deliveries/index.php:84 +msgid "Fax: {0}" +msgstr "Fax: {0}" + +#: ./templates/Deliveries/index.php:92 +#: ./templates/Faxes/add.php:47 +#: ./templates/Faxes/edit.php:47 +msgid "Fax" +msgstr "Fax" + +#: ./templates/Deliveries/index.php:105 +msgid "Sei sicuro che vuoi cancellare il Fax \"{0}\" ?" +msgstr "Are you sure you want to delete the Fax \"{0}\" ?" + +#: ./templates/Deliveries/index.php:115 +#: ./templates/Faxes/add.php:28 +msgid "Aggiungi Fax" +msgstr "Add Fax" + +#: ./templates/Deliveries/index.php:126 +msgid "Email: {0}" +msgstr "Email: {0}" + +#: ./templates/Deliveries/index.php:134 +#: ./templates/Emails/add.php:47 +#: ./templates/Emails/edit.php:47 +msgid "Email" +msgstr "Email" + +#: ./templates/Deliveries/index.php:147 +msgid "Sei sicuro che vuoi cancellare l'Email \"{0}\" ?" +msgstr "Are you sure you want to delete the Email \"{0}\" ?" + +#: ./templates/Deliveries/index.php:157 +#: ./templates/Emails/add.php:28 +msgid "Aggiungi Email" +msgstr "Add Email" + +#: ./templates/Deliveries/index.php:168 +msgid "Telefono: {0}" +msgstr "Phone {0}" + +#: ./templates/Deliveries/index.php:176 +#: ./templates/Phones/add.php:47 +#: ./templates/Phones/edit.php:47 +msgid "Telefono" +msgstr "Phone" + +#: ./templates/Deliveries/index.php:187 +msgid "Sei sicuro che vuoi cancellare il Telefono \"{0}\" ?" +msgstr "Are you sure you want to delete the Phone \"{0}\" ?" + +#: ./templates/Deliveries/index.php:197 +#: ./templates/Phones/add.php:28 +msgid "Aggiungi Telefono" +msgstr "Add Phone" + +#: ./templates/Deliveries/index.php:208 +msgid "Chat Telegram: {0}" +msgstr "Telegram Chat: {0}" + +#: ./templates/Deliveries/index.php:215 +msgid "ID" +msgstr "ID" + +#: ./templates/Deliveries/index.php:227 +msgid "Sei sicuro che vuoi cancellare la Chat Telegram con ID \"{0}\" ?" +msgstr "Are you sure you want to delete the Telegram Chat with ID \"{0}\" ?" + +#: ./templates/Deliveries/index.php:237 +#: ./templates/TelegramChats/add.php:28 +msgid "Aggiungi Chat Telegram" +msgstr "Add Telegram Chat" + +#: ./templates/Emails/add.php:40 +msgid "Aggiungi Email per {0} \"{1}\"" +msgstr "Add Email for {0} \"{1}\"" + +#: ./templates/Emails/add.php:54 +#: ./templates/Emails/edit.php:54 +#: ./templates/Faxes/add.php:54 +#: ./templates/Faxes/edit.php:54 +#: ./templates/Groups/add.php:45 +#: ./templates/Groups/edit.php:50 +#: ./templates/Groups/handle_capabilities.php:71 +#: ./templates/MobilePhones/add.php:54 +#: ./templates/MobilePhones/edit.php:54 +#: ./templates/Organisations/add.php:172 +#: ./templates/Organisations/edit.php:86 +#: ./templates/Phones/add.php:53 +#: ./templates/Phones/edit.php:53 +#: ./templates/TelegramChats/add.php:53 +#: ./templates/TelegramChats/edit.php:53 +#: ./templates/Users/add.php:57 +#: ./templates/Users/choose_new_password.php:8 +#: ./templates/Users/edit.php:62 +msgid "Salva" +msgstr "Save" + +#: ./templates/Emails/edit.php:28 +msgid "Modifica Email" +msgstr "Edit Email" + +#: ./templates/Emails/edit.php:40 +msgid "Modifica Email per {0} \"{1}\"" +msgstr "Edit Email for {0} \"{1}\"" + +#: ./templates/Faxes/add.php:40 +msgid "Aggiungi Fax per {0} \"{1}\"" +msgstr "Add Fax for {0} \"{1}\"" + +#: ./templates/Faxes/edit.php:28 +msgid "Modifica Fax" +msgstr "Edit Fax" + +#: ./templates/Faxes/edit.php:40 +msgid "Modifica Fax per {0} \"{1}\"" +msgstr "Edit Fax for {0} \"{1}\"" + +#: ./templates/Groups/add.php:13 +#: ./templates/Groups/edit.php:13 +#: ./templates/Groups/handle_capabilities.php:13 +#: ./templates/Groups/index.php:13 +#: ./templates/Groups/index.php:24 +#: ./templates/Groups/view.php:13 +msgid "Lista dei Profili Utente" +msgstr "User Profiles List" + +#: ./templates/Groups/add.php:18 +#: ./templates/Groups/add.php:31 +msgid "Nuovo Profilo Utente" +msgstr "New User Profile" + +#: ./templates/Groups/edit.php:18 +#: ./templates/Groups/handle_capabilities.php:18 +#: ./templates/Groups/view.php:18 +msgid "Dettaglio Profilo Utente" +msgstr "User Profile Details" + +#: ./templates/Groups/edit.php:23 +#: ./templates/Groups/edit.php:36 +msgid "Modifica Profilo Utente" +msgstr "Edit User Profile" + +#: ./templates/Groups/handle_capabilities.php:35 +msgid "Competenze associate al Profilo Utente \"{0}\"" +msgstr "User Profile \"{0}\" associated capabilities" + +#: ./templates/Groups/handle_capabilities.php:45 +msgid "Gruppo di competenze non visibile e non configurabile dai non SYSADMIN" +msgstr "Capability Groups not visible and not configurable by non SYSADMIN users" + +#: ./templates/Groups/handle_capabilities.php:52 +msgid "Gruppo di competenze \"{0}\"" +msgstr "Capability Group \"{0}\"" + +#: ./templates/Groups/index.php:44 +#: ./templates/Organisations/index.php:52 +#: ./templates/Users/index.php:48 +#: ./templates/plugin/AdminLTE/element/nav-top.php:118 +msgid "Dettaglio" +msgstr "Details" + +#: ./templates/Groups/index.php:46 +#: ./templates/Groups/view.php:44 +msgid "Sei sicuro che vuoi cancellare il profilo \"{0}\" ?" +msgstr "Are you sure you want to delete the user profile \"{0}\" ?" + +#: ./templates/Groups/view.php:30 +msgid "Informazioni Profilo Utente" +msgstr "User Profile Informations" + +#: ./templates/Maps/index.php:25 +msgid "Mappa" +msgstr "Map" + +#: ./templates/Maps/index.php:30 +msgid "Campo esistente appartenente al form ospite" +msgstr "Existing field that belongs to the hosting form" + +#: ./templates/Maps/index.php:37 +msgid "Posizione Evento" +msgstr "Incident location" + +#: ./templates/Maps/index.php:54 +msgid "Collezione di geometrie" +msgstr "Geometry collection" + +#: ./templates/Maps/index.php:65 +#: ./templates/Organisations/add.php:74 +msgid "Longitudine" +msgstr "Longitude" + +#: ./templates/Maps/index.php:76 +#: ./templates/Organisations/add.php:85 +msgid "Latitudine" +msgstr "Latitude" + +#: ./templates/Maps/index.php:87 +#: ./templates/Organisations/add.php:96 +#: ./templates/Organisations/add.php:158 +#: ./templates/Organisations/edit.php:62 +#: ./templates/Organisations/view.php:51 +msgid "Coordinate (Longitudine Latitudine)" +msgstr "Coordinates (Longitude Latitude)" + +#: ./templates/Maps/index.php:98 +#: ./templates/Organisations/add.php:107 +msgid "Cap" +msgstr "ZIP code" + +#: ./templates/Maps/index.php:142 +#: ./templates/Organisations/add.php:151 +msgid "Descrizione luogo" +msgstr "Location description" + +#: ./templates/MobilePhones/add.php:40 +msgid "Aggiungi Cellulare per {0} \"{1}\"" +msgstr "Add Mobile Phone for {0} \"{1}\"" + +#: ./templates/MobilePhones/edit.php:28 +msgid "Modifica Cellulare" +msgstr "Edit Mobile Phone" + +#: ./templates/MobilePhones/edit.php:40 +msgid "Modifica Cellulare per {0} \"{1}\"" +msgstr "Edit Mobile Phone for {0} \"{1}\"" + +#: ./templates/Organisations/add.php:13 +#: ./templates/Organisations/edit.php:13 +#: ./templates/Organisations/index.php:13 +#: ./templates/Organisations/view.php:13 +msgid "Lista Organizzazioni" +msgstr "Organisations List" + +#: ./templates/Organisations/add.php:18 +#: ./templates/Organisations/add.php:30 +msgid "Nuova Organizzazione" +msgstr "New Organisation" + +#: ./templates/Organisations/add.php:39 +#: ./templates/Organisations/edit.php:43 +#: ./templates/Organisations/view.php:38 +msgid "Tipo organizzazione" +msgstr "Organisation type" + +#: ./templates/Organisations/add.php:46 +#: ./templates/Organisations/edit.php:50 +#: ./templates/Organisations/view.php:45 +msgid "Posizione Organizzazione" +msgstr "Organisation Location" + +#: ./templates/Organisations/edit.php:18 +#: ./templates/Organisations/view.php:18 +#: ./templates/Organisations/view.php:29 +msgid "Dettaglio Organizzazione" +msgstr "Organisation Details" + +#: ./templates/Organisations/edit.php:23 +#: ./templates/Organisations/edit.php:34 +msgid "Modifica Organizzazione" +msgstr "Edit Organisation" + +#: ./templates/Organisations/index.php:23 +msgid "Lista delle {0} Organizzazioni" +msgstr "List of {0} Organisations" + +#: ./templates/Organisations/index.php:23 +#: ./templates/Users/index.php:23 +msgid "{0} su {1}" +msgstr "{0} out of {1}" + +#: ./templates/Organisations/index.php:54 +#: ./templates/Organisations/view.php:71 +msgid "Sei sicuro che vuoi cancellare l'organizzazione \"{0}\" ?" +msgstr "Are you sure you want to delete the organisation \"{0}\" ?" + +#: ./templates/Phones/add.php:40 +msgid "Aggiungi Telefono per {0} \"{1}\"" +msgstr "Add Phone for {0} \"{1}\"" + +#: ./templates/Phones/edit.php:28 +msgid "Modifica Telefono" +msgstr "Edit Phone" + +#: ./templates/Phones/edit.php:40 +msgid "Modifica Telefono per {0} \"{1}\"" +msgstr "Edit Phone for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:40 +msgid "Aggiungi Chat Telegram per {0} \"{1}\"" +msgstr "Add Telegram Chat for {0} \"{1}\"" + +#: ./templates/TelegramChats/add.php:47 +#: ./templates/TelegramChats/edit.php:47 +msgid "Chat Telegram ID" +msgstr "Telegram Chat ID" + +#: ./templates/TelegramChats/edit.php:28 +msgid "Modifica Chat Telegram" +msgstr "Edit Telegram Chat" + +#: ./templates/TelegramChats/edit.php:40 +msgid "Modifica Chat Telegram per {0} \"{1}\"" +msgstr "Edit Telegram Chat for {0} \"{1}\"" + +#: ./templates/Users/add.php:13 +#: ./templates/Users/edit.php:13 +#: ./templates/Users/index.php:13 +#: ./templates/Users/view.php:13 +msgid "Lista Utenti" +msgstr "Users List" + +#: ./templates/Users/add.php:18 +#: ./templates/Users/add.php:31 +msgid "Nuovo Utente" +msgstr "New User" + +#: ./templates/Users/add.php:38 +#: ./templates/Users/edit.php:43 +#: ./templates/Users/view.php:41 +msgid "Nome utente" +msgstr "Username" + +#: ./templates/Users/add.php:39 +#: ./templates/Users/edit.php:44 +msgid "Password" +msgstr "Password" + +#: ./templates/Users/add.php:42 +#: ./templates/Users/edit.php:47 +#: ./templates/Users/view.php:47 +msgid "Codice Fiscale" +msgstr "Tax ID code" + +#: ./templates/Users/add.php:43 +#: ./templates/Users/edit.php:48 +#: ./templates/Users/view.php:49 +msgid "Data di nascita" +msgstr "Date of birth" + +#: ./templates/Users/add.php:44 +#: ./templates/Users/edit.php:49 +#: ./templates/Users/view.php:51 +msgid "Luogo di nascita" +msgstr "Birth place" + +#: ./templates/Users/add.php:45 +#: ./templates/Users/edit.php:50 +#: ./templates/Users/view.php:53 +msgid "Sesso" +msgstr "Gender" + +#: ./templates/Users/add.php:47 +#: ./templates/Users/edit.php:52 +#: ./templates/Users/view.php:57 +msgid "Città" +msgstr "City" + +#: ./templates/Users/add.php:49 +#: ./templates/Users/edit.php:54 +#: ./templates/Users/view.php:61 +msgid "Lingua preferita" +msgstr "Favourite language" + +#: ./templates/Users/add.php:51 +#: ./templates/Users/edit.php:56 +msgid "Foto del profilo (solo jpeg di dimensioni 160x160!)" +msgstr "Photo (160x160 sized jpeg only!)" + +#: ./templates/Users/choose_new_password.php:4 +msgid "Imposta una nuova password" +msgstr "Set a new password" + +#: ./templates/Users/choose_new_password.php:5 +msgid "Digita la nuova password" +msgstr "Enter the new password" + +#: ./templates/Users/choose_new_password.php:6 +msgid "Ridigita la nuova password" +msgstr "Retype the previous entered password" + +#: ./templates/Users/edit.php:18 +#: ./templates/Users/view.php:18 +msgid "Dettaglio Utente" +msgstr "User Details" + +#: ./templates/Users/edit.php:23 +#: ./templates/Users/edit.php:36 +msgid "Modifica Utente" +msgstr "Edit User" + +#: ./templates/Users/index.php:23 +msgid "Lista dei {0} Utenti" +msgstr "List of {0} Users" + +#: ./templates/Users/index.php:50 +#: ./templates/Users/view.php:72 +msgid "Sei sicuro che vuoi cancellare l'utente \"{0}\" ?" +msgstr "Are you sure you wanto to delete the user \"{0}\" ?" + +#: ./templates/Users/login.php:4 +msgid "Accedi" +msgstr "Gain access" + +#: ./templates/Users/login.php:8 +msgid "Login" +msgstr "Login" + +#: ./templates/Users/password_recovery.php:4 +msgid "Inserisci un indirizzo email associato alla tua utenza" +msgstr "Insert an email that is currently associated with your account" + +#: ./templates/Users/password_recovery.php:7 +msgid "Richiedi reset password" +msgstr "Request password reset" + +#: ./templates/Users/view.php:30 +msgid "Informazioni Utente" +msgstr "User Informations" + +#: ./templates/Users/view.php:34 +msgid "Elimina foto" +msgstr "Delete photo" + +#: ./templates/Users/view.php:34 +msgid "Sei sicuro che vuoi eliminare la foto ?" +msgstr "Are you sure you want to delete the photo ?" + +#: ./templates/Users/view.php:62 +msgid "Non specificata" +msgstr "Not specified" + +#: ./templates/Users/view.php:67 +msgid "Recapiti:" +msgstr "Contacts" + +#: ./templates/cell/FilterInput/display.php:9 +#: ./templates/element/attachments.php:127 +msgid "Rimuovi" +msgstr "Remove" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:113 +msgid "Filtri attivi" +msgstr "Filters applied" + +#: ./templates/cell/Filters/display.php:3 +#: ./templates/cell/Filters/display.php:116 +msgid "Filtri disattivati" +msgstr "No Filters applied" + +#: ./templates/cell/Filters/display.php:15 +msgid "Aggiungi un filtro" +msgstr "Add a filter" + +#: ./templates/cell/Filters/display.php:34 +#: ./templates/cell/Filters/display.php:55 +msgid "Applica" +msgstr "Apply" + +#: ./templates/cell/Filters/display.php:39 +msgid "Reset" +msgstr "Reset" + +#: ./templates/cell/Filters/display.php:56 +msgid "Annulla" +msgstr "Cancel" + +#: ./templates/cell/Filters/display.php:58 +msgid "A" +msgstr "TO" + +#: ./templates/cell/Filters/display.php:59 +msgid "Dal Al" +msgstr "From To" + +#: ./templates/cell/Filters/display.php:60 +#: ./templates/cell/Filters/display.php:87 +msgid "Oggi" +msgstr "Today" + +#: ./templates/cell/Filters/display.php:62 +msgid "Dom" +msgstr "Sun" + +#: ./templates/cell/Filters/display.php:63 +msgid "Lun" +msgstr "Mon" + +#: ./templates/cell/Filters/display.php:64 +msgid "Mar" +msgstr "Tue" + +#: ./templates/cell/Filters/display.php:65 +msgid "Mer" +msgstr "Wed" + +#: ./templates/cell/Filters/display.php:66 +msgid "Gio" +msgstr "Thu" + +#: ./templates/cell/Filters/display.php:67 +msgid "Ven" +msgstr "Fri" + +#: ./templates/cell/Filters/display.php:68 +msgid "Sab" +msgstr "Sat" + +#: ./templates/cell/Filters/display.php:71 +msgid "Gennaio" +msgstr "January" + +#: ./templates/cell/Filters/display.php:72 +msgid "Febbraio" +msgstr "February" + +#: ./templates/cell/Filters/display.php:73 +msgid "Marzo" +msgstr "March" + +#: ./templates/cell/Filters/display.php:74 +msgid "Aprile" +msgstr "April" + +#: ./templates/cell/Filters/display.php:75 +msgid "Maggio" +msgstr "May" + +#: ./templates/cell/Filters/display.php:76 +msgid "Giugno" +msgstr "June" + +#: ./templates/cell/Filters/display.php:77 +msgid "Luglio" +msgstr "July" + +#: ./templates/cell/Filters/display.php:78 +msgid "Agosto" +msgstr "August" + +#: ./templates/cell/Filters/display.php:79 +msgid "Settembre" +msgstr "September" + +#: ./templates/cell/Filters/display.php:80 +msgid "Ottobre" +msgstr "October" + +#: ./templates/cell/Filters/display.php:81 +msgid "Novembre" +msgstr "November" + +#: ./templates/cell/Filters/display.php:82 +msgid "Dicembre" +msgstr "December" + +#: ./templates/cell/Filters/display.php:88 +msgid "Ieri" +msgstr "Yesterday" + +#: ./templates/cell/Filters/display.php:89 +msgid "Questa settimana" +msgstr "This week" + +#: ./templates/cell/Filters/display.php:90 +msgid "Questo mese" +msgstr "This month" + +#: ./templates/cell/Filters/display.php:91 +msgid "Lo scorso mese" +msgstr "Last month" + +#: ./templates/cell/Filters/display.php:92 +msgid "Ultimi 7 giorni" +msgstr "Last 7 days" + +#: ./templates/cell/Filters/display.php:93 +msgid "Ultimi 15 giorni" +msgstr "Last 15 days" + +#: ./templates/cell/Filters/display.php:94 +msgid "Ultimi 30 giorni" +msgstr "Last 30 days" + +#: ./templates/cell/Filters/display.php:131 +msgid "Errore durante il recupero del filtro selezionato. Riprovare di nuovo" +msgstr "Error trying to retrieve the selected filter. Pleas try again" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:118 +#: ./templates/element/Map.php:122 +msgid "OpenStreetMap ONLINE" +msgstr "OpenStreetMap ONLINE" + +#: ./templates/element/Map.php:107 +#: ./templates/element/Map.php:127 +#: ./templates/element/Map.php:131 +msgid "OpenStreetMap OFFLINE" +msgstr "OpenStreetMap OFFLINE" + +#: ./templates/element/Map.php:312 +#: ./templates/element/Map.php:541 +msgid "Indirizzo non trovato o fuori dall'area di competenza" +msgstr "Address not found or out of the platform configured bounding box" + +#: ./templates/element/Map.php:530 +msgid "Punto alle coordinate (EPSG:4326) Latitudine:" +msgstr "Point of coordinates (EPSG:4326) Latitude:" + +#: ./templates/element/Map.php:530 +msgid "Longitudine:" +msgstr "Longitude:" + +#: ./templates/element/MapCore/MapPrimitives.php:10 +msgid "Scegli un risultato:" +msgstr "Pick a result" + +#: ./templates/element/MapCore/MapPrimitives.php:30 +msgid "Inserisci un indirizzo o le coordinate (in formato EPSG:4326)" +msgstr "Insert an address or coordinates (EPSG:4326)" + +#: ./templates/element/MapCore/MapPrimitives.php:31 +msgid "Cerca un indirizzo" +msgstr "Look up for an address" + +#: ./templates/element/MapCore/MapPrimitives.php:36 +msgid "Inserisci un punto in mappa" +msgstr "Insert a point on map" + +#: ./templates/element/MapCore/MapPrimitives.php:41 +msgid "Inserisci un poligono in mappa" +msgstr "Draw a polygon on map" + +#: ./templates/element/MapCore/MapPrimitives.php:46 +msgid "Inserisci un cerchio in mappa" +msgstr "Draw a circle on map" + +#: ./templates/element/MapCore/MapPrimitives.php:51 +msgid "Cancella una geometria" +msgstr "Delete a geometry" + +#: ./templates/element/attachmentPreview.php:16 +msgid "Il tuo browser non supporta HTML5 video tag. Prova ad aggiornare il tuo browser." +msgstr "Your browser doesn't seem to support HTML5 video tag. Please try and update your browser to a more recent version." + +#: ./templates/element/attachmentPreview.php:35 +msgid "Anteprima non disponibile" +msgstr "Preview not available" + +#: ./templates/element/attachments.php:30 +msgid "di tipo: \"{0}\"" +msgstr "of type \"{0}\"" + +#: ./templates/element/attachments.php:39 +msgid "Mostra allegati correlati" +msgstr "Show also linked attachments" + +#: ./templates/element/attachments.php:48 +msgid "Allega un file " +msgstr "Attach a file" + +#: ./templates/element/attachments.php:48 +msgid "Allega files " +msgstr "Attach files" + +#: ./templates/element/attachments.php:54 +msgid "Allega file pubblico " +msgstr "Attach public file" + +#: ./templates/element/attachments.php:54 +msgid "Allega un file privato " +msgstr "Attach a private file" + +#: ./templates/element/attachments.php:54 +msgid "Allega files privati " +msgstr "Attach private files " + +#: ./templates/element/attachments.php:58 +msgid "Allega files..." +msgstr "Attach files..." + +#: ./templates/element/attachments.php:65 +msgid "Allega files {1} {0}" +msgstr "Attach files {1} {0}" + +#: ./templates/element/attachments.php:118 +msgid "latitudine" +msgstr "latitude" + +#: ./templates/element/attachments.php:119 +msgid "longitudine" +msgstr "longitude" + +#: ./templates/layout/error.php:38 +msgid "Back" +msgstr "Back" + +#: ./templates/plugin/AdminLTE/element/aside-control-sidebar.php:4 +msgid "Notifiche" +msgstr "Notifications" + +#: ./templates/plugin/AdminLTE/element/footer.php:6 +msgid "Versione" +msgstr "Version" + +#: ./templates/plugin/AdminLTE/element/footer.php:9 +msgid "Tutti i diritti riservati" +msgstr "All rights reserved" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:67 +msgid "Nuove notifiche: {0}" +msgstr "New notifications: {0}" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:91 +msgid "Segna tutte le notifiche come lette" +msgstr "Mark all new notifications as read" + +#: ./templates/plugin/AdminLTE/element/nav-top.php:121 +msgid "Esci" +msgstr "Logout" + diff --git a/idrocap_wa/resources/locales/it/cake.po b/idrocap_wa/resources/locales/it/cake.po new file mode 100644 index 0000000..799b01c --- /dev/null +++ b/idrocap_wa/resources/locales/it/cake.po @@ -0,0 +1,279 @@ +# LANGUAGE translation of CakePHP Application +# Copyright YEAR NAME +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: CakePHP 4.4.5\n" +"POT-Creation-Date: 2023-02-28 09:27+0000\n" +"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n" +"Last-Translator: NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: ./templates/Error/error400.php:39 +#: ./templates/Error/error500.php:43 +msgid "Error" +msgstr "Errore" + +#: ./templates/Error/error400.php:40 +msgid "The requested address {0} was not found on this server." +msgstr "L'indirizzo richiesto {0} non è stato trovato su questo server." + +#: ./templates/Error/error500.php:41 +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:361 +msgid "An Internal Error Has Occurred." +msgstr "Errore interno." + +#: ./vendor/cakephp/cakephp/src/Controller/Component/AuthComponent.php:462 +msgid "You are not authorized to access that location." +msgstr "Non sei autorizzato ad accedere a quella risorsa." + +#: ./vendor/cakephp/cakephp/src/Error/Renderer/WebExceptionRenderer.php:359 +msgid "Not Found" +msgstr "Non Trovato" + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:390 +msgid "Missing or incorrect CSRF cookie type." +msgstr "tipo di CSRF cookie mancante o incorretto." + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:394 +msgid "Missing or invalid CSRF cookie." +msgstr "CSRF cookie mancante o incorretto." + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/CsrfProtectionMiddleware.php:417 +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:265 +msgid "CSRF token from either the request body or request headers did not match or is missing." +msgstr "Il CSRF token è mancante o quello presente nel body non corrisponde." + +#: ./vendor/cakephp/cakephp/src/Http/Middleware/SessionCsrfProtectionMiddleware.php:247 +msgid "Missing or incorrect CSRF session key" +msgstr "Chiave di sessione CSRF incorretta o mancante" + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1489 +msgid "The requested file contains `..` and will not be read." +msgstr "Il file richiesto contiene `..` e quindi non verrà letto." + +#: ./vendor/cakephp/cakephp/src/Http/Response.php:1497 +msgid "The requested file was not found" +msgstr "Il file richiesto non è stato trovato" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:116 +msgid "{0,number,#,###.##} KB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:118 +msgid "{0,number,#,###.##} MB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:120 +msgid "{0,number,#,###.##} GB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:122 +msgid "{0,number,#,###.##} TB" +msgstr "" + +#: ./vendor/cakephp/cakephp/src/I18n/Number.php:114 +msgid "{0,number,integer} Byte" +msgid_plural "{0,number,integer} Bytes" +msgstr[0] "" +msgstr[1] "" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} from now" +msgstr "{0} da adesso" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:86 +msgid "{0} ago" +msgstr "{0} fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} after" +msgstr "{0} dopo" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:89 +msgid "{0} before" +msgstr "{0} prima" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:120 +msgid "just now" +msgstr "in questo momento" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:157 +msgid "about a second ago" +msgstr "circa un secondo fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:158 +msgid "about a minute ago" +msgstr "circa un minuto fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:159 +msgid "about an hour ago" +msgstr "circa un'ora fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:160 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:370 +msgid "about a day ago" +msgstr "circa un giorno fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:161 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:371 +msgid "about a week ago" +msgstr "circa una settimana fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:162 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:372 +msgid "about a month ago" +msgstr "circa un mese fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:163 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:373 +msgid "about a year ago" +msgstr "circa un anno fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:174 +msgid "in about a second" +msgstr "fra circa un secondo" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:175 +msgid "in about a minute" +msgstr "fra circa un minuto" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:176 +msgid "in about an hour" +msgstr "fra circa un'ora" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:177 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:384 +msgid "in about a day" +msgstr "fra circa un giorno" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:178 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:385 +msgid "in about a week" +msgstr "tra circa una settimana" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:179 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:386 +msgid "in about a month" +msgstr "tra circa un mese" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:180 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:387 +msgid "in about a year" +msgstr "tra circa un anno" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:342 +msgid "today" +msgstr "oggi" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:409 +msgid "%s ago" +msgstr "%s fa" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:410 +msgid "on %s" +msgstr "%s" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:53 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:132 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:354 +msgid "{0} year" +msgid_plural "{0} years" +msgstr[0] "{0} anno" +msgstr[1] "{0} anni" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:57 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:135 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:357 +msgid "{0} month" +msgid_plural "{0} months" +msgstr[0] "{0} mese" +msgstr[1] "{0} mesi" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:63 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:138 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:360 +msgid "{0} week" +msgid_plural "{0} weeks" +msgstr[0] "{0} settimana" +msgstr[1] "{0} settimane" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:65 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:141 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:363 +msgid "{0} day" +msgid_plural "{0} days" +msgstr[0] "{0} giorno" +msgstr[1] "{0} giorni" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:70 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:144 +msgid "{0} hour" +msgid_plural "{0} hours" +msgstr[0] "{0} ora" +msgstr[1] "{0} ore" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:74 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:147 +msgid "{0} minute" +msgid_plural "{0} minutes" +msgstr[0] "{0} minuto" +msgstr[1] "{0} minuti" + +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:78 +#: ./vendor/cakephp/cakephp/src/I18n/RelativeTimeFormatter.php:150 +msgid "{0} second" +msgid_plural "{0} seconds" +msgstr[0] "{0} secondo" +msgstr[1] "{0} secondi" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:63 +msgid "This value is already in use" +msgstr "Questo valore è già in uso" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:110 +msgid "This value does not exist" +msgstr "Questo valore non esiste" + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:232 +msgid "Cannot modify row: a constraint for the `{0}` association fails." +msgstr "Impossibile modificare: il vincolo per l'associazione `{0}` fallisce." + +#: ./vendor/cakephp/cakephp/src/ORM/RulesChecker.php:270 +msgid "The count does not match {0}{1}" +msgstr "Il conteggio non corrisponde {0}{1}" + +#: ./vendor/cakephp/cakephp/src/Utility/Text.php:923 +msgid "and" +msgstr "e" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2539 +msgid "This field is required" +msgstr "Questo campo è richiesto" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2559 +#: ./vendor/cakephp/cakephp/src/View/Form/ArrayContext.php:249 +msgid "This field cannot be left empty" +msgstr "Questo campo non può essere lasciato vuoto" + +#: ./vendor/cakephp/cakephp/src/Validation/Validator.php:2711 +msgid "The provided value is invalid" +msgstr "Il valore fornito non è valido" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:979 +msgid "Edit {0}" +msgstr "Modifica {0}" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:981 +msgid "New {0}" +msgstr "Nuovo {0}" + +#: ./vendor/cakephp/cakephp/src/View/Helper/FormHelper.php:1917 +msgid "Submit" +msgstr "Salva" + diff --git a/idrocap_wa/src/Application.php b/idrocap_wa/src/Application.php new file mode 100644 index 0000000..6cdeb82 --- /dev/null +++ b/idrocap_wa/src/Application.php @@ -0,0 +1,268 @@ +addPlugin('Authentication'); + + if (PHP_SAPI === 'cli') { + $this->bootstrapCli(); + } else { + FactoryLocator::add( + 'Table', + (new TableLocator())->allowFallbackClass(false) + ); + } + + /* + * Only try to load DebugKit in development mode + * Debug Kit should not be installed on a production system + */ + if (Configure::read('debug')) { + Configure::write('DebugKit.safeTld', ['it']); + } + + // Load more plugins here + $this->addPlugin('Muffin/Trash'); + $this->addPlugin('CsvView'); + $this->addPlugin('CakeSentry'); + } + + + /** + * Returns a service provider instance. + * + * @param \Psr\Http\Message\ServerRequestInterface $request Request + * @return \Authentication\AuthenticationServiceInterface + */ + public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface + { + $service = new AuthenticationService(); + + $fields = [ + AbstractIdentifier::CREDENTIAL_USERNAME => 'username', + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password' + ]; + + if (strpos($request->getPath(), '/api/') !== 0) { + // NORMAL REQUESTS + + // se si tratta della request "/notifications/index" non eseguire il redirect e restituisci 401! + if ($request->getPath() !== '/notifications/index') { + // Define where users should be redirected to when they are not authenticated + $service->setConfig([ + 'unauthenticatedRedirect' => Router::url([ + 'prefix' => false, + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + 'queryParam' => 'redirect', + ]); + } + + // Load the authenticators. Session should be first. + $service->loadAuthenticator('Authentication.Session'); + + $service->loadAuthenticator('Authentication.Cookie', [ + 'fields' => $fields, + 'loginUrl' => Router::url([ + 'prefix' => false, + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + ]); + + $service->loadAuthenticator('Authentication.Form', [ + 'fields' => $fields, + 'loginUrl' => Router::url([ + 'prefix' => false, + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + ]); + + // Load identifiers + $service->loadIdentifier('JixelPassword', [ + 'fields' => $fields, + ]); + } else { + // API REQUESTS + + if (strpos($request->getPath(), '/api/users/login') === 0) { + // API REQUEST LOGIN + + // Load the authenticators. + $service->loadAuthenticator('Authentication.Form', [ + 'fields' => $fields, + 'loginUrl' => Router::url([ + 'prefix' => 'Api', + 'plugin' => null, + 'controller' => 'Users', + 'action' => 'login', + ]), + ]); + + // Load identifiers + $service->loadIdentifier('Authentication.Password', compact('fields')); + } else { + // Load identifiers + $service->loadIdentifier('Authentication.JwtSubject', [ + 'tokenField' => 'username', + ]); + + // Load the authenticators + $service->loadAuthenticator('Authentication.Jwt', [ + 'secretKey' => file_get_contents(Configure::read('App.jwt.keys.public')), + 'algorithm' => Configure::read('App.jwt.algorithm'), + 'returnPayload' => false + ]); + } + } + return $service; + } + + /** + * Setup the middleware queue your application will use. + * + * @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup. + * @return \Cake\Http\MiddlewareQueue The updated middleware queue. + */ + public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue + { + $middlewareQueue + ->add(new LocaleSelectorMiddleware(['it', 'en'])) + + // Catch any exceptions in the lower layers, + // and make an error page/response + ->add(new ErrorHandlerMiddleware(Configure::read('Error'))) + + // Handle plugin/theme assets like CakePHP normally does. + ->add(new AssetMiddleware([ + 'cacheTime' => Configure::read('Asset.cacheTime'), + ])) + + // Add routing middleware. + // If you have a large number of routes connected, turning on routes + // caching in production could improve performance. For that when + // creating the middleware instance specify the cache config name by + // using it's second constructor argument: + // `new RoutingMiddleware($this, '_cake_routes_')` + ->add(new RoutingMiddleware($this)) + + // Parse various types of encoded request bodies so that they are + // available as array through $request->getData() + // https://book.cakephp.org/4/en/controllers/middleware.html#body-parser-middleware + ->add(new BodyParserMiddleware()); + + // Cross Site Request Forgery (CSRF) Protection Middleware + // https://book.cakephp.org/4/en/security/csrf.html#cross-site-request-forgery-csrf-middleware + $csrf = new CsrfProtectionMiddleware(); + + // Token check will be skipped when callback returns `true`. + $csrf->skipCheckCallback(function ($request) { + // Skip token check for API URLs. + if ($request->getParam('prefix') === 'Api') { + return true; + } + // Skip token check for ajax calls. + if ($request->is('ajax')) { + return true; + } + }); + + // Ensure routing middleware is added to the queue before CSRF protection middleware. + $middlewareQueue->add($csrf) + // encryption/decryption management of listed cookies: + ->add(new EncryptedCookieMiddleware(['CookieAuth'], Configure::read('Security.CookieEncryptionKey'))) + + // Add the AuthenticationMiddleware. It should be + // after routing and body parser. + ->add(new AuthenticationMiddleware($this)) + ->add(new UserTimezoneDatetimeRequestDataMiddleware()); + + return $middlewareQueue; + } + + /** + * Register application container services. + * + * @param \Cake\Core\ContainerInterface $container The Container to update. + * @return void + * @link https://book.cakephp.org/4/en/development/dependency-injection.html#dependency-injection + */ + public function services(ContainerInterface $container): void + { + } + + /** + * Bootstrapping for CLI application. + * + * That is when running commands. + * + * @return void + */ + protected function bootstrapCli(): void + { + $this->addOptionalPlugin('Cake/Repl'); + + // Load more plugins here + } +} diff --git a/idrocap_wa/src/Command/AddCadastralCodeToUsesCommand.php b/idrocap_wa/src/Command/AddCadastralCodeToUsesCommand.php new file mode 100644 index 0000000..3893135 --- /dev/null +++ b/idrocap_wa/src/Command/AddCadastralCodeToUsesCommand.php @@ -0,0 +1,95 @@ +addArgument('chunk_size', [ + 'help' => 'the amount of records to process in chunk (at least 10 which is the default value)', + 'required' => false, + ]); + return $parser; + } + + /* + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $chunkSize = (int)($args->getArgument('chunk_size') ?? 10); + if ($chunkSize < 10) $io->abort("Please specify a chunk size of at least 10!"); + $page = 1; + $total = 0; + $io->info("AddCadastralCodeToUsesCommand started!"); + $io->info("Chunk size is: $chunkSize"); + + do { + $intendedUses = $this->fetchTable('WaterDrawingIntendedUses')->find() + ->where([ + // recuperiamo solo le entries di tipo uso IRRIGUO che non hanno il codice BELFIORE: + "WaterDrawingIntendedUses.water_drawing_intended_use_type_id" => 1, + "WaterDrawingIntendedUses.cadastral_code IS NULL", + + // devono però avere foglio e particella validi: + "WaterDrawingIntendedUses.cadastral_sheet IS NOT NULL", + "WaterDrawingIntendedUses.cadastral_parcel IS NOT NULL", + "WaterDrawingIntendedUses.cadastral_sheet <> ''", + "WaterDrawingIntendedUses.cadastral_parcel <> ''", + ]) + ->limit($chunkSize) + ->page($page) + ->all(); + + foreach($intendedUses as $intendedUse){ + $io->info("Processing WaterDrawingIntendedUse with ID: $intendedUse->id"); + // recuperiamo il codice BELFIORE dal primo delle derivazioni connesse alla pratica (se ve ne sono....): + $derivation = $this->fetchTable('WaterDrawingDerivations')->find()->where([ + 'WaterDrawingDerivations.water_drawing_paperwork_id' => $intendedUse->water_drawing_paperwork_id + ])->first(); + if (!isset($derivation->cadastral_code)) { + $io->warning('WARNING: related water_drawing_paperwork has no suitable water_drawing_derivations to get cadastral_code from -> SKIPPED!'); + continue; + } + $intendedUse->cadastral_code = $derivation->cadastral_code; + $intendedUse->vegetation_match_status = CadastralUtils::isParcelWithinVegetationArea(strtolower($intendedUse->cadastral_code), $intendedUse->cadastral_sheet, $intendedUse->cadastral_parcel) ? 1 : -1; + + if(!$this->fetchTable('WaterDrawingIntendedUses')->save($intendedUse, ['skipResetIsMismatch' => true])){ + $io->warning('WARNING: Error during save!'); + $io->warning(json_encode($intendedUse->getErrors())); + } + } + + $count = $intendedUses->count(); + $total += $count; + if ($count) $io->success("processed $count items for page $page"); + $page++; + } while ($count === $chunkSize); + + $io->success("total processed $total items!"); + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/AddDerivationCoordinatesCommand.php b/idrocap_wa/src/Command/AddDerivationCoordinatesCommand.php new file mode 100644 index 0000000..5695e31 --- /dev/null +++ b/idrocap_wa/src/Command/AddDerivationCoordinatesCommand.php @@ -0,0 +1,44 @@ +fetchTable('WaterDrawingDerivations')->find()->where([ + 'WaterDrawingDerivations.latitude' => '', + 'WaterDrawingDerivations.longitude' => '', + 'WaterDrawingDerivations.cadastral_code IS NOT NULL', + 'WaterDrawingDerivations.cadastral_sheet IS NOT NULL', + 'WaterDrawingDerivations.cadastral_parcel IS NOT NULL', + ])->toArray(); + foreach($derivations as $derivation){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($derivation->cadastral_code), (string) $derivation->cadastral_sheet, (string) $derivation->cadastral_parcel); + if(isset($coordinates)){ + $derivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($derivation, [ + 'latitude' => $coordinates->latitude, + 'longitude' => $coordinates->longitude, + 'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":['. $coordinates->longitude .','. $coordinates->latitude .']},"properties":null}]}' + ]); + if(!$this->fetchTable('WaterDrawingDerivations')->save($derivation)){ + $io->out(__('Errore durante il salvataggio.')); + $io->out(json_encode($derivation->getErrors())); + } + } + } + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand.php b/idrocap_wa/src/Command/CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand.php new file mode 100644 index 0000000..44a04b0 --- /dev/null +++ b/idrocap_wa/src/Command/CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand.php @@ -0,0 +1,57 @@ +info("\n\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: START!!!"); + + // prima recupero, per ogni pratica, le water_drawing_antimafia_certification_requests con ID massimo + // questo mi assicura di prendere in considerazione l'ultima richiesta fatta: + $latest_water_drawing_antimafia_certification_request_ids = $this->fetchTable('WaterDrawingAntimafiaCertificationRequests') + ->find() + ->select(['max_id' => 'MAX(WaterDrawingAntimafiaCertificationRequests.id)']) + ->group('water_drawing_paperwork_id'); + + // quindi recuoero le pratiche per cui risulti l'ultima richiesta AM scaduta (termine dei 30gg) + // che sia in "stato richiesta" in modo da poter notificare i relativi utenti DRAR: + $to_be_notified_water_drawing_paperworks = $this->fetchTable('WaterDrawingPaperworks') + ->find() + ->matching('WaterDrawingAntimafiaCertificationRequests') + ->where([ + 'WaterDrawingAntimafiaCertificationRequests.id IN' => $latest_water_drawing_antimafia_certification_request_ids, + 'WaterDrawingAntimafiaCertificationRequests.water_drawing_antimafia_certification_request_status_id' => 2, + 'WaterDrawingAntimafiaCertificationRequests.created <= NOW() - INTERVAL 30 DAY' + ]) + ->toArray(); + + foreach($to_be_notified_water_drawing_paperworks as $waterDrawingPaperwork) { + // DISPATCH NOTIFICHE: + $io->info("\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: richiesta AM scaduta per pratica con ID: " . $waterDrawingPaperwork->id); + if (isset($waterDrawingPaperwork->drar_user_id)) { + $io->success("CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: Invio notifica a utente DRAR con ID: " . $waterDrawingPaperwork->drar_user_id); + // invio notifica a utente DRAR che aveva richiesto la certificazione antimafia perchè la richiesta è scaduta: + NotificationsHandler::dispatch($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user_antimafia_request_expired', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + $io->error("CheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: LA PRATICA NON HA UTENTI DRAR ASSEGNATI !!!!!"); + } + } + + $io->info("\n\nCheckExpiredWaterDrawingAntimafiaCertificateRequestsCommand: END!!!"); + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/CopyTranslationsCommand.php b/idrocap_wa/src/Command/CopyTranslationsCommand.php new file mode 100644 index 0000000..8363d6e --- /dev/null +++ b/idrocap_wa/src/Command/CopyTranslationsCommand.php @@ -0,0 +1,144 @@ +addArgument('template_filename', [ + 'help' => '.POT Template file (with full or relative path)', + 'required' => true, + ]) + ->addArgument('input_filename', [ + 'help' => '.PO Input file (with full or relative path)', + 'required' => true, + ]) + ->addArgument('output_filename', [ + 'help' => 'Output PO file (with full or relative path)', + 'required' => true, + ]); + return $parser; + } + + /** + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $template_filename = $args->getArgument('template_filename'); + $input_filename = $args->getArgument('input_filename'); + $output_filename = $args->getArgument('output_filename'); + + $io->info("\n\ntemplate file path: $template_filename, input file path: $input_filename, output file path: $output_filename\n\n"); + + if (!file_exists($template_filename)) $io->abort("\n\n\nError: File \"$template_filename\" doesn't exists!"); + if (!file_exists($input_filename)) $io->abort("\n\n\nError: File \"$input_filename\" doesn't exists!"); + + // lettura pot e retrieving identifiers: + $template_filename_handle = fopen($template_filename, "r"); + if ($template_filename_handle) { + $pot_row_count = 0; + $io->info("\n\n\nFetching translation identifiers from template file \"$template_filename\":\n"); + while (($buffer = fgets($template_filename_handle, 4096)) !== false) { + if (substr($buffer, 0, 5) !== "msgid") continue; + $text = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; + if ($text === "") continue; + ++$pot_row_count; + $io->info("msgid at row $pot_row_count: $text"); + $this->pot_identifiers[$text] = ""; + } + if (!feof($template_filename_handle)) { + $io->abort("\n\n\nError: unexpected fgets() fail"); + } + fclose($template_filename_handle); + $io->success("\n\nNumber of identifiers successfully fetched from template file \"$template_filename\": $pot_row_count\n\n"); + } else { + $io->abort("\n\n\nError: Unable to Open File \"$template_filename\"!"); + } + + // lettura input file e retrieving translations (x gli identifiers che matchano): + $input_filename_handle = fopen($input_filename, "r"); + if ($input_filename_handle) { + $count = 0; + $last_identifier = null; + $io->info("\n\n\nRetrieving translations from input file \"$input_filename\":\n"); + while (($buffer = fgets($input_filename_handle, 4096)) !== false) { + if (substr($buffer, 0, 6) === "msgid ") { + $last_identifier = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; + if ($last_identifier === "" || !isset($this->pot_identifiers[$last_identifier])) $last_identifier = null; + } + if (substr($buffer, 0, 6) === "msgstr" && isset($last_identifier)) { + $this->pot_identifiers[$last_identifier] = explode("\"\n", explode("msgstr \"", $buffer)[1])[0]; + if (!empty($this->pot_identifiers[$last_identifier])) ++$count; + $io->info("Retrieved translations so far: $count - Parsing: \"$last_identifier\" = \"" . $this->pot_identifiers[$last_identifier] . "\""); + } + } + if (!feof($input_filename_handle)) { + $io->abort("\n\n\nError: unexpected fgets() fail"); + } + fclose($input_filename_handle); + $io->success("\n\nSuccessfully retrieved $count translations from input po file \"$input_filename\"!\n\n"); + } else { + $io->abort("\n\n\nError: Unable to Open File \"$input_filename\"!"); + } + + // creazione file .PO di output partendo da struttura del .POT fornito e arricchito con le traduzioni recuperate dal file di input + $template_filename_handle = fopen($template_filename, "r"); + $output_filename_handle = fopen($output_filename, 'w'); + + if ($template_filename_handle) { + $count = 0; + $last_identifier = null; + $io->info("\n\n\nCreating new translation file \"$output_filename\":\n"); + while (($buffer = fgets($template_filename_handle, 4096)) !== false) { + if (substr($buffer, 0, 5) === "msgid") { + $last_identifier = explode("\"\n", explode("msgid \"", $buffer)[1])[0]; + if ($last_identifier !== "" && !empty($this->pot_identifiers[$last_identifier])) { + ++$count; + } else { + $last_identifier = null; + } + } + if (substr($buffer, 0, 6) === "msgstr" && isset($last_identifier)) { + $io->info("Adding translation number: $count for identifier: \"$last_identifier\"" . " with translation: \"" . $this->pot_identifiers[$last_identifier] . "\""); + $buffer = "msgstr \"" . $this->pot_identifiers[$last_identifier] . "\"\n"; + } + fwrite($output_filename_handle, $buffer); + } + if (!feof($template_filename_handle)) { + $io->abort("\n\n\nError: unexpected fgets() fail"); + } + fclose($template_filename_handle); + fclose($output_filename_handle); + $io->success("\n\nSuccessfully created po file \"$output_filename\" with $count added translations!\n\n"); + } else { + $io->abort("\n\n\nError: Unable to Open File \"$template_filename\"!"); + } + } +} diff --git a/idrocap_wa/src/Command/IntendedUseVegetationCheckCommand.php b/idrocap_wa/src/Command/IntendedUseVegetationCheckCommand.php new file mode 100644 index 0000000..6b26b14 --- /dev/null +++ b/idrocap_wa/src/Command/IntendedUseVegetationCheckCommand.php @@ -0,0 +1,107 @@ +addArgument('data', [ + 'help' => 'the serialized data to process', + 'required' => true, + ]); + return $parser; + } + + /* + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $io->info("IntendedUseVegetationCheckCommand - JOB STARTED!"); + $data = $args->getArgument('data'); + $io->info("IntendedUseVegetationCheckCommand - received data: {$data}"); + + $deserialized_data = json_decode($data, true); + + if (empty($deserialized_data['water_drawing_paperwork_id'])) { + $io->abort("IntendedUseVegetationCheckCommand - water_drawing_paperwork_id is missing!"); + } + + $water_drawing_paperwork = $this->fetchTable('WaterDrawingPaperworks')->find()->where(['WaterDrawingPaperworks.id' => $deserialized_data['water_drawing_paperwork_id']])->first(); + if (!$water_drawing_paperwork) { + $io->abort("IntendedUseVegetationCheckCommand - water_drawing_paperwork with ID: {$deserialized_data['water_drawing_paperwork_id']} not found!"); + } + + $water_drawing_intended_uses = $this->fetchTable('WaterDrawingIntendedUses')->find()->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $water_drawing_paperwork->id])->all(); + + $intended_use_linked = count($water_drawing_intended_uses); + $intended_use_processed = 0; + + foreach ($water_drawing_intended_uses as $water_drawing_intended_use) { + $io->info("IntendedUseVegetationCheckCommand - checking linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id}, cadastral_code: {$water_drawing_intended_use->cadastral_code}, cadastral_sheet: {$water_drawing_intended_use->cadastral_sheet}, cadastral_parcel: {$water_drawing_intended_use->cadastral_parcel}, water_drawing_intended_use_type_id: {$water_drawing_intended_use->water_drawing_intended_use_type_id}..."); + if ($water_drawing_intended_use->water_drawing_intended_use_type_id != 1) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has water_drawing_intended_use_type_id: {$water_drawing_intended_use->water_drawing_intended_use_type_id} (must be 1), SKIPPED!"); + continue; + } + if (empty($water_drawing_intended_use->cadastral_code)) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_code, SKIPPED!"); + continue; + } + if (empty($water_drawing_intended_use->cadastral_sheet)) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_sheet, SKIPPED!"); + continue; + } + if (empty($water_drawing_intended_use->cadastral_parcel)) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO valid cadastral_parcel, SKIPPED!"); + continue; + } + $water_drawing_intended_use->vegetation_match_status = CadastralUtils::isParcelWithinVegetationArea(strtolower($water_drawing_intended_use->cadastral_code), $water_drawing_intended_use->cadastral_sheet, $water_drawing_intended_use->cadastral_parcel) ? 1 : -1; + if ($water_drawing_intended_use->vegetation_match_status == -1) { + $io->comment("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has NO MATCHING INTENDED USE!!!"); + } else { + $io->success("IntendedUseVegetationCheckCommand - linked water_drawing_intended_use with ID: {$water_drawing_intended_use->id} has PERFECT MATCHING INTENDED USE!"); + } + if (!$this->fetchTable('WaterDrawingIntendedUses')->save($water_drawing_intended_use, ['skipResetIsMismatch' => true])) { + $io->error("IntendedUseVegetationCheckCommand - error saving processed water_drawing_intended_use with ID: {$water_drawing_intended_use->id}"); + } else { + $intended_use_processed++; + } + } + + $io->success("IntendedUseVegetationCheckCommand - checked {$intended_use_linked} linked intended uses and successfully processed {$intended_use_processed} of them!"); + + if (!empty($deserialized_data['notification_user_id'])) { + $user_to_be_notified_id = $deserialized_data['notification_user_id']; + $io->info("IntendedUseVegetationCheckCommand - sending notification to user with ID: {$user_to_be_notified_id}"); + NotificationsHandler::dispatch($water_drawing_paperwork->controllable_object_id, 'send_to_last_edit_user_intended_use_check_completed', ['last_edit_user_id' => $user_to_be_notified_id, 'link' => '/water_drawing_paperworks/view' . ($water_drawing_paperwork->scanned ? '_scan' : '') .'/' . $water_drawing_paperwork->id, 'water_drawing_paperwork_id' => $water_drawing_paperwork->id]); + } else { + $io->comment("IntendedUseVegetationCheckCommand - notification_user_id is missing, skipping notification!"); + } + + $io->info("IntendedUseVegetationCheckCommand - JOB ENDED!"); + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/NormalizeApplicantProvinceCommand.php b/idrocap_wa/src/Command/NormalizeApplicantProvinceCommand.php new file mode 100644 index 0000000..d793798 --- /dev/null +++ b/idrocap_wa/src/Command/NormalizeApplicantProvinceCommand.php @@ -0,0 +1,65 @@ +fetchTable('Applicants')->find()->where(['Applicants.province IN' => ['Palermo', 'Catania', 'Caltanissetta', 'Enna', 'Ragusa', 'Agrigento', 'Messina', 'Siracusa', 'Trapani']])->toArray(); + foreach($applicants as $applicant){ + switch(strtolower($applicant->province)){ + case 'catania': + $province = 'CT'; + break; + case 'palermo': + $province = 'PA'; + break; + case 'caltanissetta': + $province = 'CL'; + break; + case 'enna': + $province = 'EN'; + break; + case 'ragusa': + $province = 'RG'; + break; + case 'siracusa': + $province = 'SR'; + break; + case 'trapani': + $province = 'TP'; + break; + case 'messina': + $province = 'ME'; + break; + case 'agrigento': + $province = 'AG'; + break; + } + if(!isset($province)) continue; + $applicant = $this->fetchTable('Applicants')->patchEntity($applicant, [ + 'province' => $province + ]); + if(!$this->fetchTable('Applicants')->save($applicant, [ + 'checkRules' => false + ])){ + $io->out(__('Errore durante il salvataggio')); + $io->out(json_encode($applicant->getErrors(), JSON_PRETTY_PRINT)); + } + $province = null; + } + return static::CODE_SUCCESS; + } +} +?> diff --git a/idrocap_wa/src/Command/NotificationsHandlerCommand.php b/idrocap_wa/src/Command/NotificationsHandlerCommand.php new file mode 100644 index 0000000..b185036 --- /dev/null +++ b/idrocap_wa/src/Command/NotificationsHandlerCommand.php @@ -0,0 +1,65 @@ +addArgument('data', [ + 'help' => 'the serialized data to process', + 'required' => true, + ]); + + return $parser; + } + + /** + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io): int + { + $data = $args->getArgument('data'); + $io->info("NotificationsHandlerCommand - received data: {$data}"); + + $deserialized_data = json_decode($data, true); + + if (empty($deserialized_data['background_task_id'])) { + $io->abort("NotificationsHandlerCommand - background_task_id is missing!"); + } + + $background_task = $this->fetchTable('BackgroundTasks')->find()->where(['BackgroundTasks.id' => $deserialized_data['background_task_id']])->first(); + if (!$background_task) { + $io->abort("NotificationsHandlerCommand - background_task not found!"); + } + + $request = json_decode($background_task->data, true); + NotificationsHandler::executeDispatch($request['co_id'], $request['notification_code'], $request['options'], $request['group'], $request['user_logged']); + + $io->success("NotificationsHandlerCommand - successfully processed!"); + return static::CODE_SUCCESS; + } +} diff --git a/idrocap_wa/src/Command/UnpackWaterDrawingPaperworkSnapshotsCommand.php b/idrocap_wa/src/Command/UnpackWaterDrawingPaperworkSnapshotsCommand.php new file mode 100644 index 0000000..9fa732f --- /dev/null +++ b/idrocap_wa/src/Command/UnpackWaterDrawingPaperworkSnapshotsCommand.php @@ -0,0 +1,98 @@ +setDescription('Unpacks water_drawing_paperworks from Snapshots and store them to unpacked_water_drawing_paperwork_snapshots table with the last unpacking version number available'); + + $parser + ->addOptions([ + 'limit' => [ + 'short' => 'l', + 'help' => 'Number of rows to process', + 'boolean' => false, + 'required' => true, + ], + ]); + + return $parser; + } + + /** + * Implement this method with your command's logic. + * + * @param \Cake\Console\Arguments $args The command arguments. + * @param \Cake\Console\ConsoleIo $io The console io + * @return null|void|int The exit code or null for success + */ + public function execute(Arguments $args, ConsoleIo $io) + { + $limit = $args->getOption('limit'); + if ($limit < 1) $io->abort("You must specify an Int number greater than ZERO!"); + $io->info("trying processing $limit items..."); + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $io->info("lastWaterDrawingPaperworkUnpackingVersion: $lastWaterDrawingPaperworkUnpackingVersion"); + + $processed = 0; + $unpackable_water_drawing_paperwork_snapshots = $this->fetchTable('Snapshots')->find()->where(['Snapshots.controllable_object_type_id' => 9, 'OR' => ['Snapshots.unpacked_with_version is NULL', 'Snapshots.unpacked_with_version <>' => $lastWaterDrawingPaperworkUnpackingVersion]])->limit((int)$limit)->toArray(); + + $io->info("found " . count($unpackable_water_drawing_paperwork_snapshots) . " unpackable items."); + + if (count($unpackable_water_drawing_paperwork_snapshots) > 0) ConnectionManager::get('default')->begin(); + + $this->fetchTable('WaterDrawingPaperworks')->removeBehavior('Trash'); + + foreach ($unpackable_water_drawing_paperwork_snapshots as $unpackable_water_drawing_paperwork_snapshot) { + $io->info("\nUnpackedWaterDrawingPaperworkSnapshot entity:"); + $unpackedWaterDrawingPaperworkSnapshot = SnapshotsHandler::getUnpackedWaterDrawingPaperworkSnapshot($unpackable_water_drawing_paperwork_snapshot->id); + if (!$unpackedWaterDrawingPaperworkSnapshot) { + ConnectionManager::get('default')->rollback(); + $io->abort("\nError retrieving unpackedWaterDrawingPaperworkSnapshot!"); + } + $io->info(json_encode($unpackedWaterDrawingPaperworkSnapshot)); + $io->info("\nSaving unpacked water_drawing_paperwork snapshot to unpackedWaterDrawingPaperworkSnapshots table..."); + if (!$this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->save($unpackedWaterDrawingPaperworkSnapshot)) { + ConnectionManager::get('default')->rollback(); + $io->abort("\nError saving unpackedWaterDrawingPaperworkSnapshot: " . json_encode($unpackedWaterDrawingPaperworkSnapshot->getErrors())); + } + $io->info("\nMarking and saving snapshot with ID " . $unpackable_water_drawing_paperwork_snapshot->id . " as unpacked with version: " . $lastWaterDrawingPaperworkUnpackingVersion); + $unpackable_water_drawing_paperwork_snapshot->unpacked_with_version = $lastWaterDrawingPaperworkUnpackingVersion; + if (!$this->fetchTable('Snapshots')->save($unpackable_water_drawing_paperwork_snapshot)) { + ConnectionManager::get('default')->rollback(); + $io->abort("\nError saving snapshot: " . json_encode($unpackable_water_drawing_paperwork_snapshot->getErrors())); + } + $processed++; + $io->success("\nSUCCESSFULLY PROCESSED: $processed !\n"); + } + + $this->fetchTable('WaterDrawingPaperworks')->addBehavior('Muffin/Trash.Trash'); + + $io->success("\nJOB IS DONE. REQUESTED: $limit, UNPACKABLE: " . count($unpackable_water_drawing_paperwork_snapshots) . " SUCCESSFULLY PROCESSED: $processed"); + + if (count($unpackable_water_drawing_paperwork_snapshots) > 0) ConnectionManager::get('default')->commit(); + + return static::CODE_SUCCESS; + } +} diff --git a/idrocap_wa/src/Console/Installer.php b/idrocap_wa/src/Console/Installer.php new file mode 100644 index 0000000..6f55798 --- /dev/null +++ b/idrocap_wa/src/Console/Installer.php @@ -0,0 +1,250 @@ +getIO(); + + $rootDir = dirname(__DIR__, 2); + + static::createAppLocalConfig($rootDir, $io); + static::createWritableDirectories($rootDir, $io); + + static::setFolderPermissions($rootDir, $io); + static::setSecuritySalt($rootDir, $io); + + if (class_exists(CodeceptionInstaller::class)) { + CodeceptionInstaller::customizeCodeceptionBinary($event); + } + } + + /** + * Create config/app_local.php file if it does not exist. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function createAppLocalConfig(string $dir, IOInterface $io): void + { + $appLocalConfig = $dir . '/config/app_local.php'; + $appLocalConfigTemplate = $dir . '/config/app_local.example.php'; + if (!file_exists($appLocalConfig)) { + copy($appLocalConfigTemplate, $appLocalConfig); + $io->write('Created `config/app_local.php` file'); + } + } + + /** + * Create the `logs` and `tmp` directories. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function createWritableDirectories(string $dir, IOInterface $io): void + { + foreach (static::WRITABLE_DIRS as $path) { + $path = $dir . '/' . $path; + if (!file_exists($path)) { + mkdir($path); + $io->write('Created `' . $path . '` directory'); + } + } + } + + /** + * Set globally writable permissions on the "tmp" and "logs" directory. + * + * This is not the most secure default, but it gets people up and running quickly. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function setFolderPermissions(string $dir, IOInterface $io): void + { + // ask if the permissions should be changed + if ($io->isInteractive()) { + $validator = function (string $arg): string { + if (in_array($arg, ['Y', 'y', 'N', 'n'])) { + return $arg; + } + throw new Exception('This is not a valid answer. Please choose Y or n.'); + }; + $setFolderPermissions = $io->askAndValidate( + 'Set Folder Permissions ? (Default to Y) [Y,n]? ', + $validator, + 10, + 'Y' + ); + + if (in_array($setFolderPermissions, ['n', 'N'])) { + return; + } + } + + // Change the permissions on a path and output the results. + $changePerms = function (string $path) use ($io): void { + $currentPerms = fileperms($path) & 0777; + $worldWritable = $currentPerms | 0007; + if ($worldWritable == $currentPerms) { + return; + } + + $res = chmod($path, $worldWritable); + if ($res) { + $io->write('Permissions set on ' . $path); + } else { + $io->write('Failed to set permissions on ' . $path); + } + }; + + $walker = function (string $dir) use (&$walker, $changePerms): void { + /** @phpstan-ignore-next-line */ + $files = array_diff(scandir($dir), ['.', '..']); + foreach ($files as $file) { + $path = $dir . '/' . $file; + + if (!is_dir($path)) { + continue; + } + + $changePerms($path); + $walker($path); + } + }; + + $walker($dir . '/tmp'); + $changePerms($dir . '/tmp'); + $changePerms($dir . '/logs'); + } + + /** + * Set the security.salt value in the application's config file. + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @return void + */ + public static function setSecuritySalt(string $dir, IOInterface $io): void + { + $newKey = hash('sha256', Security::randomBytes(64)); + static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php'); + } + + /** + * Set the security.salt value in a given file + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @param string $newKey key to set in the file + * @param string $file A path to a file relative to the application's root + * @return void + */ + public static function setSecuritySaltInFile(string $dir, IOInterface $io, string $newKey, string $file): void + { + $config = $dir . '/config/' . $file; + $content = file_get_contents($config); + + /** @phpstan-ignore-next-line */ + $content = str_replace('__SALT__', $newKey, $content, $count); + + if ($count == 0) { + $io->write('No Security.salt placeholder to replace.'); + + return; + } + + $result = file_put_contents($config, $content); + if ($result) { + $io->write('Updated Security.salt value in config/' . $file); + + return; + } + $io->write('Unable to update Security.salt value.'); + } + + /** + * Set the APP_NAME value in a given file + * + * @param string $dir The application's root directory. + * @param \Composer\IO\IOInterface $io IO interface to write to console. + * @param string $appName app name to set in the file + * @param string $file A path to a file relative to the application's root + * @return void + */ + public static function setAppNameInFile(string $dir, IOInterface $io, string $appName, string $file): void + { + $config = $dir . '/config/' . $file; + $content = file_get_contents($config); + /** @phpstan-ignore-next-line */ + $content = str_replace('__APP_NAME__', $appName, $content, $count); + + if ($count == 0) { + $io->write('No __APP_NAME__ placeholder to replace.'); + + return; + } + + $result = file_put_contents($config, $content); + if ($result) { + $io->write('Updated __APP_NAME__ value in config/' . $file); + + return; + } + $io->write('Unable to update __APP_NAME__ value.'); + } +} diff --git a/idrocap_wa/src/Controller/AiServicesController.php b/idrocap_wa/src/Controller/AiServicesController.php new file mode 100644 index 0000000..b2822b2 --- /dev/null +++ b/idrocap_wa/src/Controller/AiServicesController.php @@ -0,0 +1,91 @@ +viewBuilder()->setClassName(JsonView::class); + $this->client = new Client([ + 'timeout' => 120 + ]); + } + + public function autocomplete(): Response + { + if (!$this->request->is('post')) { + $this->respond(405, "Method not allowed"); + } + + $isAiServiceEnabled = Configure::read('App.aiServiceEnabled'); + + if(!$isAiServiceEnabled) { + return $this->respond(403, "AI Service is disabled"); + } + + $request = $this->request->getData(); + $type = $request['type'] ?? null; + $documentHash = $request['documentHash'] ?? null; + + if (!$type || !$documentHash) { + return $this->respond(400, "Missing parameters"); + } + + $attachment = $this->findAttachment($documentHash); + + if (!$attachment) { + return $this->respond(404, "Attachment not found"); + } + + $file_name = $attachment->file_name; + $container_co_id = $attachment->container_controllable_object_id; + $path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + + if ($output === false) { + return $this->respond(404, "File not found or could not be opened"); + } + return $this->callAiServiceAndRespond($request['type'], $request['documentHash'], $output); + } + + private function callAiServiceAndRespond(string $type, string $documentHash, string $fileContent): Response + { + try { + $postData = json_encode([ + 'type' => $type, + 'documentHash' => $documentHash, + 'fileContent' => base64_encode($fileContent), + ]); + $apiResponse = $this->client->post(Configure::read('App.aiServiceUrl'),$postData, ['type' => "json"]); + + if ($apiResponse->isOk()) { + return $this->respond(200, ['result' => $apiResponse->getJson()]); + } else { + return $this->respond($apiResponse->getStatusCode(), "API Error: " . $apiResponse->getStatusCode()); + } + } catch (Exception $e) { + return $this->respond(500, $e->getMessage()); + } + } + + private function findAttachment(string $documentHash): Attachment + { + return $this->fetchTable('Attachments')->find() + ->contain(['ContainerControllableObjects']) + ->where(['file_name' => $documentHash]) + ->first(); + } +} diff --git a/idrocap_wa/src/Controller/Api/AppController.php b/idrocap_wa/src/Controller/Api/AppController.php new file mode 100644 index 0000000..3f4ea42 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/AppController.php @@ -0,0 +1,74 @@ +loadComponent('FormProtection');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + + $this->loadComponent('Authentication.Authentication'); + + $this->logged_user = $this->Authentication->getIdentity(); + $this->nopaginate = $this->request->getQuery('nopaginate') !== null && $this->request->getQuery('nopaginate'); + } + + /** + * respond + * + * @param Int $code + * @param null|Object|Array|String $bodyResponse + * @param String $content + * @return Response + */ + public function respond(Int $code = 200, null|Object|Array|String $bodyResponse = null, String $content = "application/json") : Response + { + $bodyResponse = is_object($bodyResponse) || is_array($bodyResponse) ? $bodyResponse : ['result' => $bodyResponse]; + $response = $this->getResponse(); + $response = $response->withHeader('Access-Control-Allow-Origin', '*'); + $response = $response->withHeader('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT'); + $response = $response->withHeader('Access-Control-Max-Age', '60'); + $response = $response->withHeader('Access-Control-Allow-Headers', 'x-requested-with, Content-Type, origin, authorization, accept, client-security-token'); + return $response->withStringBody(json_encode($bodyResponse))->withStatus($code)->withType($content); + } +} diff --git a/idrocap_wa/src/Controller/Api/AttachmentsController.php b/idrocap_wa/src/Controller/Api/AttachmentsController.php new file mode 100644 index 0000000..0a20053 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/AttachmentsController.php @@ -0,0 +1,53 @@ +respond(400, "not implemented");} + public function add() {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * View method + * + * @param string|null $hash Attachment hash. + * @return \Cake\Http\Response|void + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($hash) + { + $attachment = $this->fetchTable('Attachments')->find() + ->contain(['ContainerControllableObjects']) + ->where(['file_name' => $hash]) + ->first(); + + if (!$attachment) return $this->respond(404, __('Allegato non trovato')); + if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) return $this->respond(403, __('Non hai i permessi necessari per visionare l\'allegato')); + + $mimetype = $attachment->mimetype; + $file_name = $attachment->file_name; + $original_file_name = $attachment->original_file_name; + $container_co_id = $attachment->container_controllable_object_id; + $path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withAddedHeader('Content-Disposition', 'filename="' . $original_file_name . '"') + ->withCharset('UTF-8') + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/Api/ErrorController.php b/idrocap_wa/src/Controller/Api/ErrorController.php new file mode 100644 index 0000000..501e251 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/ErrorController.php @@ -0,0 +1,70 @@ +viewBuilder()->setTemplatePath('Error'); + } + + /** + * afterFilter callback. + * + * @param \Cake\Event\EventInterface $event Event. + * @return \Cake\Http\Response|null|void + */ + public function afterFilter(EventInterface $event) + { + } +} diff --git a/idrocap_wa/src/Controller/Api/NotificationsController.php b/idrocap_wa/src/Controller/Api/NotificationsController.php new file mode 100644 index 0000000..b64bc81 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/NotificationsController.php @@ -0,0 +1,156 @@ +respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $notifications = $this->fetchTable('Notifications')->find() + ->contain(['NotificationTypes']) + ->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) + ->order(['created' => 'DESC']) + ->formatResults(function (\Cake\Collection\CollectionInterface $notifications) { + return $notifications + ->map(function ($notification) { + if ($notification->already_mapped) return $notification; + $notification->already_mapped = true; + $notification->setHidden(array_merge($notification->getHidden(), ['already_mapped'])); + $notification->info = json_decode($notification->info); + $webURL = Configure::read('App.weburl'); + $notification->info->weblink = $webURL . $notification->info->link; + $notification->info->link = '/api' . $notification->info->link; + return $notification; + }); + }); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_notifications = $this->paginate($notifications, [ + 'maxLimit' => 100, + 'limit' => 100, + ]); + return $this->respond(200, ['notifications' => $paginated_notifications, 'pagination' => $paginated_notifications->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + /** + * count + * + * @return \Cake\Http\Response + */ + public function count() + { + $notifications_count = $this->fetchTable('Notifications')->find() + ->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) + ->count(); + return $this->respond(200, ['count' => $notifications_count]); + } + + /** + * add + * + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability(['notifications.read_all'])) { + return $this->respond(403, ['capabilities' => ['notifications.read_all']]); + } + $userId = $this->logged_user->id; + $this->fetchTable('Notifications')->updateAll(['read_by_user' => DateTime::now()], ['read_by_user IS NULL', 'user_id' => $userId]); + return $this->respond(201, "all notifications has been marked as read"); + } + + /** + * edit + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $notification = $this->fetchTable('Notifications')->get($id); + $userId = $this->logged_user->id; + if($notification->user_id != $userId) + { + return $this->respond(403, "access unauthorised"); + } + if($notification->read_by_user) + { + return $this->respond(400, "notification has already been read"); + } + $notification->read_by_user = DateTime::now(); + + if(!$this->fetchTable('Notifications')->save($notification)) + { + return $this->respond(400, ['error' => $notification->getErrors()]); + } + $notification->info = json_decode($notification->info); + return $this->respond(201, ['notification' => $notification]); + } + + public function check() + { + $notifications_count = $this->fetchTable('Notifications')->find() + ->where(['user_id' => $this->logged_user->id, 'read_by_user IS NULL']) + ->count(); + return $this->respond(200, ['result' => $notifications_count != 0]); + + } +} diff --git a/idrocap_wa/src/Controller/Api/OrganisationTypesController.php b/idrocap_wa/src/Controller/Api/OrganisationTypesController.php new file mode 100644 index 0000000..978712d --- /dev/null +++ b/idrocap_wa/src/Controller/Api/OrganisationTypesController.php @@ -0,0 +1,31 @@ +respond(400, "not implemented");} + public function view($id = null) {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $organisationTypes = $this->fetchTable('OrganisationTypes')->find('list')->order(['OrganisationTypes.description' => 'ASC']); + return $this->respond(200, ['organisation_types' => $organisationTypes]); + } +} diff --git a/idrocap_wa/src/Controller/Api/OrganisationsController.php b/idrocap_wa/src/Controller/Api/OrganisationsController.php new file mode 100644 index 0000000..00c726c --- /dev/null +++ b/idrocap_wa/src/Controller/Api/OrganisationsController.php @@ -0,0 +1,157 @@ +respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $options = ['type' => $this->request->getQuery('type') ?? null]; + + $user_can_index = $this->fetchTable('Organisations')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + + $organisations = $this->fetchTable('Organisations') + ->find($options['finder'], params: $options) + ->contain(['Actors', 'OrganisationTypes']) + ->formatResults(function (\Cake\Collection\CollectionInterface $organisations) { + return $organisations + ->map(function ($organisation) { + if ($organisation->already_mapped) return $organisation; + $organisation->already_mapped = true; + $organisation->setHidden(array_merge($organisation->getHidden(), ['already_mapped', 'phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); + $organisation->actor->setHidden(array_merge($organisation->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + return $organisation; + }); + }); + + $organisations = $this->fetchTable('Organisations')->applySearchParams($organisations, $this->request->getQueryParams()); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_organisations = $this->paginate($organisations, [ + 'maxLimit' => 100, + 'limit' => 100, + 'sortableFields' => ['Actors.description', 'OrganisationTypes.description', 'acronym', 'address', 'district', 'cap', 'province'], + 'order' => [ + 'Actors.description' => 'ASC' + ], + ]); + return $this->respond(200, ['organisations' => $paginated_organisations, 'pagination' => $paginated_organisations->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id = null) + { + $options = []; + + $organisation = $this->fetchTable('Organisations')->get($id, contain: ['Actors', 'OrganisationTypes']); + + $organisation->setHidden(array_merge($organisation->getHidden(), ['phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); + $organisation->actor->setHidden(array_merge($organisation->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + + if (($this->logged_user->organisation_id == $id) && (!$organisation->can_view($this->logged_user, $options))) { + return $this->respond(403, $options['error']); + } + + $organisation->deliveries = $organisation->actor->getContactsList(); + + return $this->respond(200, ['organisation' => $organisation]); + } + + /** + * getPhoto + * + * @param String $file_name + * @return \Cake\Http\Response + */ + public function getPhoto($file_name) + { + $options = []; + + $organisation = $this->fetchTable('Organisations')->find() + ->where(['Organisations.photo' => $file_name]) + ->first(); + + if (!$organisation) { + return $this->respond(404, __('Organizzazione non trovata!')); + } + if (!$organisation->can_view($this->logged_user, $options)) { + return $this->respond(403, $options['error']); + } + + $mimetype = "image/jpeg"; + $path = Configure::read('App.organisationPhotoPath') . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/Api/SubscriptionsController.php b/idrocap_wa/src/Controller/Api/SubscriptionsController.php new file mode 100644 index 0000000..31c1b5f --- /dev/null +++ b/idrocap_wa/src/Controller/Api/SubscriptionsController.php @@ -0,0 +1,67 @@ +respond(400, "not implemented");} + public function view($id = null) {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * subscribe + * + * @return \Cake\Http\Response + */ + public function subscribe() + { + $token = $this->request->getData('token') ?? null; + if (empty($token)) { + return $this->respond(400, ['error' => 'invalid subscribe token']); + } + $push_notification = $this->fetchTable('PushNotifications') + ->newEntity([ + 'value' => $token, + 'enable_notifications' => true, + 'delivery' => [ + 'actor_id' => $this->logged_user->actor_id, + 'delivery_type_id' => 0, + ], + ]); + + $result = $this->fetchTable('PushNotifications')->save($push_notification); + $status_code = is_object($result) && get_class($result) === "App\Model\Entity\PushNotification" ? 201 : 400; + $message = $status_code == 201 ? $push_notification : $push_notification->getErrors(); + return $this->respond($status_code, ['result' => $message]); + } + + /** + * unsubscribe + * + * @return \Cake\Http\Response + */ + public function unsubscribe() + { + $user_push_notification_tokens = $this->fetchTable('Deliveries') + ->find() + ->where(['Deliveries.actor_id' => $this->logged_user->actor_id, 'Deliveries.delivery_type_id' => 0]) + ->all(); + + foreach ($user_push_notification_tokens as $user_push_notification_token) { + if (!$this->fetchTable('Deliveries')->delete($user_push_notification_token)) { + return $this->respond(500, ['result' => $user_push_notification_token->getErrors()]); + } + } + return $this->respond(200, ['unsubscribed' => $user_push_notification_tokens->count()]); + } +} diff --git a/idrocap_wa/src/Controller/Api/UsersController.php b/idrocap_wa/src/Controller/Api/UsersController.php new file mode 100644 index 0000000..aa9e433 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/UsersController.php @@ -0,0 +1,230 @@ +Authentication->allowUnauthenticated(['login']); + } + + public function add() {return $this->respond(400, "not implemented");} + public function edit($id = null) {return $this->respond(400, "not implemented");} + public function delete($id = null) {return $this->respond(400, "not implemented");} + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index() + { + $options = []; + + $user_can_index = $this->fetchTable('Users')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + + $users = $this->fetchTable('Users') + ->find($options['finder'], params: $options) + ->contain(['UserActors', 'Organisations' => ['Actors']]) + ->formatResults(function (\Cake\Collection\CollectionInterface $users) { + return $users + ->map(function ($user) { + if ($user->already_mapped) return $user; + $user->already_mapped = true; + $user->setHidden(array_merge($user->getHidden(), ['already_mapped', 'organisation_id', 'phone', 'mobile', 'mobile2', 'email', 'notification_hash', 'fax', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'language_id', 'privacy', 'conditions', 'password_recovery_token', 'last_change_password', 'password_recovery_counter', 'email2', 'actor_id', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd'])); + $user->user_actor->setHidden(array_merge($user->user_actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + $user->organisation_description = $user->organisation->actor->description; + $user->birthday = $user->birthday?->format('d/m/Y'); + return $user; + }); + }); + + $users = $this->fetchTable('Users')->applySearchParams($users, $this->request->getQueryParams()); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_users = $this->paginate($users, [ + 'maxLimit' => 100, + 'limit' => 100, + 'sortableFields' => ['UserActors.description', 'username', 'surname', 'name', 'cap', 'gender'], + 'order' => [ + 'Users.surname' => 'ASC', + ], + ]); + return $this->respond(200, ['users' => $paginated_users, 'pagination' => $paginated_users->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id) + { + $options = []; + + $user = $this->fetchTable('Users')->get($id, contain: ['UserActors', 'Organisations' => ['Actors', 'OrganisationTypes']]); + + if ($user->id != $this->logged_user->id && (!$user->can_view($this->logged_user, $options))) { + return $this->respond(403, $options['error']); + } + + $user->setHidden(array_merge($user->getHidden(), ['fax', 'email', 'mobile2', 'mobile', 'email2', 'phone', 'organisation_id', 'notification_hash', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'language_id', 'privacy', 'conditions', 'password_recovery_token', 'last_change_password', 'password_recovery_counter', 'actor_id', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd'])); + $user->actor = $user->user_actor; + unset($user->user_actor); + $user->actor->setHidden(array_merge($user->actor->getHidden(), ['actor_type_id', 'interoperability_identifier', 'incident_type_group_id', 'deleted'])); + $user->organisation_description = null; + if ($user->hasValue('organisation')) { + $user->organisation->setHidden(array_merge($user->organisation->getHidden(), ['phone', 'mobile', 'fax', 'email', 'organisation_type_id', 'actor_id', 'incident_creator', 'pec', 'deleted', 'incident_default_tab', 'loggable_object_id', 'controllable_object_interface_id'])); + $user->organisation_description = $user->organisation->actor->description; + unset($user->organisation->actor); + } + + $user->deliveries = $user->actor->getContactsList(); + + return $this->respond(200, ['user' => $user]); + } + + + /** + * login + * + * @return \Cake\Http\Response + */ + public function login() + { + $result = $this->Authentication->getResult(); + // If the user is logged in send them away. + if ($result->isValid()) { + $receivedData = $this->getRequest()->getData(); + $client_id = isset($receivedData['client_id']) && $receivedData['client_id'] != "" ? $receivedData['client_id'] : 'auto-' . bin2hex(random_bytes(32)); + $platform = isset($receivedData['platform']) ? $receivedData['platform'] : 'unknown'; + $tokenExpirationTime = Configure::read('App.jwt.expiration_time'); + + $token = JWT::encode([ + 'sub' => $this->Authentication->getIdentity()->get('username'), + 'user_id' => $this->Authentication->getIdentity()->get('id'), + 'exp' => time() + $tokenExpirationTime, + 'client_id' => $client_id, + 'platform' => $platform, + ], file_get_contents(Configure::read('App.jwt.keys.private')), Configure::read('App.jwt.algorithm')); + + $user = $this->fetchTable('Users')->get($this->Authentication->getIdentity()->get('id')); + $user->setHidden(['password', 'phone', 'mobile', 'mobile2', 'email', 'mobile_token_date', 'mobile_token', 'notification_hash', 'fax', 'change_password', 'last_login', 'last_registered_request', 'from_mobile', 'last_ip_address', 'position', 'position_date', 'ask_new_password', 'password_expiration', 'password_recovery_token', 'password_recovery_counter', 'email2', 'ambiguity_verified', 'invalid_login_date', 'invalid_login_count', 'deleted', 'loggable_object_id', 'email2_wd', 'make_volunteer', 'full_name', 'capabilities']); + + $user->mobile_menu = $this->fetchTable('MobileComponents') + ->find() + ->matching('Capabilities') + ->where(['Capabilities.id IN' => $user->getCapabilityIds(true)]) + ->order(['MobileComponents.id' => 'ASC']) + ->distinct(['MobileComponents.menu_item']) + ->select('MobileComponents.menu_item') + ->toArray(); + + $user->notifications = $this->fetchTable('Notifications')->find() + ->contain(['NotificationTypes']) + ->where(['user_id' => $user->id, 'read_by_user IS NULL']) + ->order(['created' => 'DESC']) + ->formatResults(function (\Cake\Collection\CollectionInterface $notifications) { + return $notifications + ->map(function ($notification) { + $notification->info = json_decode($notification->info); + $webURL = Configure::read('App.weburl'); + $notification->info->weblink = $webURL . $notification->info->link; + $notification->info->link = '/api' . $notification->info->link; + return $notification; + }); + })->count() != 0; + return $this->respond(200, ['token' => $token, 'user' => $user, 'mobile_menu' => $user->mobile_menu]); + } + if ($this->request->is('post')) { + return $this->respond(401, ['error' => 'invalid credentials']); + } + } + + /** + * getPhoto + * + * @param String $file_name + * @return \Cake\Http\Response + */ + public function getPhoto($file_name) + { + $options = []; + + $user = $this->fetchTable('Users')->find() + ->where(['Users.photo' => $file_name]) + ->first(); + + if (!$user) { + return $this->respond(404, __('Utente non trovato!')); + } + if (!$user->can_view($this->logged_user, $options)) { + return $this->respond(403, $options['error']); + } + + $mimetype = "image/jpeg"; + $path = Configure::read('App.organisationPhotoPath') . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/Api/WaterDrawingDerivationsController.php b/idrocap_wa/src/Controller/Api/WaterDrawingDerivationsController.php new file mode 100644 index 0000000..e420203 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/WaterDrawingDerivationsController.php @@ -0,0 +1,75 @@ +fetchTable('WaterDrawingDerivations')->find()->where(['WaterDrawingDerivations.id' => $id])->first(); + if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); + return $this->respond(200, ['WaterDrawingDerivation' => $waterDrawingDerivation]); + } + + public function update_data(){ + $data = $this->request->getData(); + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->find()->where(['WaterDrawingDerivations.id' => $data['water_drawing_derivation_id']])->first(); + if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ + 'annual_volume' => $data['volume'], + 'average_flow_rate' => $data['portata'] + ]); + if($this->fetchTable('WaterDrawingDerivations')->save($waterDrawingDerivation)){ + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + return $this->respond(200, ['message' => $waterDrawingDerivation]); + }else{ + return $this->respond(500, ['message' => 'KO', 'error' => $waterDrawingDerivation->getErrors()]); + } + } + + public function update_location(){ + $data = $this->request->getData(); + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->find()->contain(['WaterDrawingPaperworks'])->where(['WaterDrawingDerivations.id' => $data['water_drawing_derivation_id']])->first(); + if(!isset($waterDrawingDerivation)) return $this->respond(500, ['message' => 'Punto di derivazione non trovato.']); + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}'; + if(!GeoValidation::isValidGeometry(json_decode($feature_collection))) return $this->respond(500, ['message' => 'Punto di derivazione non valido.']); + $reverse_geocoding = Geocoding::performGeocoding('reverse', ['format' => 'json', 'namedetails' => '1', 'lat' => $data['latitude'], 'lon' => $data['longitude']]); + if($reverse_geocoding['status_code']['http_code'] == '200'){ + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ + 'latitude' => $data['latitude'], + 'longitude' => $data['longitude'], + 'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}', + 'location' => isset($reverse_geocoding['contents']['address']['road']) ? $reverse_geocoding['contents']['address']['road'] : '', + 'district' => isset($reverse_geocoding['contents']['address']['town']) ? $reverse_geocoding['contents']['address']['town'] : '', + 'description' => isset($reverse_geocoding['contents']['display_name']) ? $reverse_geocoding['contents']['display_name'] : '' + ]); + }else{ + $waterDrawingDerivation = $this->fetchTable('WaterDrawingDerivations')->patchEntity($waterDrawingDerivation, [ + 'latitude' => $data['latitude'], + 'longitude' => $data['longitude'], + 'feature_collection' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $data['longitude'] . ',' . $data['latitude'] . ']},"properties":null}]}' + ]); + } + if($this->fetchTable('WaterDrawingDerivations')->save($waterDrawingDerivation)){ + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + return $this->respond(200, ['message' => 'OK']); + }else{ + return $this->respond(500, ['message' => 'KO', 'error' => $waterDrawingDerivation->getErrors()]); + } + } +} diff --git a/idrocap_wa/src/Controller/Api/WaterDrawingMeasurementsController.php b/idrocap_wa/src/Controller/Api/WaterDrawingMeasurementsController.php new file mode 100644 index 0000000..ac2a04f --- /dev/null +++ b/idrocap_wa/src/Controller/Api/WaterDrawingMeasurementsController.php @@ -0,0 +1,47 @@ +request->getData(); + $WaterDrawingMeasurement = $this->fetchTable('WaterDrawingMeasurements')->newEntity([ + 'volume' => $data['volume'], + 'water_drawing_meter_id' => $data['water_drawing_meter_id'], + 'date' => DateTime::now(), + 'user_id' => $this->logged_user->id + ]); + if($this->fetchTable('WaterDrawingMeasurements')->save($WaterDrawingMeasurement)){ + $waterDrawingMeter = $this->fetchTable('WaterDrawingMeters')->get($data['water_drawing_meter_id'], contain: ['WaterDrawingIntendedUses' => ['WaterDrawingPaperworks']]); + SnapshotsHandler::createSnapshot($waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork->controllable_object_id); + return $this->respond(200, ['message' => __('Salvato con successo')]); + }else{ + return $this->respond(500, ['message' => __('Errore durante il salvataggio.'), 'error' => $WaterDrawingMeasurement->getErrors()]); + } + } + + public function last_index($id){ + $WaterDrawingMeasurements = $this->fetchTable('WaterDrawingMeasurements')->find()->contain(['Users'])->where(['WaterDrawingMeasurements.water_drawing_meter_id' => $id])->order(['WaterDrawingMeasurements.date' => 'DESC', 'WaterDrawingMeasurements.id' => 'DESC'])->limit(5)->formatResults( function ($result){ + return $result->map( function ($q) { + $q->date = $q->date?->format('d/m/Y'); + return $q; + }); + })->toArray(); + return $this->respond(200, ['WaterDaringMeasurements' => $WaterDrawingMeasurements]); + } +} diff --git a/idrocap_wa/src/Controller/Api/WaterDrawingPaperworksController.php b/idrocap_wa/src/Controller/Api/WaterDrawingPaperworksController.php new file mode 100644 index 0000000..23dcb00 --- /dev/null +++ b/idrocap_wa/src/Controller/Api/WaterDrawingPaperworksController.php @@ -0,0 +1,170 @@ +fetchTable('WaterDrawingPaperworks')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + + $waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->find() + ->contain(['ControllableObjects', 'WaterDrawingPaperworkStatuses'])->matching('Applicants'); + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperworks = $waterDrawingPaperworks->where(['authority_province' => $this->logged_user?->organisation_province]); + } + $waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->applySearchParams($waterDrawingPaperworks, $this->request->getQueryParams()); + + $waterDrawingPaperworks = $waterDrawingPaperworks->distinct(['WaterDrawingPaperworks.id'])->formatResults(function ($results){ + return $results->map(function ($row) { + if ($row->already_mapped) return $row; + $row->already_mapped = true; + $row->setHidden(array_merge($row->getHidden(), ['already_mapped'])); + $row->release_date = $row->release_date?->format('d/m/Y'); + $row->expiration_date = $row->expiration_date?->format('d/m/Y'); + $row->controllable_object->created = $row->controllable_object->created?->format('d/m/Y H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('d/m/Y H:i:s'); + return $row; + }); + }); + + /** + * Default pagination settings. + * + * When calling paginate() these settings will be merged with the configuration + * you provide. + * + * - `maxLimit` - The maximum limit users can choose to view. Defaults to 100 + * - `limit` - The initial number of items per page. Defaults to 20. + * - `page` - The starting page, defaults to 1. + * - `allowedParameters` - A list of parameters users are allowed to set using request + * parameters. Modifying this list will allow users to have more influence + * over pagination, be careful with what you permit. + * - `sortableFields` - A list of fields which can be used for sorting. By + * default all table columns can be used for sorting. You can use this option + * to restrict sorting only by particular fields. If you want to allow + * sorting on either associated columns or calculated fields then you will + * have to explicitly specify them (along with other fields). Using an empty + * array will disable sorting alltogether. + * - `finder` - The table finder to use. Defaults to `all`. + * - `scope` - If specified this scope will be used to get the paging options + * from the query params passed to paginate(). Scopes allow namespacing the + * paging options and allows paginating multiple models in the same action. + * Default `null`. + * + * protected array $_defaultConfig = [ + * 'page' => 1, + * 'limit' => 20, + * 'maxLimit' => 100, + * 'allowedParameters' => ['limit', 'sort', 'page', 'direction'], + * 'sortableFields' => null, + * 'finder' => 'all', + * 'scope' => null, + * ]; + */ + + try { + $paginated_waterDrawingPaperworks = $this->paginate($waterDrawingPaperworks, [ + 'maxLimit' => 25, + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + ]); + return $this->respond(200, ['waterDrawingPaperworks' => $paginated_waterDrawingPaperworks, 'pagination' => $paginated_waterDrawingPaperworks->pagingParams()]); + } catch (\Cake\Http\Exception\NotFoundException $th) { + return $this->respond(404, ['result' => $th->getMessage()]); + } + } + + public function view($id){ + $options = []; + + $user_can_index = $this->fetchTable('WaterDrawingPaperworks')->can_index($this->logged_user, $options); + + if (!$user_can_index) + { + return $this->respond(403, $options['error']); + } + $organisation = $this->getTableLocator()->get('Organisations')->find()->where(['Organisations.id' => $this->logged_user->organisation_id])->first(); + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->find() + ->contain([ 'WaterDrawingArticles', 'WaterDrawingFees', 'GcUsers' => ['Organisations'], 'DrarUsers' => ['Organisations'], 'WaterDrawingReturnPoints', 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], 'WaterDrawingPaperworkStatuses', 'ControllableObjects' => ['Attachments' => ['Tags']], 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q){ + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + ]); + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperwork = $waterDrawingPaperwork->where(['authority_province' => $this->logged_user?->organisation_province]); + } + $waterDrawingPaperwork = $waterDrawingPaperwork->where(['WaterDrawingPaperworks.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) use ($organisation){ + return $results->map(function ($row) use ($organisation){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && ( $this->logged_user->id == $row->gc_user_id && ($row->water_drawing_paperwork_status_id === -1 || $row->water_drawing_paperwork_status_id === -5 ) || ( $this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -4 )); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete'); + $row->can_validate = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate') && $row->water_drawing_paperwork_status_id === -3; + $row->can_send_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && $row->water_drawing_paperwork_status_id === -1 && $row->check_sdd && $row->gc_user_id == $this->logged_user->id; + $row->can_send_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') && $row->water_drawing_paperwork_status_id === -4 && $row->check_dec && $row->drar_user_id == $this->logged_user->id; + $row->can_assign_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && $row->water_drawing_paperwork_status_id <= -2 && $organisation->organisation_type_id == 6; + $row->can_assign_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && isset($row->gc_user->organisation->organisation_type_id) && $organisation->organisation_type_id == $row->gc_user->organisation->organisation_type_id; + if($row->water_drawing_paperwork_status_id === -5){ + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment') ; + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_add_meter = $this->logged_user->hasCapability('documentation.water_drawing_meters.add'); + $row->can_add_measurements = $this->logged_user->hasCapability('documentation.water_drawing_measurements.add'); + $row->can_view_measurements = true; + } + if($row->water_drawing_paperwork_status_id == -4){ + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment') ; + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_submit_antimafia_request = ($this->logged_user->id == $row->drar_user_id) && (!isset($row->water_drawing_antimafia_certification_requests[0])); + $row->can_antimafia_request_to_anac = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && (isset($row->water_drawing_antimafia_certification_requests[0]) && ($row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 1)); + $row->can_request_self_certification = ($this->logged_user->id == $row->drar_user_id) && (isset($row->water_drawing_antimafia_certification_requests[0]) && (new DateTime($row->water_drawing_antimafia_certification_requests[0]->created))->diffInDays(\Cake\I18n\DateTime::now()) > 30); + $row->can_upload_antimafia_attachment = (isset($row->water_drawing_antimafia_certification_requests[0]) && ( + ( ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && !($row->check_dam)) || + ( ($this->logged_user->id == $row->gc_user_id) && $row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 3) + )); + } + return $row; + }); + })->first(); + $waterDrawingPaperwork->water_drawing_meters = $this->getTableLocator()->get('WaterDrawingMeters')->find()->contain(['WaterDrawingIntendedUses', 'WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q){ + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }])->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'WaterDrawingMeters.removal_date IS NULL'])->formatResults(function ($results){ + return $results->map(function ($row){ + $row->installation_date = $row->installation_date?->format('d/m/Y'); + return $row; + }); + })->toArray(); + return $this->respond(200, ['result' => $waterDrawingPaperwork]); + } +} diff --git a/idrocap_wa/src/Controller/AppController.php b/idrocap_wa/src/Controller/AppController.php new file mode 100644 index 0000000..69ef6df --- /dev/null +++ b/idrocap_wa/src/Controller/AppController.php @@ -0,0 +1,424 @@ +loadComponent('FormProtection');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + + $this->loadComponent('Authentication.Authentication'); + $this->loadComponent('Flash'); + + // recuperiamo l'entità dello user (se loggato): + $this->logged_user = $this->Authentication->getIdentity(); + + // settiamo il locale come da preferenze utente (se specificato, altrimenti ci pensa il LocaleSelectorMiddleware): + if (!empty($this->logged_user->language_id)) I18n::setLocale($this->fetchTable('Languages')->get($this->logged_user->language_id)->language_code); + $this->set('locale', I18n::getLocale()); + + /* + * Enable the following component for recommended CakePHP form protection settings. + * see https://book.cakephp.org/4/en/controllers/components/form-protection.html + */ + //$this->loadComponent('FormProtection'); + } + + public function beforeRender(EventInterface $event) + { + if ($this->getRequest()->is(['json', 'xml', 'csv'])) { + $this->viewBuilder()->disableAutoLayout(); + } + + $sys_admin_menu_items = null; + $menu_sections = []; + $menu_items = []; + $logged_user_id = null; + $logged_user_description = null; + $logged_user_access_type_description = null; + $logged_user_timezone = null; + $logged_user_organisation_description = null; + $logged_user_photo = Configure::read('App.defaultUserPhoto'); + $user_notifications_count = 0; + $user_notifications = []; + + // bisogna recuperare le capabilities utente (se esiste un utente loggato) + if ($this->logged_user) { + // menu SYSADMIN da mostrare solo ai SYSADMIN: + $sys_admin_menu_items = [ + [ + 'title' => __('SYSADMIN'), + 'icon' => 'lock', + 'menu_items' => [ + [ + 'title' => __('Gestione competenze'), + 'icon' => 'wrench', + 'link' => '/capabilities', + ], + [ + 'title' => __('Test notifiche'), + 'icon' => 'bell', + 'link' => '/notifications/testAll', + 'confirm' => __('Procedendo verranno inviate notifiche a tutti gli utenti e le organizzaioni che possiedono uno o più recapiti abilitati alle notifiche! Sei sicuro che vuoi continuare ?'), + 'method' => 'POST', + ], + ], + + ], + ]; + if (!$this->logged_user->sys_admin) $sys_admin_menu_items = null; + + $logged_user_id = $this->logged_user->id; + $logged_user_description = $this->logged_user->name . ' ' . $this->logged_user->surname; + $logged_user_access_type_description = $this->logged_user->sys_admin ? 'sys_admin' : ($this->logged_user->passepartout ? 'passepartout' : ''); + $logged_user_timezone = $this->logged_user->timezone ?? Configure::read('App.defaultUserTimezone'); + if (isset($this->logged_user->organisation_id)) { + $logged_user_organisation_description = $this->fetchTable('Organisations')->get($this->logged_user->organisation_id, contain: ['Actors'])->actor->description; + } + if (!empty($this->logged_user->photo)) $logged_user_photo = Configure::read('App.userPhotoSrc') . "/" . $this->logged_user->photo; + + $user_notifications_count = $this->fetchTable('Notifications')->find()->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL'])->count(); + + $user_notifications = $this->fetchTable('Notifications') + ->find() + ->contain('NotificationTypes') + ->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL']) + ->order(['Notifications.created' => 'DESC']) + ->all() + ->reduce(function ($acc, $user_notification) { + $notification_info = json_decode($user_notification->info); + $body = strlen($notification_info->body) > 200 ? substr($notification_info->body, 0, 197) . '...' : $notification_info->body; + $icon = $user_notification->notification_type->icon ?? 'bell'; + $time_ago = (new DateTime($user_notification->created))->timeAgoInWords(); + $acc[] = ['id' => $user_notification->id, 'icon' => $icon, 'title' => $notification_info->title, 'body' => $body, 'time_ago' => $time_ago]; + return $acc; + }, []); + + $user_capabilityIds_query = $this->logged_user->getCapabilityIds(true); + + $menu_sections_subquery = $this->fetchTable('MenuSections') + ->find() + ->select(['MenuSections.id']) + ->innerJoinWith('Capabilities') + ->where(['Capabilities.id IN' => $user_capabilityIds_query]) + ->distinct(['MenuSections.id']); + + $menu_sections = $this->fetchTable('MenuSections') + ->find() + ->where(['MenuSections.id IN' => $menu_sections_subquery]) + ->order(['MenuSections.id' => 'ASC']) + ->toArray(); + + if (count($menu_sections) > 0) { + // questo blocco controlla se nella request è presente il query param 'menu_section' + // se è presente e rappresenta un id di menu_section valido, lo settiamo in sessione utente + if ($this->getRequest()->getQuery('menu_section')) { + $valid_user_menu_section = $this->fetchTable('MenuSections')->find() + ->matching('Capabilities') + ->where(['Capabilities.id IN' => $user_capabilityIds_query, 'MenuSections.id' => $this->getRequest()->getQuery('menu_section')]) + ->first(); + + $valid_user_menu_section_id = $valid_user_menu_section ? $valid_user_menu_section->id : $menu_sections[0]->id; + + $this->getRequest()->getSession()->write('menu_section', $valid_user_menu_section_id); + } + $menu_section_id = $this->getRequest()->getSession()->read('menu_section') ?? $menu_sections[0]->id; + + $menu_items_subquery = $this->fetchTable('MenuItems') + ->find() + ->select(['MenuItems.id']) + ->innerJoinWith('Capabilities') + ->where(['Capabilities.id IN' => $user_capabilityIds_query]) + ->where(['MenuItems.menu_item_id IS NULL']) + ->where(['MenuItems.menu_section_id' => $menu_section_id]) + ->distinct(['MenuItems.id']); + + $menu_items = $this->fetchTable('MenuItems') + ->find() + ->where(['MenuItems.id IN' => $menu_items_subquery]) + ->order(['MenuItems.menu_order' => 'ASC']) + ->toArray(); + } + + if( $this->request->getPath() !== '/notifications/index' ) + { + $privacy = $this->fetchTable('Privacy') + ->find()->orderBy(['created' => 'DESC']) + ->first(); + + if(isset($privacy)) + { + $hasAcceptedPrivacy = $this->fetchTable('PrivacyUsers')->find()->where([ + 'PrivacyUsers.user_id' => $this->logged_user->id, + 'PrivacyUsers.privacy_id' => $privacy->id + ])->first(); + + if( + !isset($hasAcceptedPrivacy) && + $this->request->getParam('controller') != 'Privacy' && + $this->request->getParam('action') != 'accept_privacy' + ) { + return $this->redirect(['controller' => 'Privacy', 'action' => 'accept_privacy']); + } + } + } + } + + $this->set('menu_sections', $menu_sections); + $this->set('menu_items', $menu_items); + $this->set('sys_admin_menu_items', $sys_admin_menu_items); + $this->set('logged_user_id', $logged_user_id); + $this->set('logged_user_description', $logged_user_description); + $this->set('logged_user_access_type_description', $logged_user_access_type_description); + $this->set('logged_user_timezone', $logged_user_timezone); + $this->set('logged_user_organisation_description', $logged_user_organisation_description); + $this->set('logged_user_photo', $logged_user_photo); + $this->set('user_notifications_count', $user_notifications_count); + $this->set('user_notifications', $user_notifications); + } + + /** + * gen_random_code + * + * @param Int $length + * @return String + */ + protected function gen_random_code(Int $length): String { + $characters = "abcdefghijklmnopqrstuvwxyzABCDERFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $randomString = ""; + + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[mt_rand(0, strlen($characters)-1)]; + } + return $randomString; + } + + /** + * sendNotifications + * + * @param Int|Null $co_id + * @param String $notification_code + * @param Array $options + * @return void + */ + protected function sendNotifications(Int|Null $co_id, String $notification_code, Array $options) + { + NotificationsHandler::dispatch($co_id, $notification_code, $options, null, $this->logged_user->id ?? null); + } + + /** + * applyFilters + * + * @param Query $query + * @return Query + */ + protected function applyFilters(Query $query): Query + { + // recuperiamo i parametri per costruire la chiave per memorizzare i filtri in sessione. + // i filtri sono "scoped" per utente e per route. Quindi per ogni utente possiamo memorizzare + // filtri relativi a più liste. + $logged_user_id = $this->logged_user->id; + $controller = $this->request->getParam('controller'); + $action = $this->request->getParam('action'); + $filter_session_key = "filters-$logged_user_id-$controller-$action"; + + // recuperiamo i filtri o dal POST data (significa che sono stati appena applicati) + // o dalla sessione (se ci sono): + $filters = $this->request->is('post') ? $this->request->getData('filters') : $this->request->getSession()->read($filter_session_key); + \Cake\Log\Log::write("debug", 'applyFilters - ' . ($this->request->is('post') ? 'POST received' : 'SESSION retrieved') . ' filters: ' . json_encode($filters)); + + // ripuliamo i filtri eliminando prima i valori non validi per ciascun filtro + // e successivamente eliminiamo direttamente i fitri che non hanno valori validi (rimasti): + $filters = collection($filters ?? []) + ->map(function ($filter_values, $filter_id) { + return collection($filter_values) + ->filter(function ($filter_value) { + // il controllo con === "0" serve per evitare che il sanitiser elimini + // il valore "0" per filtri di tipo "bool" + return !empty($filter_value) || $filter_value === "0"; + }) + ->reduce(function ($filter_values, $filter_value) { + $filter_values[] = $filter_value; + return $filter_values; + }, []); + }) + ->filter(function ($filter_values, $filter_id) { + return !empty($filter_values); + }) + ->toArray(); + + \Cake\Log\Log::write("debug", 'applyFilters - SANITISED filters: ' . json_encode($filters)); + + // se non si è riusciti a recuperare filtri + // o è stato richesto un reset dei filtri tramite POST + // o non ne sono rimasti a seguito della sanitizzazione, + // cancelliamo comunque la sessione alla chiave $filter_session_key + // ed usciamo senza applicare nulla alla query: + if (empty($filters)) { + \Cake\Log\Log::write("debug", "applyFilters - DELETING DATA SESSION with key '$filter_session_key'"); + $this->request->getSession()->delete($filter_session_key); + \Cake\Log\Log::write("debug", 'applyFilters - NO filters to appply!'); + return $query; + } + + // se abbiamo filtri validi e li abbiamo appena ricevuti (POST), li salviamo in sessione: + if ($this->request->is('post')) { + \Cake\Log\Log::write("debug", "applyFilters - WRITING DATA SESSION with key '$filter_session_key': " . json_encode($filters)); + $this->request->getSession()->write($filter_session_key, $filters); + } + + // array delle possibili associations da gestire nella query con ->leftJoinWith(). + // verrà popolato durante il processo di conversione da filtri a conditions: + $associations = []; + + // array delle conditions creato a partire dai filters ricevuti, da gestire nella query con ->where() + $conditions = collection($filters) + // qui trasformiamo i filtri in conditions in base alla tipologia di filtro ricevuto: + ->map(function ($filter_values, $filter_id) use (&$associations) { + // recuperiamo le info sul filtro dalla table 'filters' avendo ricevuto l'id del filtro: + $filter = $this->fetchTable('Filters')->get((Int)explode("filter_id_", $filter_id)[1]); + // creazione della condizione in base al tipo di filtro: + switch ($filter->filter_type) { + case 'class': + case 'bool': + $condition = [$filter->search . ' IN' => $filter_values]; + break; + case 'text': + $condition = collection($filter_values) + ->map(function ($filter_value) use ($filter) { + return [$filter->search . ' LIKE' => $filter_value]; + }) + ->reduce(function ($conditions, $condition) { + $conditions['OR'][] = $condition; + return $conditions; + }, ['OR' => []]); + break; + case 'date': + $condition = collection($filter_values) + ->map(function ($filter_value) use ($filter) { + $date_array = explode(" - ", $filter_value); + $from_date = $date_array[0]; + $to_date = $date_array[1]; + return [$filter->search . ' >=' => $from_date, $filter->search . ' <=' => $to_date]; + }) + ->reduce(function ($conditions, $condition) { + $conditions['OR'][] = $condition; + return $conditions; + }, ['OR' => []]); + break; + default: + break; + } + // se il filtro è stato gestito e richiede una association, la inseriamo in apposito array: + if (!empty($condition) && !empty($filter->associations)) $associations[] = $filter->associations; + + // se il filtro non è stato gestito, restituiamo null; altrimenti restituiamo la condition + return $condition ?? null; + }) + // qui eliminiamo eventuali conditions null (generate da filtri non (al momento) gestiti: + ->filter(function ($condition) { + return !empty($condition); + }) + // infine restituiamo l'array_values delle conditions ottenute: + ->reduce(function ($conditions, $condition) { + $conditions[] = $condition; + return $conditions; + }, []); + + \Cake\Log\Log::write("debug", 'applyFilters - conditions applied: ' . json_encode($conditions)); + + if (count($conditions) > 0) $query = $query->where($conditions); + + \Cake\Log\Log::write("debug", 'applyFilters - associations applied: ' . json_encode($associations)); + + foreach ($associations as $association) { + $query = $query->leftJoinWith($association); + } + + if (count($associations) > 0) { + $main_table = $query->getRepository()->getAlias(); + $query = $query->distinct(["$main_table.id"]); + \Cake\Log\Log::write("debug", 'applyFilters - distinct applied: ' . "$main_table.id"); + } + + return $query; + } + + /** + * Respond with JSON + * + * @param int $statusCode HTTP status code + * @param null|object|array|string|null $responseBody Content of the response + * @param string $contentType Content type of the response, default "application/json" + * @return Response + */ + public function respond(int $statusCode = 200, null|object|array|string $responseBody = null, string $contentType = "application/json") : Response + { + $responseBody = is_object($responseBody) || is_array($responseBody) ? $responseBody : ['result' => $responseBody]; + + if ($paging = $this->request->getAttribute('paging')) { + $responseBody['pagination'] = $paging; + } + + try { + $encodedBody = json_encode($responseBody, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + } catch (Exception $e) { + return $this->getResponse() + ->withStatus(500) + ->withStringBody(json_encode(['error' => 'Failed to encode JSON response'])) + ->withType('application/json'); + } + + $response = $this->getResponse() + ->withStatus($statusCode) + ->withType($contentType) + ->withStringBody($encodedBody); + + return $response; + } +} diff --git a/idrocap_wa/src/Controller/ApplicantsController.php b/idrocap_wa/src/Controller/ApplicantsController.php new file mode 100644 index 0000000..cf643ae --- /dev/null +++ b/idrocap_wa/src/Controller/ApplicantsController.php @@ -0,0 +1,112 @@ +viewBuilder()->setClassName('Json'); + + $search = $this->request->getQueryParams('term'); + $applicants = $this->Applicants->find()->where([ + 'Applicants.tax_code LIKE "%' . $search['term'] . '%" OR Applicants.name LIKE "%' . $search['term'] . '%" OR Applicants.surname LIKE "%' . $search['term'] . '%"' + ])->formatResults(function ($results){ + return $results->map(function ($row) { + return ['id' => $row->id, 'text' => $row->tax_code . ' - ' . $row->name . ' ' . $row->surname]; + }); + })->toArray(); + $this->set(compact('applicants')); + $this->viewBuilder()->setOption('serialize', ['applicants'])->setOption('jsonOptions', JSON_FORCE_OBJECT); + } + + public function get_applicant($id){ + $applicant = $this->Applicants->get($id); + $this->set(compact('applicant')); + $this->viewBuilder()->setOption('serialize', ['applicant'])->setOption('jsonOptions', JSON_FORCE_OBJECT); + } + + public function edit($id, $water_id = null){ + $applicant = $this->Applicants->get($id); + if ($this->request->is(['patch', 'post', 'put'])) { + $applicant = $this->Applicants->patchEntity($applicant, $this->request->getData()); + if ($this->Applicants->save($applicant)) { + $this->Flash->success(__('Il concessionario è stato aggiornato correttamente.')); + + return $this->redirect(['action' => 'view', $id]); + } + $this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); + } + if(isset($water_id)){ + $waterDrawingPaperwork = $this->Applicants->WaterDrawingPaperworks->get($water_id); + $this->set(compact('waterDrawingPaperwork')); + } + $this->set(compact('applicant')); + } + + public function view($id){ + $applicant = $this->Applicants->get($id); + $this->set(compact('applicant')); + } + + // CITIZEN SECTION + + public function citizen_add(){ + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $applicant = $this->Applicants->newEmptyEntity(); + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['name'] = $this->logged_user->name; + $data['surname'] = $this->logged_user->surname; + $data['tax_code'] = $this->logged_user->tax_code; + $applicant = $this->Applicants->patchEntity($applicant, $data); + if ($this->Applicants->save($applicant)) { + $this->Flash->success(__('Il concessionario è stato creato correttamente.')); + + return $this->redirect(['action' => 'citizen_view']); + } + $this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); + } + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $this->set('user', $user); + $this->set(compact('applicant')); + } + + public function citizen_edit(){ + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $applicant = $this->Applicants->find()->where(['Applicants.tax_code' => $user->tax_code])->first(); + if ($this->request->is(['patch', 'post', 'put'])) { + $applicant = $this->Applicants->patchEntity($applicant, $this->request->getData()); + if ($this->Applicants->save($applicant)) { + $this->Flash->success(__('Il concessionario è stato aggiornato correttamente.')); + + return $this->redirect(['action' => 'citizen_view']); + } + $this->Flash->error(__('Errore. Il concessionario non è stato salvato.')); + } + $this->set('user', $user); + $this->set(compact('applicant')); + } + + public function citizen_view(){ + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $applicant = $this->Applicants->find()->where(['Applicants.tax_code' => $user->tax_code])->first(); + if(!isset($applicant)) $this->redirect(['action' => 'citizen_add']); + $this->set(compact('applicant')); + } +} diff --git a/idrocap_wa/src/Controller/AttachmentsController.php b/idrocap_wa/src/Controller/AttachmentsController.php new file mode 100644 index 0000000..4aed82a --- /dev/null +++ b/idrocap_wa/src/Controller/AttachmentsController.php @@ -0,0 +1,98 @@ +request->getQuery('withTrashed'); + $finder = !empty($withTrashed) ? 'withTrashed' : 'all'; + $attachment = $this->fetchTable('Attachments')->find($finder) + ->contain(['ContainerControllableObjects']) + ->where(['file_name' => $id]) + ->first(); + + if (!$attachment) throw new NotFoundException(__('Allegato non trovato')); + if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) throw new ForbiddenException(__('Non hai i permessi necessari per visionare l\'allegato')); + + $mimetype = $attachment->mimetype; + $file_name = $attachment->file_name; + $original_file_name = $attachment->original_file_name; + $container_co_id = $attachment->container_controllable_object_id; + $path = Configure::read('App.attachmentsPath') . "/" . $container_co_id . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withAddedHeader('Content-Disposition', 'filename="' . $original_file_name . '"') + ->withCharset('UTF-8') + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } + + /** + * markAsRelevant + * + * @param Int $id + * @throws NotFoundException + * @return \Cake\Http\Response + */ + public function markAsRelevant($id = null) + { + $this->request->allowMethod(['post']); + $attachment = $this->fetchTable('Attachments')->find()->contain(['ContainerControllableObjects', 'ControllableObjects'])->where(['file_name' => $id])->first(); + + if(!$attachment) throw new NotFoundException(__('Allegato non trovato')); + if (!$this->logged_user->canHandleAttachmentsForControllableObject($attachment->container_controllable_object)) throw new ForbiddenException(__('Non hai i permessi necessari per visionare l\'allegato')); + + $attachment->relevant = !$attachment->relevant; + $attachment->controllable_object->id = $attachment->controllable_object->id; + $attachment->setDirty('controllable_object'); + $this->fetchTable('Attachments')->save($attachment); + $response = (object) []; + $response->result = true; + $response->relevant = $attachment->relevant; + $this->set('response', $response); + $this->viewBuilder()->setOption('serialize', 'response'); + } + + /** + * markAsDeleted + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function markAsDeleted($id = null) + { + $this->response = $this->response + ->withType('application/json') + ->withStringBody(json_encode(['result' => "markAsDeleted attachment with id '$id'. Dummy method. please do not delete it!"])); + + return $this->response; + } +} diff --git a/idrocap_wa/src/Controller/CapabilitiesController.php b/idrocap_wa/src/Controller/CapabilitiesController.php new file mode 100644 index 0000000..f3b97e7 --- /dev/null +++ b/idrocap_wa/src/Controller/CapabilitiesController.php @@ -0,0 +1,205 @@ +logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $capabilities = $this->Capabilities->find('withTrashed') + ->contain(['CapabilityGroups' => function ($q) { return $q->find('withTrashed'); }]); + + $capability_search = $this->request->getQuery('capability_search'); + if (!empty($capability_search)) { + $capabilities = $capabilities->where(['OR' => [ + 'Capabilities.description LIKE' => "%$capability_search%", + 'Capabilities.value LIKE' => "%$capability_search%", + 'CapabilityGroups.description LIKE' => "%$capability_search%", + ]]); + } + + $this->paginate = [ + 'sortableFields' => ['description', 'value', 'priority', 'CapabilityGroups.description'], + ]; + + $this->set('capabilities', $this->paginate($capabilities)); + $this->set('capability_search', $capability_search); + } + + /** + * hide + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function hide($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + $capability->is_configurable = false; + if ($this->Capabilities->save($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->contain(['Capabilities' => function ($q) { return $q->find('withTrashed')->where(['Capabilities.is_configurable' => 1]); }]) + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + if (count($capability_group->capabilities) == 0) { + $capability_group->is_configurable = false; + if ($this->Capabilities->CapabilityGroups->save($capability_group)) { + $errSave = false; + } + } else { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" nascosta con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante il tentativo di nascondere la Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } + + /** + * show + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function show($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + $capability->is_configurable = true; + if ($this->Capabilities->save($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + $capability_group->is_configurable = true; + if ($this->Capabilities->CapabilityGroups->save($capability_group)) { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" resa visibile con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante il tentativo di rendere visibile la Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } + + /** + * delete + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function delete($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $this->Capabilities->Permissions->addBehavior('Muffin/Trash.Trash'); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + if ($this->Capabilities->delete($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->contain(['Capabilities']) + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + if (count($capability_group->capabilities) == 0) { + if ($this->Capabilities->CapabilityGroups->delete($capability_group)) { + $errSave = false; + } + } else { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" cancellata con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante la cancellazione della Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } + + /** + * restore + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function restore($id) + { + if (!$this->logged_user->sys_admin) throw new ForbiddenException(__('Non hai i permessi necessari')); + $this->Capabilities->Permissions->addBehavior('Muffin/Trash.Trash'); + $capability = $this->Capabilities->find('withTrashed')->where(['Capabilities.id' => $id])->first(); + $connection = ConnectionManager::get('default'); + $errSave = true; + $connection->begin(); + if ($this->Capabilities->cascadingRestoreTrash($capability)) { + $capability_group = $this->Capabilities->CapabilityGroups->find('withTrashed') + ->where(['CapabilityGroups.id' => $capability->capability_group_id]) + ->first(); + + if ($capability_group) { + $capability_group->deleted = null; + if ($this->Capabilities->CapabilityGroups->save($capability_group)) { + $errSave = false; + } + } + } + + if (!$errSave) { + $this->Flash->success(__('Competenza "{0}" ripristinata con successo!', $capability->description)); + $connection->commit(); + } else { + $this->Flash->error(__('Errore durante il ripristino della Competenza "{0}"!', $capability->description)); + $connection->rollback(); + } + return $this->redirect(['action' => 'index', '?' => $this->request->getQueryParams()]); + } +} diff --git a/idrocap_wa/src/Controller/Component/.gitkeep b/idrocap_wa/src/Controller/Component/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/src/Controller/Component/StreamableCsvExportTrait.php b/idrocap_wa/src/Controller/Component/StreamableCsvExportTrait.php new file mode 100644 index 0000000..a6fc351 --- /dev/null +++ b/idrocap_wa/src/Controller/Component/StreamableCsvExportTrait.php @@ -0,0 +1,103 @@ +disableHydration(); + + do { + $results = $query + ->limit($chunkSize) + ->page($page) + ->all(); + + foreach ($results as $rowArray) { + + if ($extract !== null) { + if (!$wroteHeader) { + // we use the provided $headers as column names, + // otherwise we fallback to $extract array keys when they are plain string or we use "Column $key" if they are not + $headerRow = $headers ?? array_map( + function($extract_value, $extract_index) { return is_string($extract_value) ? $extract_value : "Column $extract_index"; }, + $extract, + array_keys($extract) + ); + fputcsv($out, $headerRow, ...$csvOptions); + $wroteHeader = true; + } + + $dataRow = []; + + // we use the provided $extractor to obtain the mapped values: + foreach ($extract as $column) { + if (is_callable($column)) { + $dataRow[] = $column($rowArray); + } elseif (is_string($column)) { + $dataRow[] = $rowArray[$column] ?? ''; + } else { + $dataRow[] = ''; + } + } + fputcsv($out, $dataRow, ...$csvOptions); + } else { + // there is no exctractor provided, we will take plain array keys as column names: + if (!$wroteHeader) { + fputcsv($out, array_keys($rowArray), ...$csvOptions); + $wroteHeader = true; + } + // there is no exctractor provided, we will take plain array values: + $rowValues = array_values($rowArray); + fputcsv($out, $rowValues, ...$csvOptions); + } + flush(); + } + $count = $results->count(); + $page++; + } while ($count === $chunkSize); + + fclose($out); + }); + + return $this->response + ->withType('text/csv') + ->withDownload($filename) + ->withBody($stream); + } +} diff --git a/idrocap_wa/src/Controller/ControllableObjectsController.php b/idrocap_wa/src/Controller/ControllableObjectsController.php new file mode 100644 index 0000000..708925d --- /dev/null +++ b/idrocap_wa/src/Controller/ControllableObjectsController.php @@ -0,0 +1,56 @@ +ControllableObjects->Attachments + ->find() + ->contain(['ControllableObjects' => ['Creator', 'Modifier', 'Locations']]) + ->where(['Attachments.container_controllable_object_id' => $co_id]); + + if(!empty($this->request->getQuery('tags'))) { + $tags = explode(',', $this->request->getQuery('tags')); + $attachments = $attachments + ->matching('Tags') + ->where(['Tags.code IN' => $tags]); + } + + $showPrivateColumn = $attachments->all()->filter(function ($attachment) { return $attachment->private == 1; })->count() > 0; + + if (!$this->logged_user->canHandleAttachmentsForControllableObject($this->ControllableObjects->get($co_id))) { + $attachments = $attachments->where(['Attachments.id < 0']); + } + + $this->paginate = [ + 'sortableFields' => ['Attachments.private', 'Attachments.original_file_name', 'Locations.description', 'Attachments.relevant', 'Attachments.original_file_size', 'Attachments.mimetype', 'Attachments.upload_date', 'Creator.surname'], + 'limit' => 10, + 'order' => [ + 'Attachments.upload_date' => 'DESC' + ], + ]; + + if ($this->request->getQuery('removecurrentfiles') !== null) { + $this->set('removecurrentfiles', $this->request->getQuery('removecurrentfiles')); + } + + $this->viewBuilder()->setLayout('ajax'); + $this->set('numberOfAttachments', $attachments->count()); + $this->set('attachments', $this->paginate($attachments)); + $this->set('showPrivateColumn', $showPrivateColumn); + } +} diff --git a/idrocap_wa/src/Controller/DashboardController.php b/idrocap_wa/src/Controller/DashboardController.php new file mode 100644 index 0000000..733b662 --- /dev/null +++ b/idrocap_wa/src/Controller/DashboardController.php @@ -0,0 +1,35 @@ +Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canViewContactsForActor($actor)) throw new ForbiddenException(__('Non hai i permessi per visualizzare i recapiti per {0}', $actor_type_description)); + + $mobile_phones = $this->Deliveries->MobilePhones->find() + ->contain(['MobilePhoneDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'mobile_phone')) { + $mobile_phones = $mobile_phones->map(function ($mobile_phone) { + $mobile_phone->value = "**************"; + return $mobile_phone; + }); + } + + $faxes = $this->Deliveries->Faxes->find() + ->contain(['FaxDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'fax')) { + $faxes = $faxes->map(function ($fax) { + $fax->value = "**************"; + return $fax; + }); + } + + $emails = $this->Deliveries->Emails->find() + ->contain(['EmailDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'email')) { + $emails = $emails->map(function ($email) { + $email->value = "**************"; + return $email; + }); + } + + $phones = $this->Deliveries->Phones->find() + ->contain(['PhoneDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'phone')) { + $phones = $phones->map(function ($phone) { + $phone->value = "**************"; + return $phone; + }); + } + + $telegram_chats = $this->Deliveries->TelegramChats->find() + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'telegram_chat')) { + $telegram_chats = $telegram_chats->map(function ($telegram_chat) { + $telegram_chat->value = "**************"; + return $telegram_chat; + }); + } + + $pecs = $this->Deliveries->Pecs->find() + ->contain(['PecDescriptions']) + ->matching('Deliveries') + ->where(['Deliveries.actor_id' => $actor_id]) + ->all(); + + if (!$this->logged_user->canViewContactsForActor($actor, 'pec')) { + $pecs = $pecs->map(function ($pec) { + $pec->value = "**************"; + return $pec; + }); + } + + $can_add_mobile_phone = $this->logged_user->canAddContactsForActor($actor, 'mobile_phone'); + $can_edit_mobile_phone = $this->logged_user->canEditContactsForActor($actor, 'mobile_phone'); + $can_delete_mobile_phone = $this->logged_user->canDeleteContactsForActor($actor, 'mobile_phone'); + $can_add_fax = $this->logged_user->canAddContactsForActor($actor, 'fax'); + $can_edit_fax = $this->logged_user->canEditContactsForActor($actor, 'fax'); + $can_delete_fax = $this->logged_user->canDeleteContactsForActor($actor, 'fax'); + $can_add_email = $this->logged_user->canAddContactsForActor($actor, 'email'); + $can_edit_email = $this->logged_user->canEditContactsForActor($actor, 'email'); + $can_delete_email = $this->logged_user->canDeleteContactsForActor($actor, 'email'); + $can_add_phone = $this->logged_user->canAddContactsForActor($actor, 'phone'); + $can_edit_phone = $this->logged_user->canEditContactsForActor($actor, 'phone'); + $can_delete_phone = $this->logged_user->canDeleteContactsForActor($actor, 'phone'); + $can_add_telegram_chat = $this->logged_user->canAddContactsForActor($actor, 'telegram_chat'); + $can_edit_telegram_chat = $this->logged_user->canEditContactsForActor($actor, 'telegram_chat'); + $can_delete_telegram_chat = $this->logged_user->canDeleteContactsForActor($actor, 'telegram_chat'); + $can_add_pec = $this->logged_user->canAddContactsForActor($actor, 'pec'); + $can_edit_pec = $this->logged_user->canEditContactsForActor($actor, 'pec'); + $can_delete_pec = $this->logged_user->canDeleteContactsForActor($actor, 'pec'); + + $this->set(compact('actor', 'mobile_phones', 'faxes', 'emails', 'phones', 'telegram_chats', 'pecs', 'can_add_mobile_phone', 'can_edit_mobile_phone', 'can_delete_mobile_phone', 'can_add_fax', 'can_edit_fax', 'can_delete_fax', 'can_add_email', 'can_edit_email', 'can_delete_email', 'can_add_phone', 'can_edit_phone', 'can_delete_phone', 'can_add_telegram_chat', 'can_edit_telegram_chat', 'can_delete_telegram_chat', 'can_add_pec', 'can_edit_pec', 'can_delete_pec')); + } + + /** + * delete + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $delivery = $this->Deliveries->get($id, contain: ['DeliveryTypes', 'MobilePhones' => ['MobilePhoneDescriptions'], 'Faxes' => ['FaxDescriptions'], 'Emails' => ['EmailDescriptions'], 'Phones' => ['PhoneDescriptions'], 'TelegramChats', 'Pecs' => ['PecDescriptions']]); + + $actor = $this->Deliveries->Actors->get($delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canDeleteContactsForActor($actor, $delivery->delivery_type->description)) throw new ForbiddenException(__('Non hai i permessi per eliminare i recapiti di questo tipo per {0}', $actor_type_description)); + + $contact_value = ""; + + switch ($delivery->delivery_type_id) { + case 1: + $contact_value = __('Cellulare ({0}): {1}', $delivery->mobile_phone->mobile_phone_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->mobile_phone->value : "**************"); + break; + case 2: + $contact_value = __('Fax ({0}): {1}', $delivery->fax->fax_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->fax->value: "**************"); + break; + case 3: + $contact_value = __('Email ({0}): {1}', $delivery->email->email_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->email->value: "**************"); + break; + case 4: + $contact_value = __('Telefono ({0}): {1}', $delivery->phone->phone_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->phone->value: "**************"); + break; + case 5: + $contact_value = __('Telegram Chat ID: {0}', $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->telegram_chat->value: "**************"); + break; + case 6: + $contact_value = __('PEC ({0}): {1}', $delivery->pec->pec_description->description, $this->logged_user->canViewContactsForActor($actor, $delivery->delivery_type->description) ? $delivery->pec->value: "**************"); + break; + default: + $contact_value = ""; + break; + } + + if ($this->Deliveries->delete($delivery)) { + $this->Flash->success(__('Il recapito "{0}" è stato cancellato con successo', $contact_value)); + } else { + $this->Flash->error(__('Errore durante la cancellazione del recapito {0}. Riprovare di nuovo.', $contact_value)); + } + + return $this->redirect(['action' => 'index', $delivery->actor_id]); + } +} diff --git a/idrocap_wa/src/Controller/DistrictsController.php b/idrocap_wa/src/Controller/DistrictsController.php new file mode 100644 index 0000000..61e2f39 --- /dev/null +++ b/idrocap_wa/src/Controller/DistrictsController.php @@ -0,0 +1,66 @@ +viewBuilder()->setClassName('Json'); + $conditions = []; + $provinceCode = $this->request->getQuery(ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::PROVINCE_CODE)); + $term = $this->request->getQuery("term"); + $codeReg = ProvinceDistrictFieldHelper::getCodeRegByRegion(Regions::SICILY); + $regCodField = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::REGION_CODE); + $provCodeField = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::PROVINCE_CODE); + $queryDistrictFieldName = ProvinceDistrictFieldHelper::forDistricts(ProvinceDistrictFields::DISTRICT_FIELD_NAME); + + if($codeReg) { + $conditions[$regCodField] = $codeReg; + } + + if (isset($provinceCode)) { + $conditions[$provCodeField] = $provinceCode; + } + + $query = $this->Districts->find(); + + if ($term) { + $query->where(function ($exp) use ($term, $queryDistrictFieldName) { + return $exp->like($queryDistrictFieldName, "%$term%"); + }); + } + + if (!empty($conditions)) { + $query->where($conditions); + } + + $district_field = ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::DISTRICT_FIELD_NAME); + $districts = $query->find('list', keyField: $district_field, valueField: $district_field)->toArray(); + + $this->set(compact('districts')); + $this->viewBuilder()->setOption('serialize', ['districts'])->setOption('jsonOptions', JSON_FORCE_OBJECT); + } +} diff --git a/idrocap_wa/src/Controller/EmailsController.php b/idrocap_wa/src/Controller/EmailsController.php new file mode 100644 index 0000000..8c5f63b --- /dev/null +++ b/idrocap_wa/src/Controller/EmailsController.php @@ -0,0 +1,78 @@ +Emails->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'email')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $email = $this->Emails->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 3, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $email = $this->Emails->patchEntity($email, $this->request->getData()); + if ($this->Emails->save($email)) { + $this->Flash->success(__('L\'Email è stata aggiunta con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta dell\'Email')); + } + $emailDescriptions = $this->Emails->EmailDescriptions->find('list'); + $this->set(compact('actor', 'email', 'emailDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $email = $this->Emails->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Emails->Deliveries->Actors->get($email->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'email')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $email = $this->Emails->patchEntity($email, $this->request->getData()); + if ($this->Emails->save($email)) { + $this->Flash->success(__('L\'Email è stata modificata con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $email->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica dell\'Email. Riprovare di nuovo')); + } + $emailDescriptions = $this->Emails->EmailDescriptions->find('list'); + $this->set(compact('actor', 'email', 'emailDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/ErrorController.php b/idrocap_wa/src/Controller/ErrorController.php new file mode 100644 index 0000000..d0fd7eb --- /dev/null +++ b/idrocap_wa/src/Controller/ErrorController.php @@ -0,0 +1,70 @@ +viewBuilder()->setTemplatePath('Error'); + } + + /** + * afterFilter callback. + * + * @param \Cake\Event\EventInterface $event Event. + * @return \Cake\Http\Response|null|void + */ + public function afterFilter(EventInterface $event) + { + } +} diff --git a/idrocap_wa/src/Controller/FaxesController.php b/idrocap_wa/src/Controller/FaxesController.php new file mode 100644 index 0000000..89bc206 --- /dev/null +++ b/idrocap_wa/src/Controller/FaxesController.php @@ -0,0 +1,78 @@ +Faxes->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'fax')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $fax = $this->Faxes->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 2, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $fax = $this->Faxes->patchEntity($fax, $this->request->getData()); + if ($this->Faxes->save($fax)) { + $this->Flash->success(__('Il Fax è stato aggiunto con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta del Fax')); + } + $faxDescriptions = $this->Faxes->FaxDescriptions->find('list'); + $this->set(compact('actor', 'fax', 'faxDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $fax = $this->Faxes->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Faxes->Deliveries->Actors->get($fax->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'fax')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $fax = $this->Faxes->patchEntity($fax, $this->request->getData()); + if ($this->Faxes->save($fax)) { + $this->Flash->success(__('Il Fax è stato modificato con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $fax->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica del Fax. Riprovare di nuovo')); + } + $faxDescriptions = $this->Faxes->FaxDescriptions->find('list'); + $this->set(compact('actor', 'fax', 'faxDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/FiltersController.php b/idrocap_wa/src/Controller/FiltersController.php new file mode 100644 index 0000000..ad09547 --- /dev/null +++ b/idrocap_wa/src/Controller/FiltersController.php @@ -0,0 +1,25 @@ +set('filter_id', $filter_id); + $this->viewBuilder()->setLayout('ajax'); + } +} diff --git a/idrocap_wa/src/Controller/GroupsController.php b/idrocap_wa/src/Controller/GroupsController.php new file mode 100644 index 0000000..d7632e5 --- /dev/null +++ b/idrocap_wa/src/Controller/GroupsController.php @@ -0,0 +1,236 @@ +logged_user->hasCapability('configuration.groups.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $groups = $this->Groups->find() + ->contain(['Actors', 'ChildGroups']); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $groups = $groups + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('configuration.groups.edit'); + $row->can_delete = $this->logged_user->hasCapability('configuration.groups.delete'); + $row->child_groups_csv = collection($row->child_groups)->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group->description : ($csv . ', ' . $child_group->description); }, ''); + return $row; + }); + }); + } + + $this->paginate = [ + 'sortableFields' => ['description', 'is_default'], + ]; + + $this->set('groups', $this->getRequest()->is(['json', 'xml', 'csv']) ? $groups : $this->paginate($groups)); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('configuration.groups.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Descrizione'), + __('Profilo Default'), + __('Profili Associati'), + ]; + $extract = [ + 'description', + function (array $row) { + return $row['is_default'] ? __('SI') : __('NO'); + }, + function (array $row) { + return collection($row['child_groups'])->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group['description'] : ($csv . ', ' . $child_group['description']); }, ''); + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("profiles_$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'groups'); + } + + /** + * view + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->get($id, contain: ['Actors', 'ChildGroups']); + + $group->can_handle_capabilities = $this->logged_user->hasCapability('configuration.groups.capabilities'); + $group->can_edit = $this->logged_user->hasCapability('configuration.groups.edit'); + $group->can_delete = $this->logged_user->hasCapability('configuration.groups.delete'); + $group->child_groups_csv = collection($group->child_groups)->reduce(function ($csv, $child_group) { return empty($csv) ? $child_group->description : ($csv . ', ' . $child_group->description); }, ''); + + $this->set(compact('group')); + $this->viewBuilder()->setOption('serialize', 'group'); + } + + /** + * add + * + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability('configuration.groups.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->newEmptyEntity(); + if ($this->request->is('post')) { + $group = $this->Groups->patchEntity($group, $this->request->getData()); + if ($this->Groups->save($group)) { + $this->Flash->success(__('Profilo Utente creato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la creazione del Profilo Utente')); + } + $child_groups = $this->fetchTable('Groups')->find('list')->contain(['Actors'])->order(['Groups.description' => 'ASC']); + $this->set(compact('group')); + $this->set(compact('child_groups')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.edit')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->get($id, contain: ['Actors', 'ChildGroups']); + if ($this->request->is(['patch', 'post', 'put'])) { + $group = $this->Groups->patchEntity($group, $this->request->getData()); + if ($this->Groups->save($group)) { + $this->Flash->success(__('Profilo Utente "{0}" modificato con successo.', $group->description)); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la modifica del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); + } + $child_groups = $this->fetchTable('Groups')->find('list')->contain(['Actors'])->order(['Groups.description' => 'ASC']); + $this->set(compact('group')); + $this->set(compact('child_groups')); + } + + /** + * delete + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.delete')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $group = $this->Groups->get($id, contain: ['Actors']); + + if ($this->Groups->Actors->delete($group->actor)) { + $this->Flash->success(__('Il Profilo Utente "{0}" è stato cancellato con successo', $group->description)); + } else { + $errors = $group->actor->getErrors(); + if (isset($errors['is_editable']['checkGroupIsEditable'])) { + $errorMessage = $errors['is_editable']['checkGroupIsEditable']; + $this->Flash->error($errorMessage); + } else { + $this->Flash->error(__('Errore durante la cancellazione del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); + } + } + + return $this->redirect(['action' => 'index']); + } + + /** + * handleCapabilities + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function handleCapabilities($id = null) + { + if (!$this->logged_user->hasCapability('configuration.groups.capabilities')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $group = $this->Groups->get($id, contain: ['Actors']); + + $group_capability_ids = $this->Groups->Capabilities->find() + ->select(['id']) + ->matching('Groups') + ->where(['Groups.id' => $id]); + + if (!$this->logged_user->sys_admin) { + $group_capability_ids = $group_capability_ids + ->where(['Capabilities.is_configurable' => 1]); + } + + $group_capability_ids = $group_capability_ids + ->distinct() + ->all() + ->extract('id') + ->toArray(); + + if ($this->request->is(['patch', 'post', 'put'])) { + $group = $this->Groups->patchEntity($group, $this->request->getData(), ['group_id' => $group->id]); + if ($this->Groups->save($group)) { + $this->Flash->success(__('Profilo Utente "{0}" modificato con successo.', $group->description)); + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la modifica del Profilo Utente "{0}". Riprovare di nuovo.', $group->description)); + } + + $capability_groups = $this->Groups->Capabilities->CapabilityGroups->find() + ->contain(['Capabilities' => function ($q) { + if (!$this->logged_user->sys_admin) { + $q->where(['Capabilities.is_configurable' => 1]); + } + return $q->order(['Capabilities.capability_group_id' => 'ASC', 'Capabilities.priority_group_id' => 'ASC', 'Capabilities.priority' => 'ASC', 'Capabilities.description']); + }]) + ->order(['CapabilityGroups.description' => 'ASC']); + + $this->set(compact('group', 'group_capability_ids', 'capability_groups')); + $this->viewBuilder()->setOption('serialize', 'group'); + } +} diff --git a/idrocap_wa/src/Controller/MapsController.php b/idrocap_wa/src/Controller/MapsController.php new file mode 100644 index 0000000..c2987da --- /dev/null +++ b/idrocap_wa/src/Controller/MapsController.php @@ -0,0 +1,187 @@ +'], ['%20', '%3E'], $query_parameters); + $url .= $query_parameters; + $http = new Client(); + $response = $http->get($url, [], [ + 'auth' => ['username' => Configure::read('App.geoserverUsername'), 'password' => Configure::read('App.geoserverPassword')] + ]); + return $response->getStringBody(); + } + + /** + * get_location_attributes + * + * @param String $lat + * @param String $lon + * @return ?Array + */ + private function get_location_attributes(String $lat, String $lon): ?Array { + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; + $location = $this->fetchTable('Locations')->newEntity([ + 'feature_collection' => $feature_collection, + ]); + $lar = new LocationAttributesRetriever($location); + $lar_result = $lar->retrieve()[0] ?? null; + return $lar_result; + } + + /** + * get_matching_geo_resources + * + * @param String $lat + * @param String $lon + * @return ?Array + */ + private function get_matching_geo_resources(String $lat, String $lon): ?Array { + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; + $matching_geo_resources = []; + // inizializziamo l'array $mapped_fields con un array associativo con KEY id del campo e VALUE '': + $mapped_fields = collection($this->geo_resources)->reduce(function ($acc, $geo_resource) { + return array_merge($acc, array_fill_keys(array_values($geo_resource['attributes_fields']), '')); + }, []); + + foreach ($this->geo_resources as $geo_resource) { + if (isset($geo_resource['external']) && is_bool($geo_resource['external']) && $geo_resource['external']) { + $grar = new ExtGeoResourceAttributesRetriever($geo_resource['url'], $geo_resource['lon_parameter_name'], $geo_resource['lat_parameter_name']); + $grar_result = $grar->retrieve($lon, $lat); + if (isset($grar_result)) { + // scremiamo il risultato proveniente dal servizio esterno considerando solo gli attributi che ci interessano: + $grar_result = array_intersect_key($grar_result, $geo_resource['attributes_fields']); + $matching_geo_resources[$geo_resource['url']] = $grar_result; + foreach ($grar_result as $attribute_name => $attribute_value) { + $mapped_fields[$geo_resource['attributes_fields'][$attribute_name]] = $attribute_value; + } + } + } else { + $grar = new IntGeoResourceAttributesRetriever($geo_resource['table_name'], $geo_resource['geometry_name'], array_keys($geo_resource['attributes_fields'])); + $grar_result = $grar->retrieve($feature_collection)[0] ?? null; + if (isset($grar_result)) { + $matching_geo_resources[$geo_resource['table_name']] = $grar_result; + foreach ($grar_result as $attribute_name => $attribute_value) { + $mapped_fields[$geo_resource['attributes_fields'][$attribute_name]] = $attribute_value; + } + } + } + } + return ['matching_geo_resources' => $matching_geo_resources, 'mapped_fields' => $mapped_fields]; + } + + /** + * map_geocoding_result_content + * + * @param Array $content + * @return Array + */ + private function map_geocoding_result_content(Array $content): Array { + $array_content = explode(", ", $content['display_name'] ?? ''); + $index_cursor = count($array_content) - 1; + if ($index_cursor > 0) $nation = $array_content[$index_cursor--]; + if ($index_cursor > 0) $cap = (Int)$array_content[$index_cursor] > 0 ? $array_content[$index_cursor--] : ''; + if ($index_cursor > 0) $region = $array_content[$index_cursor--]; + if ($index_cursor > 0) $province = $array_content[$index_cursor--]; + if ($index_cursor > 0) $district = $array_content[$index_cursor--]; + $address = $content['namedetails']['name'] ?? ''; + $description = $content['display_name'] ?? ''; + $lat = $content['lat'] ?? ''; + $lon = $content['lon'] ?? ''; + return ['nation' => $nation ?? '', 'cap' => $cap ?? '', 'region' => $region ?? '', 'province' => $province ?? '', 'district' => $district ?? '', 'address' => $address, 'lat' => $lat, 'lon' => $lon, 'description' => $description]; + } + + /** + * index + * + * @return \Cake\Http\Response + */ + public function index () { + if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); + } + + /** + * getWfs + * + * @return Response + */ + public function getWfs(): Response { + if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); + $response = $this->geoserver_proxy($this->request->getUri()->getQuery()); + return $this->getResponse()->withStringBody($response)->withType("application/json"); + } + + /** + * geocode + * + * @throws BadRequestException + * @throws NotFoundException + * @return Response + */ + public function geocode(): Response { + if(!$this->logged_user->hasCapability(['confiiguration.maps.view'])) throw new BadRequestException(__('Non hai i permessi')); + // geo_resources, se presente, contiene le info per mappare campi aggiuntivi con attributi di + // una o + geo-risorse in base a dove il punto specificato ricade: + $geo_resources = json_decode($this->request->getQuery('geo_resources') ?? '', true); + if ($geo_resources !== null && is_array($geo_resources) && count($geo_resources) > 0) $this->geo_resources = $geo_resources; + + if ($this->request->getQuery('address') === null) throw new BadRequestException('geocode error: invalid address'); + + $separator = null; + + if (count(collection(explode(" ", $this->request->getQuery('address')))->filter(function ($part) { return is_numeric(trim($part)); })->toArray()) === 2) { + $separator = " "; + } + + if (count(collection(explode(",", $this->request->getQuery('address')))->filter(function ($part) { return is_numeric(trim($part)); })->toArray()) === 2) { + $separator = ","; + } + + if ($separator !== null) { + $address_parts = explode($separator, $this->request->getQuery('address')); + $lat = $address_parts[0] > $address_parts[1] ? $address_parts[0] : $address_parts[1]; + $lon = $address_parts[0] > $address_parts[1] ? $address_parts[1] : $address_parts[0]; + $feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[' . $lon . ',' . $lat . ']},"properties":null}]}'; + if (!GeoValidation::isValidGeometry(json_decode($feature_collection))) throw new BadRequestException('invalid coordinates or out of boundary!'); + $reverse_geocoding = Geocoding::performGeocoding('reverse', ['format' => 'json', 'namedetails' => '1', 'lat' => $lat, 'lon' => $lon]); + if (!empty($reverse_geocoding['contents'])) { + $mapped_geocoding_result_content = $this->map_geocoding_result_content($reverse_geocoding['contents']); + } + $lar_result = $this->get_location_attributes($lat, $lon); + $content = ['geo_resources' => $this->get_matching_geo_resources($lat, $lon), 'nation' => $mapped_geocoding_result_content['nation'] ?? '', 'cap' => $mapped_geocoding_result_content['cap'] ?? '', 'region' => $lar_result['region'] ?? $mapped_geocoding_result_content['region'] ?? '', 'province' => $lar_result['county_name'] ?? $mapped_geocoding_result_content['province'] ?? '', 'district_code' => $lar_result['district_code'] ?? '', 'district' => $lar_result['district_name'] ?? $mapped_geocoding_result_content['district'] ?? '', 'address' => $mapped_geocoding_result_content['address'] ?? '', 'lat' => $lat, 'lon' => $lon, 'description' => !empty($mapped_geocoding_result_content['description']) ? $mapped_geocoding_result_content['description'] : __('Punto alle coordinate (EPSG:4326) Latitudine: {0}, Longitudine: {1}', $lat, $lon)]; + return $this->getResponse()->withStringBody(json_encode($content))->withType("application/json"); + } + + $geocoding = Geocoding::performGeocoding('search', ['format' => 'json', 'namedetails' => '1', 'q' => $this->request->getQuery('address')]); + if (empty($geocoding['contents'])) throw new NotFoundException('geocode error: no contents'); + return $this->getResponse()->withStringBody(json_encode($geocoding['contents']))->withType("application/json"); + } +} diff --git a/idrocap_wa/src/Controller/MobilePhonesController.php b/idrocap_wa/src/Controller/MobilePhonesController.php new file mode 100644 index 0000000..b1fca0f --- /dev/null +++ b/idrocap_wa/src/Controller/MobilePhonesController.php @@ -0,0 +1,79 @@ +MobilePhones->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'mobile_phone')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $mobilePhone = $this->MobilePhones->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 1, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $mobilePhone = $this->MobilePhones->patchEntity($mobilePhone, $this->request->getData()); + if ($this->MobilePhones->save($mobilePhone)) { + $this->Flash->success(__('Il Cellulare è stato aggiunto con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta del Cellulare')); + } + $mobilePhoneDescriptions = $this->MobilePhones->MobilePhoneDescriptions->find('list'); + $this->set(compact('actor', 'mobilePhone', 'mobilePhoneDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $mobilePhone = $this->MobilePhones->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->MobilePhones->Deliveries->Actors->get($mobilePhone->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'mobile_phone')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $mobilePhone = $this->MobilePhones->patchEntity($mobilePhone, $this->request->getData()); + if ($this->MobilePhones->save($mobilePhone)) { + $this->Flash->success(__('Il Cellulare è stato modificato con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $mobilePhone->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica del Cellulare. Riprovare di nuovo')); + } + $mobilePhoneDescriptions = $this->MobilePhones->MobilePhoneDescriptions->find('list'); + $this->set(compact('actor', 'mobilePhone', 'mobilePhoneDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/NotificationsController.php b/idrocap_wa/src/Controller/NotificationsController.php new file mode 100644 index 0000000..800a842 --- /dev/null +++ b/idrocap_wa/src/Controller/NotificationsController.php @@ -0,0 +1,97 @@ +fetchTable('Notifications') + ->find() + ->contain('NotificationTypes') + ->where(['Notifications.user_id' => $this->logged_user->id, 'Notifications.read_by_user IS NULL']) + ->order(['Notifications.created' => 'DESC']) + ->all() + ->reduce(function ($acc, $user_notification) { + $notification_info = json_decode($user_notification->info); + $body = strlen($notification_info->body) > 200 ? substr($notification_info->body, 0, 197) . '...' : $notification_info->body; + $icon = $user_notification->notification_type->icon ?? 'bell'; + $time_ago = (new DateTime($user_notification->created))->timeAgoInWords(); + $acc[] = ['id' => $user_notification->id, 'icon' => $icon, 'title' => $notification_info->title, 'body' => $body, 'time_ago' => $time_ago]; + return $acc; + }, []); + } + + /** + * readAll + * + * @return \Cake\Http\Response + */ + public function readAll() + { + $this->fetchTable('Notifications')->updateAll(['read_by_user' => new DateTime()], ['user_id' => $this->logged_user->id, 'read_by_user IS NULL']); + $user_notifications = $this->getUserNotifications(); + $this->set('user_notifications', $user_notifications); + $this->viewBuilder()->setOption('serialize', 'user_notifications')->setLayout('ajax'); + } + + /** + * testAll + * + * @return \Cake\Http\Response + */ + public function testAll() + { + $this->request->allowMethod(['post']); + $this->sendNotifications(null, 'test_all', []); + return $this->redirect('/'); + } + + /** + * view + * + * @todo recuperare la specializzazione del CO e fare redirect alla view dell'oggetto specifico! + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id) + { + $notification = $this->fetchTable('Notifications')->get($id); + $notification->read_by_user = new DateTime(); + + if (!$this->fetchTable('Notifications')->save($notification)) { + $this->Flash->error(__('Errore durante la cancellazione della notifica')); + } + + $notification_info = json_decode($notification->info); + $link = !empty($notification_info->link) ? $notification_info->link : '/'; + return $this->redirect($link); + } + + public function index() + { + $user_notifications = $this->getUserNotifications(); + $this->set('user_notifications', $user_notifications); + $this->viewBuilder()->setOption('serialize', 'user_notifications')->setLayout('ajax'); + } +} diff --git a/idrocap_wa/src/Controller/OrganisationsController.php b/idrocap_wa/src/Controller/OrganisationsController.php new file mode 100644 index 0000000..5b156b9 --- /dev/null +++ b/idrocap_wa/src/Controller/OrganisationsController.php @@ -0,0 +1,204 @@ +logged_user->hasCapability('configuration.organisations.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisations = $this->Organisations->find() + ->contain(['OrganisationTypes', 'Actors']); + + $this->set('total_organisations', $organisations->count()); + // applichiamo gli eventuali filtri presenti: + $organisations = $this->applyFilters($organisations); + $this->set('filtered_organisations', $organisations->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $organisations = $organisations + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->organisation_id == $row->id || $this->logged_user->hasCapability('configuration.organisations.edit'); + $row->can_delete = $this->logged_user->organisation_id == $row->id || $this->logged_user->hasCapability('configuration.organisations.delete'); + return $row; + }); + }); + } + + $this->paginate = [ + 'sortableFields' => ['Actors.description', 'acronym', 'OrganisationTypes.description', 'address', 'district', 'cap', 'province'], + ]; + + $this->set('organisations', $this->getRequest()->is(['json', 'xml', 'csv']) ? $organisations : $this->paginate($organisations)); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('configuration.organisations.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Descrizione'), + __('Acronimo'), + __('Tipologia'), + __('Indirizzo'), + __('Comune'), + __('CAP'), + __('Provincia'), + __('Recapiti'), + ]; + $extract = [ + function (array $row) { + return $row['actor']['description']; + }, + 'acronym', + function (array $row) { + return $row['organisation_type']['description']; + }, + 'address', + 'district', + 'cap', + 'province', + function (array $row) { + return $row['actor']['contacts']; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("organisations_$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'organisations'); + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id = null) + { + if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.read')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisation = $this->Organisations->get($id, contain: ['ControllableObjectInterfaces', 'OrganisationTypes', 'Actors']); + + $organisation->can_handle_contacts = $this->logged_user->canViewContactsForActor($this->Organisations->Actors->get($organisation->actor_id, contain: ['Organisations'])); + $organisation->can_edit = $this->logged_user->organisation_id == $id || $this->logged_user->hasCapability('configuration.organisations.edit'); + $organisation->can_delete = $this->logged_user->organisation_id == $id || $this->logged_user->hasCapability('configuration.organisations.delete'); + + $organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); + $this->set(compact('organisation', 'organisationTypes')); + } + + /** + * add + * + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability('configuration.organisations.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisation = $this->Organisations->newEmptyEntity(); + if ($this->request->is('post')) { + $organisation = $this->Organisations->patchEntity($organisation, $this->request->getData()); + if ($this->Organisations->save($organisation)) { + $this->Flash->success(__('Organizzazione creata con successo.')); + + return $this->redirect(['action' => 'index']); + } + $errorMessage = $organisation->getError('attachment')[0] ?? ''; + $this->Flash->error(__('Errore durante la creazione dell\'organizzazione. ' . $errorMessage)); + } + $organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); + $this->set(compact('organisation', 'organisationTypes')); + } + + /** + * edit + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.edit')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $organisation = $this->Organisations->get($id, contain: ['Actors', 'ControllableObjectInterfaces', 'OrganisationTypes']); + if ($this->request->is(['patch', 'post', 'put'])) { + $organisation = $this->Organisations->patchEntity($organisation, $this->request->getData()); + if ($this->Organisations->save($organisation)) { + $this->Flash->success(__('Organizzazione "{0}" modificata con successo.', $organisation->actor->description)); + + return $this->redirect(['action' => 'index']); + } + $errMessage = $organisation->getError('attachment')[0] ?? ''; + $this->Flash->error(__('Errore durante la modifica dell\'organizzazione "{0}". Riprovare di nuovo. ', $organisation->actor->description) . $errMessage); + } + $organisationTypes = $this->Organisations->OrganisationTypes->find('list')->order(['OrganisationTypes.description' => 'ASC']); + $this->set(compact('organisation', 'organisationTypes')); + } + + /** + * delete + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + if ($this->logged_user->organisation_id != $id && !$this->logged_user->hasCapability('configuration.organisations.delete')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $organisation = $this->Organisations->get($id, contain: ['Actors']); + + // controlliamo se il type è cittadini e preveniamo la possibilità di delete. + if($organisation->organisation_type_id === 7) { + $this->Flash->error(__('Impossibile eliminare l\'organizzazione "{0}".', $organisation->actor->description)); + return $this->redirect(['action' => 'index']); + } + + $are_there_users_in_this_org = $this->fetchTable('Users')->find()->where(['Users.organisation_id' => $id])->count(); + if ($are_there_users_in_this_org > 0) { + $this->Flash->error(__('Impossibile eliminare l\'organizzazione "{0}". Ci sono {1} utenti collegati ad essa.', $organisation->actor->description, $are_there_users_in_this_org)); + return $this->redirect(['action' => 'index']); + } + + if ($this->Organisations->Actors->delete($organisation->actor)) { + $this->Flash->success(__('L\'organizzazione "{0}" è stata cancellata con successo', $organisation->actor->description)); + } else { + $this->Flash->error(__('Errore durante la cancellazione dell\'organizzazione "{0}". Riprovare di nuovo.', $organisation->actor->description)); + } + + return $this->redirect(['action' => 'index']); + } +} diff --git a/idrocap_wa/src/Controller/PecsController.php b/idrocap_wa/src/Controller/PecsController.php new file mode 100644 index 0000000..d3bc5f5 --- /dev/null +++ b/idrocap_wa/src/Controller/PecsController.php @@ -0,0 +1,78 @@ +Pecs->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'pec')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $pec = $this->Pecs->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 6, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $pec = $this->Pecs->patchEntity($pec, $this->request->getData()); + if ($this->Pecs->save($pec)) { + $this->Flash->success(__('La PEC è stata aggiunta con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta della PEC')); + } + $pecDescriptions = $this->Pecs->PecDescriptions->find('list'); + $this->set(compact('actor', 'pec', 'pecDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $pec = $this->Pecs->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Pecs->Deliveries->Actors->get($pec->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'pec')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $pec = $this->Pecs->patchEntity($pec, $this->request->getData()); + if ($this->Pecs->save($pec)) { + $this->Flash->success(__('La PEC è stata modificata con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $pec->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica della PEC. Riprovare di nuovo')); + } + $pecDescriptions = $this->Pecs->PecDescriptions->find('list'); + $this->set(compact('actor', 'pec', 'pecDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/PhonesController.php b/idrocap_wa/src/Controller/PhonesController.php new file mode 100644 index 0000000..add984c --- /dev/null +++ b/idrocap_wa/src/Controller/PhonesController.php @@ -0,0 +1,78 @@ +Phones->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'phone')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $phone = $this->Phones->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 4, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $phone = $this->Phones->patchEntity($phone, $this->request->getData()); + if ($this->Phones->save($phone)) { + $this->Flash->success(__('Il Telefono è stato aggiunto con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta del Telefono')); + } + $phoneDescriptions = $this->Phones->PhoneDescriptions->find('list'); + $this->set(compact('actor', 'phone', 'phoneDescriptions')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $phone = $this->Phones->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->Phones->Deliveries->Actors->get($phone->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'phone')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $phone = $this->Phones->patchEntity($phone, $this->request->getData()); + if ($this->Phones->save($phone)) { + $this->Flash->success(__('Il Telefono è stato modificato con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $phone->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica del Telefono. Riprovare di nuovo')); + } + $phoneDescriptions = $this->Phones->PhoneDescriptions->find('list'); + $this->set(compact('actor', 'phone', 'phoneDescriptions')); + } +} diff --git a/idrocap_wa/src/Controller/PrivacyController.php b/idrocap_wa/src/Controller/PrivacyController.php new file mode 100644 index 0000000..6ff81f6 --- /dev/null +++ b/idrocap_wa/src/Controller/PrivacyController.php @@ -0,0 +1,174 @@ +Authentication->allowUnauthenticated(['view_public']); + } + + /** + * Index method + * + * @return \Cake\Http\Response|null|void Renders view + */ + public function view_public() + { + $privacy = $this->Privacy->findPrivacy(); + $this->viewBuilder()->setLayout('view_public'); + $this->set(compact('privacy')); + } + + /** + * View method + * + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view() + { + $breadcrumbs = $this->retrieveBreadcrumbs('view'); + $privacy = $this->Privacy->findPrivacy(); + $this->set(compact('privacy', 'breadcrumbs')); + } + + /** + * Edit method + * + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit() + { + if (!$this->logged_user->hasCapability(['configuration.privacy.edit'])) { + throw new ForbiddenException(__('Non hai i permessi necessari')); + } + + $breadcrumbs = $this->retrieveBreadcrumbs('edit'); + $privacy = $this->Privacy->findPrivacy(); + if ($this->request->is(['patch', 'post', 'put'])) { + $privacy = $this->Privacy->patchEntity($privacy, $this->request->getData()); + try { + $connection = ConnectionManager::get('default'); + $connection->begin(); + if ($this->Privacy->save($privacy)) { + $this->Privacy->PrivacyUsers->deleteAll(['privacy_id' => $privacy->id]); + $connection->commit(); + $this->Flash->success(__('La privacy è stata salvata con successo.')); + } else { + $connection->rollback(); + $this->Flash->error(__('La privacy non è stata salvata. Riprova, per favore.')); + } + } catch(Exception $e) { + $connection->rollback(); + $this->Flash->error(__('Errore. La privacy non è stata salvata.')); + } + } + $this->set(compact('privacy', 'breadcrumbs')); + } + + public function accept_privacy() + { + $hasConsent = $this->Privacy->PrivacyUsers->hasConsent($this->logged_user->id); + if ($hasConsent) { + $this->Flash->error(__('Hai già accettato la privacy.')); + return $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); + } + $breadcrumbs = $this->retrieveBreadcrumbs('accept_privacy'); + $privacy = $this->Privacy->findPrivacy(); + if (!$privacy) { + $this->Flash->error(__('La privacy non è disponibile.')); + return $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); + } + + if ($this->request->is(['post', 'put', 'patch'])) { + if ($this->Privacy->PrivacyUsers->saveConsent($this->logged_user->id, $privacy->id)) { + $this->Flash->success(__('La privacy è stata accettata con successo.')); + $this->redirect(['controller' => 'Dashboard', 'action' => 'index']); + } else { + $this->Flash->error(__('Errore. La privacy non è stata accettata.')); + } + } + $this->set(compact('privacy', 'breadcrumbs')); + } + + private function retrieveBreadcrumbs(string $action): array + { + $breadcrumbs = [ + 'edit' => [ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Privacy'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Modifica privacy'), + 'icon' => 'fa fa-pencil-alt', + ], + ], + 'view' => + [ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Privacy'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Visualizza privacy'), + 'icon' => 'fa fa-info', + ], + ], + 'accept_privacy' => [ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Privacy'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Visualizzazione privacy'), + 'icon' => 'fa fa-info', + ], + ] + ]; + + return $breadcrumbs[$action] ?? []; + } +} diff --git a/idrocap_wa/src/Controller/TagsController.php b/idrocap_wa/src/Controller/TagsController.php new file mode 100644 index 0000000..17905dc --- /dev/null +++ b/idrocap_wa/src/Controller/TagsController.php @@ -0,0 +1,91 @@ +logged_user->hasCapability(['configuration.tags.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tags = $this->Tags->find()->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('configuration.tags.edit'); + $row->can_view = $this->logged_user->hasCapability('configuration.tags.disable'); + return $row; + }); + }); + $tags = $this->paginate($tags); + $this->set(compact('tags')); + } + + /** + * View method + * + * @param string|null $id Tag id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability(['configuration.tags.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tag = $this->Tags->get($id); + $this->set(compact('tag')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + if (!$this->logged_user->hasCapability(['configuration.tags.add'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tag = $this->Tags->newEmptyEntity(); + if ($this->request->is('post')) { + $tag = $this->Tags->patchEntity($tag, $this->request->getData()); + if ($this->Tags->save($tag, ['associated' => ['ControllableObjects']])) { + $this->Flash->success(__('Il nuovo tag è stato creato')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore nella creazione del nuovo tag.') . json_encode($tag->getErrors())); + } + $this->set(compact('tag')); + } + + /** + * Edit method + * + * @param string|null $id Tag id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + if (!$this->logged_user->hasCapability(['configuration.tags.edit'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $tag = $this->Tags->find()->contain(['ControllableObjects'])->where(['Tags.id' => $id])->first(); + if ($this->request->is(['patch', 'post', 'put'])) { + $tag = $this->Tags->patchEntity($tag, $this->request->getData(), ['filename_as_tag' => true, 'associated' => ['ControllableObjects' => ['associated' => ['Attachments']]]]); + if ($this->Tags->save($tag)) { + $this->Flash->success(__('Il tag è stato salvato.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante il salvataggio del tag.') . json_encode($tag->getErrors())); + } + $this->set(compact('tag')); + } +} diff --git a/idrocap_wa/src/Controller/TelegramChatsController.php b/idrocap_wa/src/Controller/TelegramChatsController.php new file mode 100644 index 0000000..01ac143 --- /dev/null +++ b/idrocap_wa/src/Controller/TelegramChatsController.php @@ -0,0 +1,76 @@ +TelegramChats->Deliveries->Actors->get($actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canAddContactsForActor($actor, 'telegram_chat')) throw new ForbiddenException(__('Non hai i permessi per aggiungere i recapiti di questo tipo per {0}', $actor_type_description)); + + $telegram_chat = $this->TelegramChats->newEntity([ + 'delivery' => [ + 'actor_id' => $actor_id, + 'delivery_type_id' => 5, + ], + ], ['validate' => false]); + + if ($this->request->is('post')) { + $telegram_chat = $this->TelegramChats->patchEntity($telegram_chat, $this->request->getData()); + if ($this->TelegramChats->save($telegram_chat)) { + $this->Flash->success(__('La Chat Telegram è stata aggiunta con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $actor_id]); + } + $this->Flash->error(__('Errore durante l\'aggiunta della Chat Telegram')); + } + $this->set(compact('actor', 'telegram_chat')); + } + + /** + * edit + * + * @param Int $id + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + $telegram_chat = $this->TelegramChats->get($id, contain: ['Deliveries' => ['Actors' => ['ActorTypes']]]); + + $actor = $this->TelegramChats->Deliveries->Actors->get($telegram_chat->delivery->actor_id, contain: ['ActorTypes', 'Organisations', 'Users']); + // se arriviamo in questa pagina con un actor_id non di tipo "organizzazione" o "utente": + if (!in_array($actor->actor_type_id, [1,5])) throw new ForbiddenException(__('Gestione recapiti non prevista per questa tipologia di oggetto')); + $actor_type_description = $actor->actor_type_id == 1 ? __('questa organizzazione') : __('questo utente'); + if (!$this->logged_user->canEditContactsForActor($actor, 'telegram_chat')) throw new ForbiddenException(__('Non hai i permessi per modificare i recapiti di questo tipo per {0}', $actor_type_description)); + + if ($this->request->is(['patch', 'post', 'put'])) { + $telegram_chat = $this->TelegramChats->patchEntity($telegram_chat, $this->request->getData()); + if ($this->TelegramChats->save($telegram_chat)) { + $this->Flash->success(__('La Chat Telegram è stata modificata con successo.')); + + return $this->redirect(['controller' => 'Deliveries', 'action' => 'index', $telegram_chat->delivery->actor_id]); + } + $this->Flash->error(__('Errore durante la modifica della Chat Telegram. Riprovare di nuovo')); + } + $this->set(compact('actor', 'telegram_chat')); + } +} diff --git a/idrocap_wa/src/Controller/UsersController.php b/idrocap_wa/src/Controller/UsersController.php new file mode 100644 index 0000000..ec1b375 --- /dev/null +++ b/idrocap_wa/src/Controller/UsersController.php @@ -0,0 +1,624 @@ +Authentication->allowUnauthenticated(['logout', 'login', 'login_oidc', 'login_oidc_authenticated', 'passwordRecovery', 'chooseNewPassword', 'oneTimePassword', 'add_citizen', 'verify_citizen']); + } + + public function viewClasses(): array + { + return [JsonView::class, CustomCsvView::class]; + } + + public function login_oidc() + { + OpenIdConnectClient::authorize( + Configure::read('App.oidc.authUrl'), + Configure::read('App.oidc.clientId'), + Configure::read('App.oidc.scopes'), + Configure::read('App.oidc.redirectUri') + ); + } + + public function login_oidc_authenticated() + { + try { + $access_token = OpenIdConnectClient::get_access_token( + Configure::read('App.oidc.tokenUrl'), + Configure::read('App.oidc.issuer'), + Configure::read('App.oidc.clientId'), + Configure::read('App.oidc.clientSecret'), + Configure::read('App.oidc.redirectUri') + ); + $userinfo = OpenIdConnectClient::get_user_info(Configure::read('App.oidc.userinfoUrl'), Configure::read('App.oidc.userinfo_claim_key'), $access_token); + $userinfo_claim_value = $userinfo[Configure::read('App.oidc.userinfo_claim_key')]; + $user = $this->Users->find()->where(['Users.' . Configure::read('App.oidc.usermodel_matching_attribute') => $userinfo_claim_value]); + if ($user->count() > 1) throw new \Exception(__('Non è stato possibile identificare in maniera univoca l\'utente in base all\'attributo \' {0} \' ricevuto dal provider', Configure::read('App.oidc.userinfo_claim_key'))); + $user = $user->first(); + $isUserVerified = $user?->is_verified ?? false; + if ($user && $isUserVerified) { + $this->Authentication->setIdentity($user); + } else { + if (!$user) { + $citizenRegistrationDTO = (new \App\WGS\Utils\Dto\Users\CitizenRegistrationDTO()) + ->setShowAlert(true) + // attenzione!!!!!! se $userinfo_claim_value NON COINCIDE CON IL CF, NON FUNZIONA + !!!!!!!!!!!!!!!!!!!!!!!!!! + ->setFiscalCode($userinfo[Configure::read('App.oidc.userinfo_claim_key')] ?? '') + ->setName($userinfo['given_name'] ?? '') + ->setSurname($userinfo['family_name'] ?? '') + ->setGender($userinfo['gender'] ?? '') + ->setBirthdate($userinfo['birthdate'] ?? ''); + $this->request->getSession()->write('showCitizenRegistration', $citizenRegistrationDTO); + $errorMessage = __('Errore durante l\'autenticazione mediante {0} "Utente non trovato". Riprovare di nuovo o utilizzare le credenziali di accesso', Configure::read('App.oidc.idp_name', 'OpenID Connect')); + } else if ($user && !$isUserVerified) { + $errorMessage = __('Utente non verificato. Controlla la tua email per completare la verifica.'); + } + $this->Flash->error($errorMessage); + } + return $this->redirect('/'); + } catch (\Exception $e) { + $this->Flash->error(__('Errore durante l\'autenticazione mediante {0} "{1}". Riprovare di nuovo o utilizzare le credenziali di accesso', Configure::read('App.oidc.idp_name', 'OpenID Connect'), $e->getMessage())); + return $this->redirect('/'); + } + } + + /** + * index + * + * @throws ForbiddenException + * @return \Cake\Http\Response + */ + public function index() + { + if (!$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $users = $this->Users->find() + ->contain(['Actors', 'Organisations' => ['Actors', 'OrganisationActors']]); + + if (!$this->logged_user->hasCapability('configuration.users.read')) { + $users = $users->where(['Users.organisation_id' => $this->logged_user->organisation_id]); + } + + $this->set('total_users', $users->count()); + // applichiamo gli eventuali filtri presenti: + $users = $this->applyFilters($users); + $this->set('filtered_users', $users->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $users = $users + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->id == $row->id || ($this->logged_user->organisation_id == $row->organisation_id && $this->logged_user->hasCapability('configuration.users.edit_foo')) || $this->logged_user->hasCapability('configuration.users.edit'); + $row->can_delete = $this->logged_user->id != $row->id && (($this->logged_user->organisation_id == $row->organisation_id && $this->logged_user->hasCapability('configuration.users.delete_foo')) || $this->logged_user->hasCapability('configuration.users.delete')); + return $row; + }); + }); + } + + $this->paginate = [ + 'sortableFields' => ['surname', 'name', 'username', 'OrganisationActors.description'], + ]; + + $this->set('users', $this->getRequest()->is(['json', 'xml', 'csv']) ? $users : $this->paginate($users)); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('configuration.users.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Cognome'), + __('Nome'), + __('Username'), + __('Recapiti'), + __('Profili'), + __('Organizzazione'), + ]; + $extract = [ + 'surname', + 'name', + 'username', + function (array $row) { + return $row['actor']['contacts']; + }, + 'profiles', + function (array $row) { + return $row['organisation']['organisation_actor']['description']; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("users_$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'users'); + } + + /** + * view + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function view($id = null) + { + if ($this->logged_user->id != $id && !$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $user = $this->Users->get($id, contain: ['Actors', 'Languages', 'Organisations' => ['Actors']]); + + if (!$this->logged_user->hasCapability('configuration.users.read') && $this->logged_user->organisation_id != $user->organisation_id && $this->logged_user->id != $user->id) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $user->can_handle_contacts = $this->logged_user->canViewContactsForActor($this->Users->Actors->get($user->actor_id, contain: ['Users'])); + $user->can_edit = $this->logged_user->hasCapability('configuration.users.edit') || $this->logged_user->organisation_id == $user->organisation_id && $this->logged_user->hasCapability('configuration.users.edit_foo') || $this->logged_user->id == $user->id; + $user->can_delete = $this->logged_user->id != $user->id && (($this->logged_user->organisation_id == $user->organisation_id && $this->logged_user->hasCapability('configuration.users.delete_foo')) || $this->logged_user->hasCapability('configuration.users.delete')); + + $this->set(compact('user')); + $this->viewBuilder()->setOption('serialize', 'user'); + } + + /** + * add + * + * @return \Cake\Http\Response + */ + public function add() + { + if (!$this->logged_user->hasCapability(['configuration.users.add', 'configuration.users.add_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $can_view_profiles = $this->logged_user->hasCapability('configuration.groups.read'); + $can_handle_profiles = $can_view_profiles && ($this->logged_user->hasCapability('configuration.users.profiles') || $this->fetchTable('Users')->getAssociableUserGroups()->count() > 0); + + $user = $this->Users->newEmptyEntity(); + + $default_profiles = $this->Users->Groups->find() + ->contain(['Actors']) + ->where(['Groups.is_default' => 1]) + ->all() + ->toArray(); + + $user['groups'] = $default_profiles; + + if ($this->request->is('post')) { + $user = $this->Users->patchEntity($user, $this->request->getData()); + + if (!$can_handle_profiles) $user['groups'] = $default_profiles; + + if ($this->Users->save($user)) { + $this->Flash->success(__('Utente creato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la creazione dell\'utente')); + } + $organisations = $this->Users->Organisations->find('list')->contain(['Actors'])->order(['Actors.description' => 'ASC']); + if (!$this->logged_user->hasCapability('configuration.users.add')) $organisations = $organisations->where(['Organisations.id' => $this->logged_user->organisation_id]); + $languages = $this->Users->Languages->find('list'); + $groups = $this->fetchTable('Users')->getAssociableUserGroups(as_list: true)->order(['Groups.description' => 'ASC']); + $this->set('today', DateTime::now()); + $this->set(compact('user', 'organisations', 'languages', 'groups', 'can_view_profiles', 'can_handle_profiles')); + } + + /** + * edit + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function edit($id = null) + { + if ($this->logged_user->id != $id && !$this->logged_user->hasCapability(['configuration.users.edit', 'configuration.users.edit_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $can_view_profiles = $this->logged_user->hasCapability('configuration.groups.read'); + $can_handle_profiles = $can_view_profiles && ($this->logged_user->hasCapability('configuration.users.profiles') || $this->fetchTable('Users')->getAssociableUserGroups()->count() > 0); + + $user = $this->Users->get($id, contain: ['Actors', 'Groups', 'Languages', 'Organisations' => ['Actors']]); + if ($this->request->is(['patch', 'post', 'put'])) { + $user->setAccess('groups', $can_handle_profiles); + $user = $this->Users->patchEntity($user, $this->request->getData()); + + if ($this->Users->save($user)) { + $this->Flash->success(__('Utente "{0}" modificato con successo.', $user->actor->description)); + + return $this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo']) ? $this->redirect(['action' => 'index']) : $this->redirect('/'); + } + $this->Flash->error(__('Errore durante la modifica dell\'utente "{0}". Riprovare di nuovo.', $user->actor->description)); + } + $organisations = $this->Users->Organisations->find('list')->contain(['Actors'])->order(['Actors.description' => 'ASC']); + if (!$this->logged_user->hasCapability('configuration.users.edit')) $organisations = $organisations->where(['Organisations.id' => $this->logged_user->organisation_id]); + $languages = $this->Users->Languages->find('list'); + $groups = $this->fetchTable('Users')->getAssociableUserGroups(as_list: true)->order(['Groups.description' => 'ASC']); + $this->set('today', DateTime::now()); + $this->set(compact('user', 'organisations', 'languages', 'groups', 'can_view_profiles', 'can_handle_profiles')); + } + + /** + * delete + * + * @param Int $id + * @return \Cake\Http\Response + */ + public function delete($id = null) + { + if (!$this->logged_user->hasCapability(['configuration.users.delete', 'configuration.users.delete_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $user = $this->Users->get($id, contain: ['Actors']); + + if ($this->logged_user->id == $user->id || ($this->logged_user->organisation_id != $user->organisation_id && !$this->logged_user->hasCapability('configuration.users.delete'))) throw new ForbiddenException(__('Non hai i permessi necessari')); + + if ($this->Users->Actors->delete($user->actor)) { + $this->Flash->success(__('L\'utente "{0}" è stato cancellato con successo', $user->actor->description)); + } else { + $this->Flash->error(__('Errore durante la cancellazione dell\'utente "{0}". Riprovare di nuovo.', $user->actor->description)); + } + + return $this->redirect(['action' => 'index']); + } + + /** + * login + * + * @return \Cake\Http\Response + */ + public function login() + { + $result = $this->Authentication->getResult(); + // If the user is logged in send them away. + if ($result->isValid()) { + $user = $this->Authentication->getIdentity(); + $user->timezone = $this->request->getData('user_timezone', Configure::read('App.defaultUserTimezone')); + // se per qualche motivo il form restituisce "" stringa vuota per il timezone, impostiamo invece il default! + if (empty($user->timezone)) $user->timezone = Configure::read('App.defaultUserTimezone'); + $this->fetchTable('Users')->save($user); + $target = $this->Authentication->getLoginRedirect() ?? '/'; + $this->request->getSession()->write("oidc", null); + return $this->redirect($target); + } + + if ($this->request->is('post')) { + $authError = $this->request->getSession()->read('AuthError'); + if ($authError) { + $this->Flash->error($authError); + $this->request->getSession()->delete('AuthError'); + } else { + $this->Flash->error('username e/o password errati'); + } + } + $login_citizen_registration = $this->request->getSession()->read('showCitizenRegistration'); + $this->set(compact('login_citizen_registration')); + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ho dimenticato la mia password')); + $this->set('login_layout_link_action', 'passwordRecovery'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + if (isset($login_citizen_registration) && $login_citizen_registration->isShowAlert()) { + $login_citizen_registration_copy = clone $login_citizen_registration; + $login_citizen_registration_copy->setShowAlert(false); + $this->request->getSession()->write('showCitizenRegistration', $login_citizen_registration_copy); + } + } + + /** + * logout + * + * @return \Cake\Http\Response + */ + public function logout() + { + $this->Authentication->logout(); + + if ($this->request->getSession()->read('oidc')) { + OpenIdConnectClient::logout( + Configure::read('App.oidc.logoutUrl'), + Configure::read('App.oidc.clientId'), + Configure::read('App.oidc.postLogoutRedirectUri') + ); + } + + $this->Flash->success(__('Logout eseguito con successo.')); + return $this->redirect(['controller' => 'Users', 'action' => 'login']); + } + + /** + * executePasswordRecovery + * + * @param \App\Model\Entity\User $user + * @param String $email + * @param String|Null $password_recovery_token + * @return String|Null + */ + private function executePasswordRecovery(\App\Model\Entity\User $user, String $email, String|Null $password_recovery_token = null): String|Null + { + $user->password_recovery_token = $password_recovery_token ?? sha1($this->gen_random_code(40)); + + if (!$this->Users->save($user)) return null; + + $options = []; + $options['user_id'] = $user->id; + $options['username'] = $user->username; + $options['email'] = $email; + $options['type'] = 'users'; + $options['password_recovery_token'] = $user->password_recovery_token; + $this->sendNotifications(null, 'password_recovery', $options); + return $user->password_recovery_token; + } + + /** + * passwordRecovery + * + * @return \Cake\Http\Response + */ + public function passwordRecovery() + { + if ($this->request->is('post')) + { + if (empty($this->request->getData('email'))) { + $this->Flash->error(__('Inserire un indirizzo email valido!')); + return $this->redirect(['action' => 'passwordRecovery']); + } + + $email = $this->Users->Actors->Deliveries->Emails->find() + ->contain(['Deliveries' => ['Actors' => ['Users']]]) + ->where(['Emails.value' => $this->request->getData('email')]) + ->first(); + + if (isset($email->delivery->actor->user)) + { + $this->executePasswordRecovery($email->delivery->actor->user, $this->request->getData('email')); + $this->Flash->success(__('A breve riceverai un\'email all\'indirizzo "{0}" con le istruzioni per eseguire il reset della password per il tuo account con username "{1}".', $this->request->getData('email'), $email->delivery->actor->user->username)); + return $this->redirect(['action' => 'login']); + } + else + { + $this->Flash->error(__('L\'indirizzo email inserito non risulta presente')); + return $this->redirect(['action' => 'passwordRecovery']); + } + } + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ritorna al login')); + $this->set('login_layout_link_action', 'login'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + } + + /** + * chooseNewPassword + * + * @param String $token + * @return \Cake\Http\Response + */ + public function chooseNewPassword($token) + { + $user = $this->Users->find()->contain(['Actors', 'Organisations'])->where(['Users.password_recovery_token' => $token])->first(); + + if(!$user) + { + $this->Flash->error(__('Impossibile completare la procedura di recupero password.')); + return $this->redirect(['action' => 'login']); + } + + if ($this->request->is('post')) + { + if (!empty($this->request->getData('new_password')) && !empty($this->request->getData('confirm_new_password')) && $this->request->getData('new_password') == $this->request->getData('confirm_new_password')) { + $user_data = $user->toArray(); + $user_data['password'] = $this->request->getData('new_password'); + $user = $this->Users->patchEntity($user, $user_data, ['validate' => false]); + if (count($user->getError('password')) > 0) { + $this->Flash->error(implode(" - ", $user->getError('password'))); + return $this->redirect(['action' => 'chooseNewPassword', $token]); + } + + $user->password_recovery_token = null; + $user->last_change_password = new \DateTime(); + $user->password_recovery_counter = $user->password_recovery_counter+1; + + if ($this->Users->save($user)) { + $this->Flash->success('Password modificata con successo'); + return $this->redirect(['action' => 'login']); + } else { + $this->Flash->error(__('Impossibile cambiare la password')); + } + + } else { + $this->Flash->error(__('La nuova password non è valida e/o le 2 password non coincidono')); + } + } + + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ritorna al login')); + $this->set('login_layout_link_action', 'login'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + } + + public function oneTimePassword(String $otp) { + $users = $this->fetchTable('Users')->find()->where(['Users.otp' => $otp]); + if ($users->count() != 1) { + $this->Flash->error(__('Codice OTP non valido o già utilizzato. Effettua il login.')); + return $this->redirect(['action' => 'login']); + } + + $user = $users->first(); + + // controllo che otp_expires sia un datetime valido e non scaduto: + if ($user->otp_expires === null || !is_object($user->otp_expires) || get_class($user->otp_expires) != "Cake\I18n\DateTime" || !$user->otp_expires->isWithinNext(Configure::read('App.oneTimePasswordExpirationHours', 1) . ' hours')) { + $user->otp = null; + $user->otp_redirect_url = null; + $user->otp_expires = null; + $this->fetchTable('Users')->save($user); + $this->Flash->error(__('Codice OTP scaduto. Effettua il login.')); + return $this->redirect(['action' => 'login']); + } + + if ($this->request->is('post')) + { + $redirect_url = $user->otp_redirect_url ?? '/'; + $user->sys_admin = false; + $user->passepartout = false; + $user->otp = null; + $user->otp_redirect_url = null; + $user->otp_expires = null; + $this->fetchTable('Users')->save($user); + $this->getRequest()->getSession()->write('Auth', $user); + return $this->redirect($redirect_url); + } + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set('login_layout_link_label', __('Ritorna al login')); + $this->set('login_layout_link_action', 'login'); + $this->set('login_layout_privacy_label', __('Visualizza Privacy Policy')); + $this->set('login_layout_privacy_link', 'view_public'); + } + + /** + * getPhoto + * + * @param String $file_name + * @return \Cake\Http\Response + */ + public function getPhoto($file_name) + { + $photo_owner = $this->fetchTable('Users')->find()->where(['Users.photo' => $file_name])->first(); + + if (!$photo_owner) throw new NotFoundException(__('Foto utente non trovata!')); + + if ($this->logged_user->id != $photo_owner->id) { + if (!$this->logged_user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability(['configuration.users.read']) && $this->logged_user->organisation_id != $photo_owner->organisation_id) throw new ForbiddenException(__('Non hai i permessi necessari')); + } + + $mimetype = "image/jpeg"; + $path = Configure::read('App.userPhotoPath') . "/" . $file_name; + $output = \App\WGS\FileStorage\FileStorageFactory::create()->getFile($path); + $this->response = $this->response + ->withType($mimetype) + ->withStringBody($output); + + return $this->response; + } + + /** + * deleteUserPhoto + * + * @param Int $user_id + * @return \Cake\Http\Response + */ + public function deleteUserPhoto($user_id) + { + $user = $this->Users->get($user_id); + $user->photo = null; + if (!$this->Users->save($user)) { + $this->Flash->error(__('Errore durante l\'eliminazione della foto utente!')); + } else { + $this->Flash->success(__('Foto utente eliminata con successo')); + } + return $this->redirect(['action' => 'view', $user_id]); + } + + /** + * add_citizen + * @return \Cake\Http\Response + */ + public function add_citizen() + { + $user = $this->Users->newEmptyEntity(); + $citizenRegistrationData = $this->request->getSession()->read('showCitizenRegistration'); + if ($this->request->is('post') || $this->request->is('put')) { + $data = $this->request->getData(); + $taxCode = $data['tax_code'] ?? null; + $name = $data['name'] ?? null; + $surname = $data['surname'] ?? null; + $birthday = $data['birthday'] ?? null; + $gender = $data['gender'] ?? null; + if ($taxCode && $citizenRegistrationData && $citizenRegistrationData?->getFiscalCode() !== '' && $citizenRegistrationData->getFiscalCode() != $taxCode) { + $this->Flash->error(__('Il codice fiscale inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + elseif ($name && $citizenRegistrationData && $citizenRegistrationData?->getName() !== '' && $citizenRegistrationData->getName() != $name) { + $this->Flash->error(__('Il nome inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + elseif ($surname && $citizenRegistrationData && $citizenRegistrationData?->getSurname() !== '' && $citizenRegistrationData->getSurname() != $surname) { + $this->Flash->error(__('Il cognome inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + elseif ($birthday && $citizenRegistrationData && $citizenRegistrationData?->getBirthdate() !== '' && $citizenRegistrationData->getBirthdate() != $birthday) { + $this->Flash->error(__('La data di nascita inserita non corrisponde a quella fornita in fase di autenticazione. Riprovare.')); + } + elseif ($gender && $citizenRegistrationData && $citizenRegistrationData?->getGender() !== '' && $citizenRegistrationData->getGender() != $gender) { + $this->Flash->error(__('Il sesso inserito non corrisponde a quello fornito in fase di autenticazione. Riprovare.')); + } + else { + $newCitizen = $this->Users->createCitizen($user, $data); + if ($newCitizen) { + $emails = $newCitizen?->getEmailsWithNotifications() ?? []; + $notificationEmail = $emails[0] ?? null; + $successMessage = 'Utente creato con successo.'; + if ($notificationEmail) { + $options = [ + 'user_id' => $newCitizen->id, + 'username' => $newCitizen->username, + 'email' => $notificationEmail->value, + 'type' => 'users', + 'verification_token' => $newCitizen->email_verification_code, + ]; + $this->sendNotifications(null, 'verify-citizen-registration', $options); + $successMessage = 'Utente creato con successo. Riceverai un\'email per confermare la registrazione.'; + } + $this->request->getSession()->delete('showCitizenRegistration'); + $this->Flash->success(__($successMessage)); + return $this->redirect(['action' => 'login']); + } else { + $this->Flash->error(__('Errore durante la creazione dell\'utente')); + } + } + } + + $languages = $this->Users->Languages->find('list'); + $this->viewBuilder()->setLayout('CakeLte.login'); + $this->set([ + 'today' => DateTime::now(), + 'hideLogin' => true, + 'user' => $user, + 'languages' => $languages, + 'citizenRegistrationData' => $citizenRegistrationData, + ]); + } + + + /** + * verify citizen + * @param string|null $token + * @return \Cake\Http\Response + */ + public function verify_citizen(string|null $token) + { + $token = $token ?? ''; + if ($this->Users->verifyCitizen($token)) { + $this->Flash->success(__('Utente verificato con successo.')); + return $this->redirect(['action' => 'login']); + } + + $this->Flash->error(__('Errore durante la verifica, si prega di riprovare.')); + return $this->redirect(['action' => 'login']); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingArticlesController.php b/idrocap_wa/src/Controller/WaterDrawingArticlesController.php new file mode 100644 index 0000000..0f51528 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingArticlesController.php @@ -0,0 +1,124 @@ +WaterDrawingArticles->find()->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('configuration.water_drawing_articles.edit'); + $row->can_delete = $this->logged_user->hasCapability('configuration.water_drawing_articles.delete'); + $row->can_disable = $this->logged_user->hasCapability('configuration.water_drawing_articles.disable'); + return $row; + }); + }); + $waterDrawingArticles = $this->paginate($waterDrawingArticles); + + $this->set(compact('waterDrawingArticles')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Article id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingArticle = $this->WaterDrawingArticles->get($id, contain: []); + $waterDrawingArticle->can_edit = $this->logged_user->hasCapability('configuration.water_drawing_articles.edit'); + $waterDrawingArticle->can_delete = $this->logged_user->hasCapability('configuration.water_drawing_articles.delete'); + $waterDrawingArticle->can_disable = $this->logged_user->hasCapability('configuration.water_drawing_articles.disable'); + $this->set(compact('waterDrawingArticle')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + $waterDrawingArticle = $this->WaterDrawingArticles->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, $this->request->getData()); + if ($this->WaterDrawingArticles->save($waterDrawingArticle)) { + $this->Flash->success(__('Articolo di legge salvato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante il salvataggio dell\'articolo di legge. Riprovare di nuovo.')); + } + $this->set(compact('waterDrawingArticle')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Article id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingArticle = $this->WaterDrawingArticles->get($id, contain: []); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, $this->request->getData()); + if ($this->WaterDrawingArticles->save($waterDrawingArticle)) { + $this->Flash->success(__('Articolo di legge modificato con successo.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore durante la modifica dell\'articolo di legge. Riprovare di nuovo.')); + } + $this->set(compact('waterDrawingArticle')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Article id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingArticle = $this->WaterDrawingArticles->get($id); + if ($this->WaterDrawingArticles->delete($waterDrawingArticle)) { + $this->Flash->success(__('L\'articolo di legge è stato cancellato con successo.')); + } else { + $this->Flash->error(__('Errore durante la cancellazione dell\'articolo di legge. Riprovare di nuovo.')); + } + + return $this->redirect(['action' => 'index']); + } + + public function change_status($id){ + $waterDrawingArticle = $this->WaterDrawingArticles->get($id); + $waterDrawingArticle = $this->WaterDrawingArticles->patchEntity($waterDrawingArticle, [ + 'disable' => $waterDrawingArticle->disable ? false : true + ]); + if($this->WaterDrawingArticles->save($waterDrawingArticle)){ + $this->Flash->success( $waterDrawingArticle->disable ? __('Articolo disabilitato con successo.') : __('Articolo abilitato con successo.')); + }else{ + $this->Flash->error( $waterDrawingArticle->disable ? __('Errore durante l\'abilitazione dell\'articolo.') : __('Errore durante la disabilitazione dell\'articolo.')); + } + return $this->redirect(['action' => 'index']); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingDerivationsController.php b/idrocap_wa/src/Controller/WaterDrawingDerivationsController.php new file mode 100644 index 0000000..fb7974a --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingDerivationsController.php @@ -0,0 +1,123 @@ +paginate = [ + 'contain' => ['WaterDrawingDerivationTypes', 'WaterDrawingPaperworks'], + ]; + $waterDrawingDerivations = $this->paginate($this->WaterDrawingDerivations); + + $this->set(compact('waterDrawingDerivations')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Derivation id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingDerivation = $this->WaterDrawingDerivations->find() + ->contain(['WaterDrawingDerivationTypes', 'WaterDrawingPaperworks']) + ->where(['WaterDrawingDerivations.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results){ + return $results->map(function ($row){ + $row->can_edit = true; + $row->can_delete = true; + return $row; + }); + })->first(); + + $this->set(compact('waterDrawingDerivation')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingDerivation = $this->WaterDrawingDerivations->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingDerivation = $this->WaterDrawingDerivations->patchEntity($waterDrawingDerivation, $this->request->getData()); + if ($this->WaterDrawingDerivations->save($waterDrawingDerivation)) { + $waterDrawingPaperworks = $this->WaterDrawingDerivations->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Il punto di prelievo è stato salvato con successo')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio del punto di prelievo.')); + } + $waterDrawingDerivationTypes = $this->WaterDrawingDerivations->WaterDrawingDerivationTypes->find()->all()->combine('id','description')->toArray(); + $this->set(compact('waterDrawingDerivation', 'waterDrawingDerivationTypes', 'water_drawing_paperwork_id')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Derivation id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingDerivation = $this->WaterDrawingDerivations->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingDerivation = $this->WaterDrawingDerivations->patchEntity($waterDrawingDerivation, $this->request->getData()); + + if ($this->WaterDrawingDerivations->save($waterDrawingDerivation)) { + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di prelievo è stato salvato con successo')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio del punto di prelievo.')); + } + $waterDrawingDerivationTypes = $this->WaterDrawingDerivations->WaterDrawingDerivationTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingDerivation', 'waterDrawingDerivationTypes')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Derivation id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingDerivation = $this->WaterDrawingDerivations->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->WaterDrawingDerivations->delete($waterDrawingDerivation)) { + SnapshotsHandler::createSnapshot($waterDrawingDerivation->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di prelievo è stato cancellato')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id]); + } else { + $this->Flash->error(__('Errore durante la cancellazione del punto di prelievo.')); + } + + return $this->redirect(['action' => 'view', $waterDrawingDerivation->id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingFeesController.php b/idrocap_wa/src/Controller/WaterDrawingFeesController.php new file mode 100644 index 0000000..b1d3986 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingFeesController.php @@ -0,0 +1,174 @@ +logged_user->hasCapability(['documentation.water_drawing_fees.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingFees = $this->WaterDrawingFees->find()->contain(['WaterDrawingPayments'])->where(['WaterDrawingFees.water_drawing_paperwork_id' => $water_drawing_paperwork_id])->formatResults(function ($result){ + return $result->map(function ($row){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_fees.delete') && (count($row->water_drawing_payments) == 0); + return $row; + }); + }); + $this->set('total_water_drawing_fees', $waterDrawingFees->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingFees = $this->applyFilters($waterDrawingFees); + $this->set('filtered_water_drawing_fees', $waterDrawingFees->count()); + $waterDrawingFees = $this->paginate($waterDrawingFees); + + $this->set(compact('waterDrawingFees', 'water_drawing_paperwork_id')); + $this->set('can_export_csv', $this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Anno'), + __('Canone'), + __('Dovuto') + ]; + $extract = [ + 'year', + 'amount', + 'to_pay' + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_fees_$water_drawing_paperwork_id-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingFees'); + } + + /** + * View method + * + * @param string|null $id Water Drawing Fee id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_fees.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingFee = $this->WaterDrawingFees->find()->contain(['WaterDrawingPayments'])->where(['WaterDrawingFees.id' => $id])->formatResults(function ($result){ + return $result->map(function ($row){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_fees.delete') && (count($row->water_drawing_payments) == 0); + return $row; + }); + })->first(); + + $waterDrawingPayments = $this->WaterDrawingFees->WaterDrawingPayments->find()->contain(['WaterDrawingFees', 'WaterDrawingPaymentTypes', 'Users'])->where(['WaterDrawingPayments.water_drawing_fee_id' => $id])->formatResults(function ($result){ + return $result->map(function ($row){ + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + return $row; + }); + }); + + $this->set(compact('waterDrawingFee', 'waterDrawingPayments')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingFee = $this->WaterDrawingFees->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingFee = $this->WaterDrawingFees->patchEntity($waterDrawingFee, $this->request->getData()); + if ($this->WaterDrawingFees->save($waterDrawingFee)) { + $waterDrawingPaperworks = $this->WaterDrawingFees->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Il canone annuale è stato salvato.')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il canone annuale non è stato salvato.')); + } + $this->set(compact('waterDrawingFee', 'water_drawing_paperwork_id')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Fee id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingFee = $this->WaterDrawingFees->get($id); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingFee = $this->WaterDrawingFees->patchEntity($waterDrawingFee, $this->request->getData()); + if ($this->WaterDrawingFees->save($waterDrawingFee)) { + $this->Flash->success(__('Il canone annuale è stato salvato.')); + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il canone annuale non è stato salvato.')); + } + $this->set(compact('waterDrawingFee')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Fee id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingFee = $this->WaterDrawingFees->get($id, contain: ['WaterDrawingPayments']); + if(count($waterDrawingFee->water_drawing_payments) > 0){ + $this->Flash->error(__('Errore. Per poter eliminare il canone bisogna eliminare i pagamenti ad esso associati.')); + return $this->redirect(['action' => 'view', $id]); + } + if ($this->WaterDrawingFees->delete($waterDrawingFee)) { + $this->Flash->success(__('Il canone annuale è stato cancellato.')); + } else { + $this->Flash->error(__('Errore. Il canone annuale non è stato cancellato.')); + } + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingIntendedUsesController.php b/idrocap_wa/src/Controller/WaterDrawingIntendedUsesController.php new file mode 100644 index 0000000..9859ceb --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingIntendedUsesController.php @@ -0,0 +1,108 @@ +paginate = [ + 'contain' => ['WaterDrawingPaperworks', 'WaterDrawingIntendedUseTypes'], + ]; + $waterDrawingIntendedUses = $this->paginate($this->WaterDrawingIntendedUses); + + $this->set(compact('waterDrawingIntendedUses')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Intended Use id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id, contain: ['WaterDrawingPaperworks', 'WaterDrawingIntendedUseTypes']); + + $this->set(compact('waterDrawingIntendedUse')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->patchEntity($waterDrawingIntendedUse, $this->request->getData()); + if ($this->WaterDrawingIntendedUses->save($waterDrawingIntendedUse)) { + $this->Flash->success(__('The water drawing intended use has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The water drawing intended use could not be saved. Please, try again.')); + } + $waterDrawingPaperworks = $this->WaterDrawingIntendedUses->WaterDrawingPaperworks->find('list')->all(); + $waterDrawingIntendedUseTypes = $this->WaterDrawingIntendedUses->WaterDrawingIntendedUseTypes->find('list')->all(); + $this->set(compact('waterDrawingIntendedUse', 'waterDrawingPaperworks', 'waterDrawingIntendedUseTypes')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Intended Use id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id, contain: []); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->patchEntity($waterDrawingIntendedUse, $this->request->getData()); + if ($this->WaterDrawingIntendedUses->save($waterDrawingIntendedUse)) { + $this->Flash->success(__('The water drawing intended use has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The water drawing intended use could not be saved. Please, try again.')); + } + $waterDrawingPaperworks = $this->WaterDrawingIntendedUses->WaterDrawingPaperworks->find('list')->all(); + $waterDrawingIntendedUseTypes = $this->WaterDrawingIntendedUses->WaterDrawingIntendedUseTypes->find('list')->all(); + $this->set(compact('waterDrawingIntendedUse', 'waterDrawingPaperworks', 'waterDrawingIntendedUseTypes')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Intended Use id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingIntendedUse = $this->WaterDrawingIntendedUses->get($id); + if ($this->WaterDrawingIntendedUses->delete($waterDrawingIntendedUse)) { + $this->Flash->success(__('The water drawing intended use has been deleted.')); + } else { + $this->Flash->error(__('The water drawing intended use could not be deleted. Please, try again.')); + } + + return $this->redirect(['action' => 'index']); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingMeasurementsController.php b/idrocap_wa/src/Controller/WaterDrawingMeasurementsController.php new file mode 100644 index 0000000..75779cf --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingMeasurementsController.php @@ -0,0 +1,124 @@ +logged_user->hasCapability('documentation.water_drawing_measurements.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeasurement = $this->WaterDrawingMeasurements->newEmptyEntity(); + $waterDrawingMeter = $this->WaterDrawingMeasurements->WaterDrawingMeters->find()->contain(['WaterDrawingIntendedUses' => ['WaterDrawingPaperworks']])->where(['WaterDrawingMeters.id' => $water_drawing_meter_id])->first(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['user_id'] = $this->logged_user->id; + $data['water_drawing_meter_id'] = $water_drawing_meter_id; + $waterDrawingMeasurement = $this->WaterDrawingMeasurements->patchEntity($waterDrawingMeasurement, $data); + if ($this->WaterDrawingMeasurements->save($waterDrawingMeasurement)) { + SnapshotsHandler::createSnapshot($waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Misurazione salvata con successo.')); + return $this->redirect(['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingMeter->id]); + } + $this->Flash->error(__('Errore durante il salvataggio della misurazione.')); + } + $this->set('today', DateTime::now()); + $this->set('water_drawing_paperwork_id', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id); + $this->set(compact('waterDrawingMeasurement', 'water_drawing_meter_id')); + } + + /** + * index + * + * @param mixed $water_drawing_paperwork_id + * @return void + */ + public function index($water_drawing_paperwork_id){ + $waterDrawingMeasurements = $this->WaterDrawingMeasurements->find()->contain(['WaterDrawingMeters' => ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses'], 'Users'])->where(['WaterDrawingIntendedUses.water_drawing_paperwork_id' => $water_drawing_paperwork_id]); + $this->set('total_water_drawing_measurements', $waterDrawingMeasurements->count()); + + // applichiamo gli eventuali filtri presenti: + $waterDrawingMeasurements = $this->applyFilters($waterDrawingMeasurements); + $this->set('filtered_water_drawing_measurements', $waterDrawingMeasurements->count()); + + if(!$this->getRequest()->is(['json', 'xml', 'csv'])){ + $waterDrawingMeasurements = $waterDrawingMeasurements + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->date = $row->date?->format('d/m/Y'); + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'order' => [ + 'WaterDrawingMeasurements.date' => 'DESC' + ], + ]; + + $this->set(compact('water_drawing_paperwork_id')); + $this->set('waterDrawingMeasurements', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingMeasurements : $this->paginate($waterDrawingMeasurements)); + $this->set('can_export_csv', $this->logged_user->hasCapability('documentation.water_drawing_measurements.export_csv_measurement')); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_measurements.export_csv_measurement')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $header = [ + __('N° matricola strumento di misura'), + __('Lettura Volume (m^3)'), + __('Data lettura'), + __('Utente'), + ]; + $extract = [ + function (array $row) { + return $row['water_drawing_meter']['part_number']; + }, + 'volume', + 'date', + function (array $row) { + $user = $this->fetchTable('Users')->get($row['user']['id']); + return $user; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_measurements_$water_drawing_paperwork_id-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingMeasurements'); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingMetersController.php b/idrocap_wa/src/Controller/WaterDrawingMetersController.php new file mode 100644 index 0000000..d80427e --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingMetersController.php @@ -0,0 +1,97 @@ +logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->newEmptyEntity(); + $waterDrawingIntendedUse = $this->WaterDrawingMeters->WaterDrawingIntendedUses->get($water_drawing_intended_use_id); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['water_drawing_intended_use_id'] = $water_drawing_intended_use_id; + $waterDrawingMeter = $this->WaterDrawingMeters->patchEntity($waterDrawingMeter, $data); + if ($this->WaterDrawingMeters->save($waterDrawingMeter)) { + $waterDrawingPaperworks = $this->WaterDrawingMeters->WaterDrawingIntendedUses->WaterDrawingPaperworks->get($waterDrawingIntendedUse->water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Strumento di misura salvato con successo.')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio dello strumento di misura.')); + } + $waterDrawingToolTypes = $this->WaterDrawingMeters->WaterDrawingToolTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingMeter', 'waterDrawingToolTypes', 'water_drawing_intended_use_id')); + $this->set('water_drawing_paperwork_id', $waterDrawingIntendedUse->water_drawing_paperwork_id); + } + + /** + * dismiss + * + * @param mixed $water_drawing_meter_id + * @return void + */ + public function dismiss($water_drawing_meter_id) + { + if (!$this->logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->get($water_drawing_meter_id, contain: ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingMeter = $this->WaterDrawingMeters->patchEntity($waterDrawingMeter, $this->request->getData()); + if ($this->WaterDrawingMeters->save($waterDrawingMeter)) { + $this->Flash->success(__('Strumento di misura dismesso con successo.')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante la dismissione dello strumento di misura.')); + } + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingMeter')); + } + + public function edit($water_drawing_meter_id) + { + if (!$this->logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->get($water_drawing_meter_id, contain: ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingMeter = $this->WaterDrawingMeters->patchEntity($waterDrawingMeter, $this->request->getData()); + if ($this->WaterDrawingMeters->save($waterDrawingMeter)) { + $this->Flash->success(__('Strumento di misura salvato con successo.')); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante il salvataggio dello strumento di misura.')); + } + $waterDrawingToolTypes = $this->WaterDrawingMeters->WaterDrawingToolTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingMeter', 'waterDrawingToolTypes')); + } + + public function view($water_drawing_meter_id) + { + if (!$this->logged_user->hasCapability('documentation.water_drawing_meters.add')) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingMeter = $this->WaterDrawingMeters->get($water_drawing_meter_id, contain: ['WaterDrawingToolTypes', 'WaterDrawingIntendedUses', 'WaterDrawingMeasurements' => function ($q){ + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }] + ); + $waterDrawingToolTypes = $this->WaterDrawingMeters->WaterDrawingToolTypes->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingMeter', 'waterDrawingToolTypes')); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingPaperworkPecsController.php b/idrocap_wa/src/Controller/WaterDrawingPaperworkPecsController.php new file mode 100644 index 0000000..0a71852 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingPaperworkPecsController.php @@ -0,0 +1,148 @@ +WaterDrawingPaperworkPecs->find()->contain(['Users'])->where(['WaterDrawingPaperworkPecs.water_drawing_paperwork_id' => $water_drawing_paperwork_id]); + $this->set('total_water_drawing_papwork_pecs', $waterDrawingPaperworkPecs->count()); + + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworkPecs = $this->applyFilters($waterDrawingPaperworkPecs); + $this->set('filtered_water_drawing_papwork_pecs', $waterDrawingPaperworkPecs->count()); + + $this->paginate = [ + 'order' => [ + 'WaterDrawingPaperworkPec.date' => 'DESC' + ], + ]; + $waterDrawingPaperworkPecs = $waterDrawingPaperworkPecs->formatResults(function ($results){ + return $results->map( function ($row){ + $row->can_edit_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.edit'); + $row->can_delete_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.delete'); + return $row; + }); + }); + $this->set(compact('water_drawing_paperwork_id')); + $this->set('waterDrawingPaperworkPecs', $this->paginate($waterDrawingPaperworkPecs)); + $this->set('add_documentation', $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.add')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Paperwork Pec id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->find()->contain(['WaterDrawingPaperworks', 'Users', 'ControllableObjects' => ['Attachments']])->where(['WaterDrawingPaperworkPecs.id' => $id])->formatResults(function ($results) { + return $results->map(function ($row) { + $row->can_edit_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.edit'); + $row->can_delete_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.delete'); + return $row; + }); + })->first(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkPecs'])->all()->combine('code', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperworkPec', 'tags')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->newEmptyEntity(); + if ($this->request->is('post')) { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->patchEntity($waterDrawingPaperworkPec, $this->request->getData()); + $waterDrawingPaperworkPec->user_id = $this->logged_user->id; + if ($this->WaterDrawingPaperworkPecs->save($waterDrawingPaperworkPec)) { + $waterDrawingPaperworks = $this->WaterDrawingPaperworkPecs->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperworks->controllable_object_id); + $this->Flash->success(__('Il documento PEC è stato salvato.')); + + return $this->redirect(['action' => 'index', $water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore.Non è stato salvato il documento PEC. ') . $waterDrawingPaperworkPec->getError('attachment')[0]); + } + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkPecs'])->all()->combine('code', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperworkPec', 'water_drawing_paperwork_id', 'tags')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Paperwork Pec id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->get($id, contain: ['ControllableObjects' => ['Attachments'], 'WaterDrawingPaperworks']); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkPecs'])->all()->combine('code', 'description')->toArray(); + if ($this->request->is(['patch', 'post', 'put'])) { + $this->log(json_encode($this->request->getData(), JSON_PRETTY_PRINT), 'debug'); + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->patchEntity($waterDrawingPaperworkPec, $this->request->getData(), ['associated' => ['ControllableObjects']]); + $this->log(json_encode($waterDrawingPaperworkPec, JSON_PRETTY_PRINT), 'debug'); + if ($this->WaterDrawingPaperworkPecs->save($waterDrawingPaperworkPec)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperworkPec->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il documento PEC è stato salvato.')); + + return $this->redirect(['action' => 'index', $waterDrawingPaperworkPec->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore.Non è stato salvato il documento PEC. ') . $waterDrawingPaperworkPec->getError('attachment')[0]); + } + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperworkPec', 'tags')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Paperwork Pec id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingPaperworkPec = $this->WaterDrawingPaperworkPecs->get($id); + if ($this->WaterDrawingPaperworkPecs->delete($waterDrawingPaperworkPec)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperworkPec->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il documento PEC è stato cancellato.')); + } else { + $this->Flash->error(__('Errore.Non è stato cancellato il documento PEC.')); + } + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPaperworkPec->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingPaperworksController.php b/idrocap_wa/src/Controller/WaterDrawingPaperworksController.php new file mode 100644 index 0000000..20a9da4 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingPaperworksController.php @@ -0,0 +1,1775 @@ +logged_user->hasCapability(['documentation.water_drawing_snapshots.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->set('water_drawing_paperwork_id', $water_drawing_paperwork_id); + $this->set('can_export_snapshots', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots.export_csv'])); + + $water_drawing_paperwork = $this->fetchTable('WaterDrawingPaperworks')->get($water_drawing_paperwork_id); + $this->set('waterDrawingPaperwork', $water_drawing_paperwork); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.water_drawing_paperwork_id' => $water_drawing_paperwork_id, 'UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $this->paginate = [ + 'limit' => 25, + 'order' => [ + 'when' => 'DESC' + ], + ]; + + $this->set('unpackedWaterDrawingPaperworkSnapshots', $this->getRequest()->is(['json', 'xml', 'csv']) ? $unpackedWaterDrawingPaperworkSnapshots : $this->paginate($unpackedWaterDrawingPaperworkSnapshots)); + + $this->viewBuilder()->setOption('serialize', 'unpackedWaterDrawingPaperworkSnapshots'); + } + + /** + * index_snapshots_csv + * + * @param mixed $water_drawing_paperwork_id + * @return void + */ + public function index_snapshots_csv($water_drawing_paperwork_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability('documentation.water_drawing_snapshots.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.water_drawing_paperwork_id' => $water_drawing_paperwork_id, 'UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $headers = [ + __('Data'), + __('Da (operatore)'), + __('Azione'), + __('Stato pratica'), + __('Assegnatario Genio Civile'), + __('Assegnatario DRAR'), + ]; + $extract = [ + function (array $row) { + return isset($row['when']) ? (new DateTime($row['when']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + 'who', + 'what', + 'water_drawing_paperwork_status', + 'gc_user', + 'drar_user', + ]; + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + + return $this->streamCsvResponse( + $unpackedWaterDrawingPaperworkSnapshots, + "water_drawing_paperwork-$water_drawing_paperwork_id-snapshots_$timestamp.csv", + $extract, + $headers + ); + } + + public function view_snapshot($snapshot_id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $snapshot = $this->fetchTable('Snapshots')->get($snapshot_id); + + $co = SnapshotsHandler::getControllableObjectFromSnapshotWithId((int)$snapshot_id); + + $this->set('back_to_logs', !empty($this->request->getQuery('origin')) && $this->request->getQuery('origin') == 'logs'); + $this->set('date', $snapshot->date); + $this->set('previous_snapshot_id', $this->fetchTable('Snapshots')->find()->where(['Snapshots.id <' => $snapshot_id, 'Snapshots.controllable_object_id' => $co->id, 'Snapshots.unpacked_with_version' => SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion()])->order(['Snapshots.id' => 'DESC'])->first()?->id); + $this->set('next_snapshot_id', $this->fetchTable('Snapshots')->find()->where(['Snapshots.id >' => $snapshot_id, 'Snapshots.controllable_object_id' => $co->id, 'Snapshots.unpacked_with_version' => SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion()])->order(['Snapshots.id' => 'ASC'])->first()?->id); + + $co->water_drawing_paperwork->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $co->water_drawing_paperwork->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + + $this->set('waterDrawingPaperwork', $co->water_drawing_paperwork); + $this->set('waterDrawingPaperworkHistories', $co->water_drawing_paperwork->water_drawing_paperwork_histories); + + $waterDrawingPayments = collection($co->water_drawing_paperwork->water_drawing_fees) + ->reduce(function ($acc, $water_drawing_fee) { + $water_drawing_fee_year = $water_drawing_fee->year; + $water_drawing_fee->water_drawing_payments = collection($water_drawing_fee->water_drawing_payments)->map(function ($water_drawing_payment, $key) use ($water_drawing_fee_year) { + $water_drawing_payment->amount = !empty($water_drawing_payment->amount) ? $water_drawing_payment->amount . ' €' : null; + $water_drawing_payment->payment_date = $water_drawing_payment->payment_date?->format('Y/m/d'); + $water_drawing_payment->created = isset($water_drawing_payment->created) ? (new DateTime($water_drawing_payment->created))->i18nFormat('Y/MM/dd HH:mm:ss', $this->logged_user->timezone) : null; + $water_drawing_payment->water_drawing_fee_year = $water_drawing_fee_year; + return $water_drawing_payment; + })->toArray(); + return array_merge($acc, $water_drawing_fee->water_drawing_payments); + }, []); + + $this->set('waterDrawingPayments', $waterDrawingPayments); + + $this->set('numberOfAttachments', count($co->child_attachments)); + $this->set('attachments', $co->child_attachments); + + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('WaterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('logged_user_id', $this->logged_user->id); + } + + public function index_snapshots_all() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->set('can_export_snapshots_all', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots.export_all_csv'])); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $this->paginate = [ + 'limit' => 25, + 'order' => [ + 'when' => 'DESC' + ], + ]; + + $this->set('unpackedWaterDrawingPaperworkSnapshots', $this->getRequest()->is(['json', 'xml', 'csv']) ? $unpackedWaterDrawingPaperworkSnapshots : $this->paginate($unpackedWaterDrawingPaperworkSnapshots)); + + $this->viewBuilder()->setOption('serialize', 'unpackedWaterDrawingPaperworkSnapshots'); + } + + /** + * index_snapshots_all_csv + * + * @return void + */ + public function index_snapshots_all_csv() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability('documentation.water_drawing_snapshots.export_all_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $lastWaterDrawingPaperworkUnpackingVersion = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpackedWaterDrawingPaperworkSnapshots = $this->fetchTable('UnpackedWaterDrawingPaperworkSnapshots')->find() + ->where(['UnpackedWaterDrawingPaperworkSnapshots.unpacking_version' => $lastWaterDrawingPaperworkUnpackingVersion]); + + $headers = [ + __('Data'), + __('Da (operatore)'), + __('Azione'), + __('ID Pratica'), + __('Stato pratica'), + __('Assegnatario Genio Civile'), + __('Assegnatario DRAR'), + ]; + $extract = [ + function (array $row) { + return isset($row['when']) ? (new DateTime($row['when']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + 'who', + 'what', + 'water_drawing_paperwork_id', + 'water_drawing_paperwork_status', + 'gc_user', + 'drar_user', + ]; + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + + return $this->streamCsvResponse( + $unpackedWaterDrawingPaperworkSnapshots, + "water_drawing_paperwork_snapshots_all_$timestamp.csv", + $extract, + $headers + ); + } + + /** + * Index method + * + * @return \Cake\Http\Response|null|void Renders view + */ + public function index() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find() + ->contain(['Applicants', 'ControllableObjects', 'WaterDrawingPaperworkStatuses']); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperworks->where(['authority_province' => $this->logged_user?->organisation_province]); + } + + $this->set('total_water_drawing_paperworks', $waterDrawingPaperworks->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworks = $this->applyFilters($waterDrawingPaperworks); + $this->set('filtered_water_drawing_paperworks', $waterDrawingPaperworks->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $waterDrawingPaperworks = $waterDrawingPaperworks + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->release_date = $row->release_date?->format('Y/m/d'); + $row->expiration_date = $row->expiration_date?->format('Y/m/d'); + $row->controllable_object->created = $row->controllable_object->created?->format('Y/m/d H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('Y/m/d H:i:s'); + $row->can_edit = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province') && $row?->authority_province === $this->logged_user?->organisation_province) && + ($this->logged_user->id == $row->gc_user_id && ($row->water_drawing_paperwork_status_id === -1 || $row->water_drawing_paperwork_status_id === -5) || + ($this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -4))) || + (($row->water_drawing_paperwork_status_id == 3 || $row->water_drawing_paperwork_status_id == 5) || + ($row->water_drawing_paperwork_status_id == 8) ? false : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_scan')) ; + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete') || $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_own_province') && $row?->authority_province === $this->logged_user?->organisation_province; + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + 'order' => [ + 'ControllableObjects.created' => 'DESC', + ], + ]; + if(!($this->getRequest()->is(['json', 'xml', 'csv']))){ + $waterDrawingPaperworks = $this->paginate($waterDrawingPaperworks); + if($waterDrawingPaperworks->currentPage() > $waterDrawingPaperworks->pageCount()){ + $queryParams = $this->getRequest()->getQueryParams(); + $queryParams['page'] = 1; + $this->setRequest($this->getRequest()->withQueryParams($queryParams)); + } + } + + $this->set('waterDrawingPaperworks', $waterDrawingPaperworks); + + $this->set('can_export_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_list.export_csv'])); + $this->set('can_export_all_payments_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_all_payments.export_csv_payment'])); + $this->set('can_view_all_snapshots', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])); + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPaperworks'); + } + + /** + * index_csv + * + * @return void + */ + public function index_csv() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks_list.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find() + ->contain(['ControllableObjects', 'WaterDrawingPaperworkStatuses']); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperworks->where(['authority_province' => $this->logged_user?->organisation_province]); + } + + $headers = [ + __('ID'), + __('Codice identificativo'), + __('Stato'), + __('Provincia'), + __('Data di rilascio'), + __('Scadenza'), + __('Creata'), + __('Modificata'), + ]; + + $extract = [ + 'id', + 'authority_identification_code_civil_engineering_office', + function (array $row) { + return $row['water_drawing_paperwork_status']['description'] ?? ''; + }, + 'authority_province', + function (array $row) { + return isset($row['release_date']) ? (new DateTime($row['release_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['expiration_date']) ? (new DateTime($row['expiration_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['created']) ? (new DateTime($row['controllable_object']['created']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['modified']) ? (new DateTime($row['controllable_object']['modified']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + ]; + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + + return $this->streamCsvResponse( + $waterDrawingPaperworks, + "water_drawing_paperworks-$timestamp.csv", + $extract, + $headers + ); + } + + /** + * view method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $organisation = $this->getTableLocator()->get('Organisations')->find()->where(['Organisations.id' => $this->logged_user->organisation_id])->first(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find() + ->contain([ + 'WaterDrawingPaperworkPecs', + 'WaterDrawingFees', + 'GcUsers' => ['Organisations'], + 'DrarUsers' => ['Organisations'], + 'WaterDrawingReturnPoints', + 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], + 'WaterDrawingPaperworkStatuses', + 'ControllableObjects' => ['Attachments' => ['Tags']], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q) { + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ]) + ->where(['WaterDrawingPaperworks.id' => $id]); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperwork->where(['authority_province' => $this->logged_user?->organisation_province]); + } + + $waterDrawingPaperwork = $waterDrawingPaperwork->formatResults(function (\Cake\Collection\CollectionInterface $results) use ($organisation) { + return $results->map(function ($row) use ($organisation) { + if (!$organisation && !empty($row['gc_user'])) { + return $row; + } + $row->can_view_snapshots = $this->logged_user->hasCapability('documentation.water_drawing_snapshots.view'); + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province') && $row?->authority_province === $this->logged_user?->organisation_province) && (isset($row->gc_user_id) && $this->logged_user->id == $row->gc_user_id && ($row->water_drawing_paperwork_status_id === -1 || $row->water_drawing_paperwork_status_id === -5) || ($this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -4)); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_own_province') && $row?->authority_province === $this->logged_user?->organisation_province); + $row->can_validate = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate') && ((isset($row->drar_user_id) && $this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -3) || (isset($row->gc_user_id) && $this->logged_user->id == $row->gc_user_id && $row->water_drawing_paperwork_status_id === 10)); + $row->can_send_to_drar = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province')) && $row?->authority_province === $this->logged_user?->organisation_province) && $row->water_drawing_paperwork_status_id === -1 && $row->check_sdd && isset($row->gc_user_id) && $row->gc_user_id == $this->logged_user->id; + $row->can_send_to_gc = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province')) && $row?->authority_province === $this->logged_user?->organisation_province) && $row->water_drawing_paperwork_status_id === -4 && $row->check_dec && isset($row->drar_user_id) && $row->drar_user_id == $this->logged_user->id; + $row->can_assign_to_drar = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && $row->water_drawing_paperwork_status_id <= -2 && $organisation->organisation_type_id == 6; + $row->can_assign_to_gc = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.assign') && ($row->water_drawing_paperwork_status_id === 9 || !isset($row->gc_user_id) || $organisation->organisation_type_id == $row->gc_user->organisation->organisation_type_id); + $row->can_add_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.add'); + $row->can_edit_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.edit'); + $row->can_delete_pec = $this->logged_user->hasCapability('documentation.water_drawing_paperwork_pecs.delete'); + if ($row->water_drawing_paperwork_status_id === -5) { + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit') || $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + $row->can_add_meter = $this->logged_user->hasCapability('documentation.water_drawing_meters.add'); + $row->can_add_measurements = $this->logged_user->hasCapability('documentation.water_drawing_measurements.add'); + $row->can_view_measurements = true; + } + if ($row->water_drawing_paperwork_status_id == -4) { + $row->can_add_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.add'); + $row->can_edit_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.edit') || $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province'); + $row->can_view_fee = $this->logged_user->hasCapability('documentation.water_drawing_fees.view'); + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + $row->can_submit_antimafia_request = ($this->logged_user->id == $row->drar_user_id) && (!isset($row->water_drawing_antimafia_certification_requests[0])); + $row->can_antimafia_request_to_anac = ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && (isset($row->water_drawing_antimafia_certification_requests[0]) && ($row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 1)); + $row->can_request_self_certification = ($this->logged_user->id == $row->drar_user_id) && (isset($row->water_drawing_antimafia_certification_requests[0]) && (new DateTime($row->water_drawing_antimafia_certification_requests[0]->created))->diffInDays(\Cake\I18n\DateTime::now()) > 30); + $row->can_upload_antimafia_attachment = (isset($row->water_drawing_antimafia_certification_requests[0]) && ( + (($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && !($row->check_dam)) || + (($this->logged_user->id == $row->gc_user_id) && $row->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 3) + )); + } + return $row; + }); + })->first(); + + if (!isset($waterDrawingPaperwork)) { + throw new NotFoundException(__('Pratica non trovata')); + } + + $waterDrawingPaperworkHistories = $this->fetchTable('WaterDrawingPaperworkHistories')->find()->contain(['Users' => ['Actors'], 'ControllableObjects'])->order(['WaterDrawingPaperworkHistories.created' => 'DESC'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id])->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->created = $row->created?->format('Y/m/d'); + return $row; + })->toArray(); + }); + + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $id]) + ->order(['WaterDrawingPayments.created' => 'DESC']) + ->limit(5) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('d/m/Y'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperwork', 'waterDrawingPayments', 'WaterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('waterDrawingPaperworkHistories', $this->paginate($waterDrawingPaperworkHistories)); + $this->set('logged_user_id', $this->logged_user->id); + } + + /** + * view_scan method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view_scan($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find() + ->contain([ + 'WaterDrawingPaperworkPecs', + 'WaterDrawingFees', + 'GcUsers' => ['Organisations'], + 'DrarUsers' => ['Organisations'], + 'WaterDrawingReturnPoints', + 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], + 'WaterDrawingPaperworkStatuses', + 'ControllableObjects' => ['Attachments' => ['Tags']], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q) { + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ]) + ->where(['WaterDrawingPaperworks.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_delete_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + $row->can_edit = ($row->water_drawing_paperwork_status_id == 3 || $row->water_drawing_paperwork_status_id == 5) ? false : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_scan'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete'); + $row->can_validate = ($row->water_drawing_paperwork_status_id != 3 && $row->water_drawing_paperwork_status_id != 5) ? false : ($row->water_drawing_paperwork_status_id == 3 ? $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.first_level_scan') : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.second_level_scan')); + $row->can_send_to_validation = ( + (($row->water_drawing_paperwork_status_id == 1 || $row->water_drawing_paperwork_status_id == 2) && isset($row->applicants, $row->applicants[0]->tax_code, $row->authority_identification_code_civil_engineering_office)) + || $row->water_drawing_paperwork_status_id == 4); + return $row; + }); + }); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.view', + 'documentation.water_drawing_paperworks.view_own_province' + ])) { + $waterDrawingPaperwork = $waterDrawingPaperwork->where(['authority_province' => $this->logged_user?->organisation_province]); + } + $waterDrawingPaperwork = $waterDrawingPaperwork->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + $waterDrawingPaperworkHistories = $this->fetchTable('WaterDrawingPaperworkHistories')->find()->contain(['Users' => ['Actors'], 'ControllableObjects'])->order(['WaterDrawingPaperworkHistories.created' => 'DESC'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id])->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->created = $row->created?->format('Y/m/d'); + return $row; + })->toArray(); + }); + + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $id]) + ->order(['WaterDrawingPayments.created' => 'DESC']) + ->limit(5) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('d/m/Y'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperwork', 'waterDrawingPayments', 'WaterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('waterDrawingPaperworkHistories', $this->paginate($waterDrawingPaperworkHistories)); + $this->set('logged_user_id', $this->logged_user->id); + } + + /** + * add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.add', 'documentation.water_drawing_paperworks.add_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->newEmptyEntity(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id NOT IN' => [-11, -14, -15], 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.add', + 'documentation.water_drawing_paperworks.add_own_province' + ])) { + $data['authority_province'] = $this->logged_user?->organisation_province; + $this->set("authority_civil_engineer_code", SicilyProvinces::getAuthorityEngineerCode($this->logged_user?->organisation_province)); + $this->set("hide_authority_province", true); + } + + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['scanned'] = 0; + $data['water_drawing_paperwork_status_id'] = -1; + $data['gc_user_id'] = $this->logged_user->id; + + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true, 'associated' => ['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['associated' => ['CadastralCropTypes']]]]); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . $waterDrawingPaperwork->getError('attachment')[0]); + } + $waterDrawingDerivationTypes = $this->getTableLocator()->get('WaterDrawingDerivationTypes')->find()->all()->combine('id', 'description')->toArray(); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->where(['WaterDrawingArticles.disable IS NOT' => 1])->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperwork', 'tags', 'waterDrawingDerivationTypes', 'WaterDrawingArticles')); + } + + /** + * add_scan method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add_scan() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.add_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->newEmptyEntity(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['scanned'] = 1; + $messages = $this->WaterDrawingPaperworks->checkAttachments($data); + if (count($messages) != 0) { + $error = ''; + foreach ($messages as $message) $error = $error . $message . " "; + $this->Flash->error(__("Errore con gli allegati. ") . $error); + } else { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'edit_scan', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . json_encode($waterDrawingPaperwork->getErrors())); + } + } + $this->set(compact('waterDrawingPaperwork', 'tags')); + } + + public function edit($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit', 'documentation.water_drawing_paperworks.edit_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->where(['WaterDrawingPaperworks.id' => $id]) + ->contain(['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['CadastralCropTypes']]); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.edit', + 'documentation.water_drawing_paperworks.edit_own_province' + ])) { + $waterDrawingPaperwork->where(['WaterDrawingPaperworks.authority_province' => $this->logged_user->organisation_province]); + $this->set("hide_authority_province", true); + $this->set("authority_civil_engineer_code", SicilyProvinces::getAuthorityEngineerCode($this->logged_user?->organisation_province)); + } + + $waterDrawingPaperwork = $waterDrawingPaperwork->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -2) { + $this->Flash->error(__('La pratica di attingimento è in stato di assegnazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -3) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if (($waterDrawingPaperwork->water_drawing_paperwork_status_id == -1 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == -5) && $waterDrawingPaperwork->gc_user_id != $this->logged_user->id) { + $this->Flash->error(__('La pratica di attingimento è in carico al Genio Civile. Non puoi modificare questa pratica.')); + return $this->redirect(['action' => 'index']); + } + if (($waterDrawingPaperwork->water_drawing_paperwork_status_id == -4) && $waterDrawingPaperwork->drar_user_id != $this->logged_user->id) { + $this->Flash->error(__('La pratica di attingimento è in carico al DRAR. Non puoi modificare questa pratica.')); + return $this->redirect(['action' => 'index']); + } + + if ($this->request->is(['patch', 'post', 'put'])) { + $requestData = $this->request->getData(); + + if ($this->logged_user->hasOnlyLowerPriorityCapability([ + 'documentation.water_drawing_paperworks.edit', + 'documentation.water_drawing_paperworks.edit_own_province' + ])) { + $requestData['authority_province'] = $this->logged_user->organisation_province; + } + + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $requestData, ['filename_as_tag' => true, 'associated' => ['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['associated' => ['CadastralCropTypes']]]]); + + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . (isset($waterDrawingPaperwork->getError('attachment')[0]) ? $waterDrawingPaperwork->getError('attachment')[0] : null)); + } + $tags_viewer = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->all()->combine('code', 'description')->toArray(); + $tags_picker = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id NOT IN' => [-11, -14, -15], 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + $waterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->where(['WaterDrawingArticles.disable IS NOT' => 1])->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPaperwork', 'tags_picker', 'tags_viewer', 'waterDrawingArticles', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + $this->set('user_id', $this->logged_user->id); + } + + /** + * edit_scan method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit_scan($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['CadastralCropTypes']]); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 3 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 5) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $this->request->getData(), ['associated' => ['Applicants._joinData', 'ControllableObjects', 'WaterDrawingIntendedUses' => ['associated' => ['CadastralCropTypes']]]]); + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + $waterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->where(['WaterDrawingArticles.disable IS NOT' => 1])->all()->combine('id', 'description')->toArray(); + $tags_viewer = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->all()->combine('code', 'description')->toArray(); + $tags_picker = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id NOT IN' => [-11, -14, -15], 'Tags.id < 0'])->all()->combine('code', 'description')->toArray(); + + + /* + * IA PLUGIN + * Ordino gli allegati in base alla priorità definita. + * La priorità massima è assegnata al decreto (DEC) poiché contiene più informazioni. + * Se il decreto non è presente, la seconda priorità è il disciplinare (DSC). + * Se il disciplinare non è presente, la terza priorità è la licenza (LIC). + */ + $iaHighestPriorityAttachment = $this->fetchTable('ControllableObjects') + ->Attachments->find() + ->where(['Attachments.container_controllable_object_id' => $waterDrawingPaperwork->controllable_object_id]) + ->matching('Tags', function ($q) { + return $q->where(['Tags.code IN' => ['DEC', 'DSC', 'LIC']]); + })->orderBy( + [ + 'CASE WHEN Tags.code = "DEC" THEN 1 WHEN Tags.code = "DSC" THEN 2 WHEN Tags.code = "LIC" THEN 3 ELSE 4 END' + ] + )->first(); + + $iaPluginData = []; + if ($iaHighestPriorityAttachment) { + $iaPluginData = [ + 'documentHash' => $iaHighestPriorityAttachment->file_name, + 'type' => $iaHighestPriorityAttachment->_matchingData['Tags']->code, + ]; + } + $isAiServiceEnabled = Configure::read('App.aiServiceEnabled'); + /* IA PLUGIN END */ + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + + $this->set(compact('waterDrawingPaperwork', 'waterDrawingArticles', 'tags_picker', 'tags_viewer', 'iaPluginData', 'intendedUseTypes', 'cadastralCropTypes', 'isAiServiceEnabled', 'wateringSystems')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Paperwork id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.delete', 'documentation.water_drawing_paperworks.delete_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $this->request->allowMethod(['post', 'delete']); + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->find()->where(['WaterDrawingPaperworks.id' => $id])->contain(['Applicants', 'ControllableObjects']); + + + if ($this->logged_user->hasOnlyLowerPriorityCapability( + [ + 'documentation.water_drawing_paperworks.delete', + 'documentation.water_drawing_paperworks.delete_own_province' + ] + )) { + $waterDrawingPaperwork->where(['WaterDrawingPaperworks.authority_province' => $this->logged_user->organisation_province]); + } + + $waterDrawingPaperwork = $waterDrawingPaperwork->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + + $connection = ConnectionManager::get('default'); + $connection->begin(); + if (SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id) && $this->fetchTable('WaterDrawingPaperworks')->ControllableObjects->delete($waterDrawingPaperwork->controllable_object)) { + $connection->commit(); + $this->Flash->success(__('La pratica di attingimento con ID:"{0}" è stato cancellato con successo', $waterDrawingPaperwork->id)); + } else { + $connection->rollback(); + $this->Flash->error(__('Errore durante la cancellazione della pratica di attingimento con ID:"{0}". Riprovare di nuovo.', $waterDrawingPaperwork->id)); + } + + return $this->redirect(['action' => 'index']); + } + + /** + * applicants_water_drawing_paperworks_item_block + * + * @param mixed $id + * @return void + */ + public function applicants_water_drawing_paperworks_item_block($id, $water_id = null) + { + if (isset($water_id)) { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($water_id); + $this->set('waterDrawingPaperwork', $waterDrawingPaperwork); + } + + $this->set('applicant_item_block', $id); + $this->viewBuilder()->setLayout('ajax'); + } + + /** + * intended_uses_water_drawing_paperworks_item_block + * + * @param mixed $id + * @return void + */ + public function intended_uses_water_drawing_paperworks_item_block($id, $water_id = null) + { + if (isset($water_id)) { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($water_id); + $this->set('waterDrawingPaperwork', $waterDrawingPaperwork); + } + + $this->set('intended_use_item_block', $id); + $this->viewBuilder()->setLayout('ajax'); + } + + /** + * validate_scan + * + * @param mixed $id + * @return void + */ + public function validate_scan($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan', 'documentation.water_drawing_paperworks.validate.second_level_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects' => ['Attachments'], 'WaterDrawingPaperworkStatuses', + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ] + ); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if (($waterDrawingPaperwork->water_drawing_paperwork_status_id != 3 && $waterDrawingPaperwork->water_drawing_paperwork_status_id != 5) || + ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 3 && !($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan']))) || + ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 5 && !($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.second_level_scan']))) + ) { + $this->Flash->error(__('Nessuna pratica da validare.')); + $this->redirect(['action' => 'index']); + } + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->newEmptyEntity(); + if ($this->request->is(['patch', 'post', 'put'])) { + $connection = ConnectionManager::get('default'); + $connection->begin(); + $data = $this->request->getData(); + $data['water_drawing_paperwork_id'] = $waterDrawingPaperwork->id; + $data['user_id'] = $this->logged_user->id; + $data['water_drawing_paperwork_status_id'] = $waterDrawingPaperwork->water_drawing_paperwork_status_id; + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->patchEntity($waterDrawingPaperworkHistory, $data, [ + 'associated' => ['ControllableObjects'] + ]); + $operatorUserIdNotification = $waterDrawingPaperwork->controllable_object->edit_user_id; + if ($this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->save($waterDrawingPaperworkHistory)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica verificata con successo.')); + $connection->commit(); + $result = $waterDrawingPaperworkHistory->result ? __('ed accettata') : __('ma respinta'); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_result_of_validation_to_operator', ['user_id' => $operatorUserIdNotification, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'result' => $result]); + $this->redirect(['action' => 'validate_index']); + } else { + $connection->rollback(); + $this->Flash->error(__('Errore durante la verifica della pratica.')); + $this->log('errore nel salvataggio', 'debug'); + $this->log(json_encode($waterDrawingPaperworkHistory->getErrors()), 'debug'); + } + } + $waterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $waterDrawingPaperworkHistories = $this->fetchTable('WaterDrawingPaperworkHistories')->find()->contain(['Users' => ['Actors'], 'ControllableObjects'])->order(['WaterDrawingPaperworkHistories.created' => 'DESC'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id])->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->created = $row->created?->format('Y/m/d'); + return $row; + })->toArray(); + }); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'waterDrawingArticles', 'waterDrawingPaperworkHistory', 'intendedUseTypes', 'cadastralCropTypes')); + $this->set('waterDrawingPaperworkHistories', $this->paginate($waterDrawingPaperworkHistories)); + } + + /** + * validate_index + * + * @return void + */ + public function validate_index() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan', 'documentation.water_drawing_paperworks.validate.second_level_scan', 'documentation.water_drawing_paperworks.validate'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $status_level = []; + if ($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.first_level_scan'])) $status_level[] = 3; + if ($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate.second_level_scan'])) $status_level[] = 5; + if ($this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate'])) $status_level[] = -3; + $status_level[] = 10; + + $waterDrawingPaperworks = $this->fetchTable('WaterDrawingPaperworks')->find() + ->contain(['Applicants', 'ControllableObjects', 'WaterDrawingPaperworkStatuses']) + ->where([ + 'OR' => [['WaterDrawingPaperworks.water_drawing_paperwork_status_id IN ' => $status_level, 'WaterDrawingPaperworks.drar_user_id' => $this->logged_user->id], ['WaterDrawingPaperworks.water_drawing_paperwork_status_id IN ' => $status_level, 'WaterDrawingPaperworks.gc_user_id' => $this->logged_user->id]] + ]); + + $this->set('total_water_drawing_paperworks', $waterDrawingPaperworks->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworks = $this->applyFilters($waterDrawingPaperworks); + $this->set('filtered_water_drawing_paperworks', $waterDrawingPaperworks->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $waterDrawingPaperworks = $waterDrawingPaperworks + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->release_date = $row->release_date?->format('Y/m/d'); + $row->expiration_date = $row->expiration_date?->format('Y/m/d'); + $row->controllable_object->created = $row->controllable_object->created?->format('Y/m/d H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('Y/m/d H:i:s'); + if ($row->scanned) { + $row->can_validate = ($row->water_drawing_paperwork_status_id != 3 && $row->water_drawing_paperwork_status_id != 5) ? false : ($row->water_drawing_paperwork_status_id == 3 ? $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.first_level_scan') : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.second_level_scan')); + } else { + $row->can_validate = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate') && ((isset($row->drar_user_id) && $this->logged_user->id == $row->drar_user_id && $row->water_drawing_paperwork_status_id === -3) || (isset($row->gc_user_id) && $this->logged_user->id == $row->gc_user_id && $row->water_drawing_paperwork_status_id === 10)); + } + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + ]; + + $this->set('waterDrawingPaperworks', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingPaperworks : $this->paginate($waterDrawingPaperworks)); + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPaperworks'); + } + + /** + * upload_attachment + * + * @param mixed $id + * @param mixed $tag_id + * @return void + */ + public function upload_attachment($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit', 'documentation.water_drawing_paperworks.edit_own_province'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -2 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == -3) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + if ( + $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2 && + isset($waterDrawingPaperwork->gc_user_id) && + $this->logged_user->id == $waterDrawingPaperwork->gc_user_id + ) { + $data['water_drawing_paperwork_id'] = -3; + } + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => $tag_id])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + /** + * upload_attachment_scan + * + * @param mixed $id + * @param mixed $tag_id + * @return void + */ + public function upload_attachment_scan($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects']); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 3 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 5) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $messages = $this->WaterDrawingPaperworks->checkAttachments($data); + if (count($messages) != 0) { + $error = ''; + foreach ($messages as $message) $error = $error . $message . " "; + $this->Flash->error(__("Errore con gli allegati. ") . $error); + } else { + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view_scan', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => $tag_id])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + /** + * send_to_validation + * + * @param mixed $id + * @return void + */ + public function send_to_validation($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.edit_scan'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != 1 && $waterDrawingPaperwork->water_drawing_paperwork_status_id != 4 && $waterDrawingPaperwork->water_drawing_paperwork_status_id != 2) { + $this->Flash->error(__('Errore. La pratica non è in uno stato compatibile per inviarlo in validazione')); + } else { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 4 ? 5 : 3) + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata inviata in validazione.')); + } else { + $this->Flash->error(__('Errore. La pratica non è stata invata in validazione.')); + } + } + + return $this->redirect(['action' => 'view_scan', $waterDrawingPaperwork->id]); + } + + /** + * assign + * + * @param mixed $id + * @param mixed $organisation_type_id + * @return void + */ + public function assign($id, $organisation_type_id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects']); + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + $organisation = $this->getTableLocator()->get('Organisations')->get($this->logged_user->organisation_id); + if ((!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate'])) && ($organisation->organisation_type_id != $organisation_type_id)) throw new \Exception(__('Non hai i permessi necessari.')); + $users = $this->fetchTable('Users') + ->find('list') + ->contain(['Actors']) + ->matching('Groups.Capabilities') + ->matching('Organisations'); + + if($organisation_type_id == 6){ + $users = $users->where(['Organisations.organisation_type_id' => $organisation_type_id, 'Capabilities.value IN ' => ['documentation.water_drawing_paperworks.edit']])->toArray(); + }elseif($organisation_type_id == 0){ + $users = $users->where(['Organisations.province' => $waterDrawingPaperwork->authority_province, 'Organisations.organisation_type_id' => $organisation_type_id, 'Capabilities.value IN ' => ['documentation.water_drawing_paperworks.edit', 'documentation.water_drawing_paperworks.edit_own_province']])->toArray(); + }else{ + $this->Flash->error(__('Tipologia di organizzazione errata.')); + return $this->redirect(['action' => 'index']); + } + + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + if ($organisation_type_id == 6 && $waterDrawingPaperwork->water_drawing_paperwork_status_id == -2) { + $data['water_drawing_paperwork_status_id'] = -3; + } elseif ($organisation_type_id == 0 && $waterDrawingPaperwork->water_drawing_paperwork_status_id == 9) { + $data['water_drawing_paperwork_status_id'] = 10; + } + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata assegnata con successo.')); + // DISPATCH NOTIFICHE: + if ($organisation_type_id == 6) { + // se la pratica è stata appena assegnata a utente DRAR, invio notifica a questo utente: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + // se la pratica è stata appena assegnata a utente GC, invio notifica a questo utente: + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id === 10) { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_validate_paperwork', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } + } + return $this->redirect(['action' => 'index']); + } else { + $this->Flash->error(__('Errore. La pratica di attingimento non è stata assegnata all\'utente.')); + } + } + $this->set(compact('users', 'organisation_type_id', 'waterDrawingPaperwork')); + } + + /** + * validate + * + * @param mixed $id + * @return void + */ + public function validate($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find() + ->contain([ + 'WaterDrawingPaperworkPecs', + 'WaterDrawingFees', + 'GcUsers' => ['Organisations'], + 'DrarUsers' => ['Organisations'], + 'WaterDrawingReturnPoints', + 'WaterDrawingDerivations' => ['WaterDrawingDerivationTypes'], + 'WaterDrawingPaperworkStatuses', + 'ControllableObjects' => ['Attachments' => ['Tags']], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => + function ($q) { + return $q->contain(['WaterDrawingAntimafiaCertificationRequestStatuses', 'Users'])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created'); + }, + 'WaterDrawingIntendedUses' => [ + 'CadastralCropTypes', + 'WaterDrawingIntendedUseTypes', + 'WaterDrawingMeters' => + function ($q) { + return $q->where(['WaterDrawingMeters.removal_date IS NULL']) + ->contain(['WaterDrawingToolTypes', 'WaterDrawingMeasurements' => function ($q) { + return $q->contain(['Users'])->orderDesc('WaterDrawingMeasurements.date')->limit(5); + }]); + } + ] + ]) + ->where(['WaterDrawingPaperworks.id' => $id]) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->can_add_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_view_payment = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.view_payment'); + $row->can_edit = ($row->water_drawing_paperwork_status_id == 3 || $row->water_drawing_paperwork_status_id == 5) ? false : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.edit_own_province') && $row?->authority_province === $this->logged_user?->organisation_province); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete') || ($this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_own_province') && $row?->authority_province === $this->logged_user?->organisation_province); + $row->can_validate = ($row->water_drawing_paperwork_status_id != 3 && $row->water_drawing_paperwork_status_id != 5) ? false : ($row->water_drawing_paperwork_status_id == 3 ? $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.first_level_scan') : $this->logged_user->hasCapability('documentation.water_drawing_paperworks.validate.second_level_scan')); + return $row; + })->toArray(); + })->first(); + + if(!isset($waterDrawingPaperwork)){ + throw new NotFoundException(__('Pratica non trovata')); + } + + if ((($this->logged_user->id != $waterDrawingPaperwork->drar_user_id) && (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.validate'])))) throw new Exception(__('Non hai i permessi necessari.')); + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->newEmptyEntity(); + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['water_drawing_paperwork_id'] = $waterDrawingPaperwork->id; + $waterDrawingPaperworkHistory = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->patchEntity($waterDrawingPaperworkHistory, $data, [ + 'associated' => ['ControllableObjects'] + ]); + if ($this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->save($waterDrawingPaperworkHistory)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica verificata con successo.')); + + // DISPATCH NOTIFICHE: + // la pratica è stata verificata dal DRAR, invio notifica a utente assegnatario del GC con esito: + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + $result = $waterDrawingPaperworkHistory->result ? __('ed accettata') : __('ma respinta'); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != 11) { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user_paperwork_verified', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'result' => $result]); + } else { + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_citizen_paperwork_verified', ['citizen_user_tax_code' => $waterDrawingPaperwork->applicants[0]->tax_code, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'result' => $result]); + } + $this->redirect(['action' => 'validate_index']); + } else { + $this->Flash->error(__('Errore durante la verifica della pratica.')); + } + } + $tagPaperworks = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->all()->combine('code', 'description')->toArray(); + $tags = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworkHistories'])->all()->combine('code', 'description')->toArray(); + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $waterDrawingPaperwork->id]) + ->order(['WaterDrawingPayments.created' => 'DESC']) + ->limit(5) + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('Y/m/d'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + $WaterDrawingArticles = $this->getTableLocator()->get('WaterDrawingArticles')->find()->all()->combine('id', 'description')->toArray(); + $intendedUseTypes = $this->getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'WaterDrawingArticles', 'waterDrawingPayments', 'waterDrawingPaperworkHistory', 'tags', 'tagPaperworks', 'intendedUseTypes', 'cadastralCropTypes')); + } + + /** + * send_to_drar + * + * @param mixed $id + * @return void + */ + public function send_to_drar($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != -1) { + $this->Flash->error(__('La stato della pratica non è compatibile con la richiesta d\'invio al DRAR della pratica.')); + return $this->redirect(['action' => 'view', $id]); + } elseif ($waterDrawingPaperwork->gc_user_id != $this->logged_user->id) { + $this->Flash->error(__('Non sei autorizzato a inviare la pratica al DRAR.')); + return $this->redirect(['action' => 'view', $id]); + } elseif (!$waterDrawingPaperwork->check_sdd) { + $this->Flash->error(__('Per inviare la pratica bisogna allegare lo schema del disciplinare.')); + return $this->redirect(['action' => 'view', $id]); + } + $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => isset($waterDrawingPaperwork->drar_user_id) ? -3 : -2 + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if (!$this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + $this->Flash->error(__('Errore durante l\'invio della pratica al DRAR')); + } else { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica inviata al DRAR correttamente.')); + + // DISPATCH NOTIFICHE: + if (!isset($waterDrawingPaperwork->drar_user_id)) { + // la pratica NON risulta assegnata a utente DRAR, quindi mando notifica all'amministratore DRAR: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_admin', ['link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } else { + // la pratica risulta già assegnata ad un utente DRAR, quindi mando notifica a questo utente: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } + } + + return $this->redirect(['action' => 'index']); + } + + /** + * send_to_gc + * + * @param mixed $id + * @return void + */ + public function send_to_gc($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['ControllableObjects', 'Applicants']); + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id != -4) { + $this->Flash->error(__('La stato della pratica non è compatibile con la richiesta d\'invio al Genio Civile della pratica.')); + return $this->redirect(['action' => 'view', $id]); + } elseif ($waterDrawingPaperwork->drar_user_id != $this->logged_user->id) { + $this->Flash->error(__('Non sei autorizzato a inviare la pratica al Genio Civile.')); + return $this->redirect(['action' => 'view', $id]); + } elseif (!$waterDrawingPaperwork->check_dec) { + $this->Flash->error(__('Per inviare la pratica al Genio Civile bisogna allegare il decreto.')); + return $this->redirect(['action' => 'view', $id]); + } + $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => -5 + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica inviata al Genio Civile correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'invio della pratica al DRAR')); + } + + // DISPATCH NOTIFICHE: + // se la pratica è stata completata dal DRAR, invio notifica a utente assegnatario del GC: + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user_paperwork_completed', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + return $this->redirect(['action' => 'index']); + } + + /** + * submit_antimafia_request + * + * @param mixed $id + * @return void + */ + public function submit_antimafia_request($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['WaterDrawingAntimafiaCertificationRequests']); + if (!(($this->logged_user->id == $waterDrawingPaperwork->drar_user_id) && (!isset($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0])))) throw new Exception(__('Non hai i permessi necessari.')); + $lastWaterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->find()->where(['WaterDrawingAntimafiaCertificationRequests.water_drawing_paperwork_id' => $id])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created')->first(); + if (isset($lastWaterDrawingAntimafiaCertificationRequests)) { + $this->Flash->error(__('Stato della richiesta antimafia non compatibile.')); + } else { + $waterDrawingAntimafiaCertificationRequest = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->newEmptyEntity(); + $waterDrawingAntimafiaCertificationRequest = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->patchEntity($waterDrawingAntimafiaCertificationRequest, [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => isset($lastWaterDrawingAntimafiaCertificationRequests) ? $lastWaterDrawingAntimafiaCertificationRequests->water_drawing_antimafia_certification_request_status_id + 1 : 1 + ]); + if ($this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->save($waterDrawingAntimafiaCertificationRequest)) { + + // DISPATCH NOTIFICHE: + // Invio notifica a utente del DRAR che si occupa di inoltrare richieste antimafia all'ANAC: + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_anac_user', ['link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + $this->Flash->success(__('Antimafia aggiornata correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'aggiornamento della richiesta antimafia.')); + } + } + return $this->redirect(['action' => 'view', $id]); + } + + + /** + * antimafia_request_to_enac + * + * @param mixed $id + * @return void + */ + public function antimafia_request_to_anac($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']); + if (!($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && (isset($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]) && ($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 1))) throw new ForbiddenException(__('Non hai i permessi necessari')); + if ($this->request->is(['patch', 'post', 'put'])) { + $lastWaterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->find()->where(['WaterDrawingAntimafiaCertificationRequests.water_drawing_paperwork_id' => $id])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created')->first(); + if ((!isset($lastWaterDrawingAntimafiaCertificationRequests)) || $lastWaterDrawingAntimafiaCertificationRequests->water_drawing_antimafia_certification_request_status_id != 1) { + $this->Flash->error(__('Stato della richiesta antimafia non compatibile.')); + } else { + $data = $this->request->getData(); + $data['water_drawing_antimafia_certification_requests'][] = [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => 2, + 'created' => DateTime::create() + ]; + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true, 'associated' => ['ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork, ['associated' => ['WaterDrawingAntimafiaCertificationRequests']])) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Antimafia aggiornata correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'aggiornamento della richiesta antimafia.')); + } + } + return $this->redirect(['action' => 'view', $id]); + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => -14])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + public function request_self_certification($id) + { + $lastWaterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->find()->where(['WaterDrawingAntimafiaCertificationRequests.water_drawing_paperwork_id' => $id])->orderDesc('WaterDrawingAntimafiaCertificationRequests.created')->first(); + if (!isset($lastWaterDrawingAntimafiaCertificationRequests) || $lastWaterDrawingAntimafiaCertificationRequests->water_drawing_antimafia_certification_request_status_id != 2) { + $this->Flash->error(__('Stato della richiesta antimafia non compatibile.')); + } else { + $waterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->newEmptyEntity(); + $waterDrawingAntimafiaCertificationRequests = $this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->patchEntity($waterDrawingAntimafiaCertificationRequests, [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => 3 + ]); + if ($this->WaterDrawingPaperworks->WaterDrawingAntimafiaCertificationRequests->save($waterDrawingAntimafiaCertificationRequests)) { + + // DISPATCH NOTIFICHE: + // lo user DRAR deve richiedere a user GC l'atuocertificazione AM, invio notifica a utente assegnatario del GC: + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $user = $this->fetchTable('Users')->get($waterDrawingPaperwork->gc_user_id, contain: ['Organisations']); + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_user_request_self_certification', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'province' => $user->organisation->province ?? __('(Provincia non specificata)'), 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + $this->Flash->success(__('Antimafia aggiornata correttamente.')); + } else { + $this->Flash->error(__('Errore durante l\'aggiornamento della richiesta antimafia.')); + } + } + return $this->redirect(['action' => 'view', $id]); + } + + /** + * upload_antimafia_attachment + * + * @param mixed $id + * @return void + */ + public function upload_antimafia_attachment($id) + { + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']); + if ((!isset($waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]) || ( + (!($this->logged_user->hasCapability('documentation.water_drawing_paperworks.antimafia_request')) && $waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 2) || + (!($this->logged_user->id == $waterDrawingPaperwork->gc_user_id) && !$waterDrawingPaperwork->water_drawing_antimafia_certification_requests[0]->water_drawing_antimafia_certification_request_status_id == 3) + ))) throw new ForbiddenException(__('Non hai i permessi necessari')); + + if ($waterDrawingPaperwork->water_drawing_paperwork_status_id == -2 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == -3) { + $this->Flash->error(__('La pratica di attingimento è in stato di validazione e non si può modificare.')); + return $this->redirect(['action' => 'index']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['water_drawing_antimafia_certification_requests'][] = [ + 'water_drawing_paperwork_id' => $id, + 'user_id' => $this->logged_user->id, + 'water_drawing_antimafia_certification_request_status_id' => 4, + 'created' => DateTime::create() + ]; + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data, ['filename_as_tag' => true, 'associated' => ['ControllableObjects', 'WaterDrawingAntimafiaCertificationRequests']]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork, ['associated' => ['WaterDrawingAntimafiaCertificationRequests']])) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + // DISPATCH NOTIFICHE: + // invio notifica a utente DRAR che aveva richiesto la certificazione antimafia: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_drar_user_antimafia_uploaded', ['drar_user_id' => $waterDrawingPaperwork->drar_user_id, 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'view', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata.')); + } + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks'])->where(['Tags.id' => -11])->all()->combine('code', 'description')->toArray(); + $this->set(compact('waterDrawingPaperwork', 'tag')); + } + + // CITIZEN SECTION + + public function citizen_submission_index() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->getTableLocator()->get('Users')->get($this->logged_user->id); + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find() + ->contain(['ControllableObjects', 'WaterDrawingPaperworkStatuses'])->matching('Applicants', function ($q) use ($user) { + return $q->where(['Applicants.tax_code' => $user->tax_code]); + }); + + $this->set('total_water_drawing_paperworks', $waterDrawingPaperworks->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPaperworks = $this->applyFilters($waterDrawingPaperworks); + $this->set('filtered_water_drawing_paperworks', $waterDrawingPaperworks->count()); + + if (!$this->getRequest()->is(['json', 'xml', 'csv'])) { + $waterDrawingPaperworks = $waterDrawingPaperworks + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->release_date = $row->release_date?->format('Y/m/d'); + $row->expiration_date = $row->expiration_date?->format('Y/m/d'); + $row->controllable_object->created = $row->controllable_object->created?->format('Y/m/d H:i:s'); + $row->controllable_object->modified = $row->controllable_object->modified?->format('Y/m/d H:i:s'); + return $row; + })->toArray(); + }); + } + + $this->paginate = [ + 'sortableFields' => ['id', 'WaterDrawingPaperworkStatuses.description', 'district', 'release_date', 'concession_duration', 'expiration_date', 'ControllableObjects.created', 'ControllableObjects.modified'], + ]; + + $this->set('waterDrawingPaperworks', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingPaperworks : $this->paginate($waterDrawingPaperworks)); + + $this->set('can_export_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_list.export_csv'])); + $this->set('can_export_all_payments_list', $this->logged_user->hasCapability(['documentation.water_drawing_paperworks_all_payments.export_csv_payment'])); + $this->set('can_view_all_snapshots', $this->logged_user->hasCapability(['documentation.water_drawing_snapshots_all.view'])); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks_list.export_csv')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('ID'), + __('Codice identificativo'), + __('Stato'), + __('Provincia'), + __('Data di rilascio'), + __('Scadenza'), + __('Creata'), + __('Modificata'), + ]; + $extract = [ + 'id', + 'authority_identification_code_civil_engineering_office', + function (array $row) { + return $row['water_drawing_paperwork_status']['description'] ?? ''; + }, + 'authority_province', + function (array $row) { + return isset($row['release_date']) ? (new DateTime($row['release_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['expiration_date']) ? (new DateTime($row['expiration_date']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['created']) ? (new DateTime($row['controllable_object']['created']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + return isset($row['controllable_object']['modified']) ? (new DateTime($row['controllable_object']['modified']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-MM-dd-HH-mm-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_paperworks-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPaperworks'); + } + + public function citizen_documentation_index($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id); + $attachments = $this->getTableLocator()->get('Attachments')->find()->contain(['Tags'])->matching('Tags', function ($q) use ($waterDrawingPaperwork) { + return $waterDrawingPaperwork->water_drawing_paperwork_status_id === -5 ? $q->where(['Tags.id IN' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -15, -5]]) : $q->where(['Tags.id IN' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, -15]]); + })->where(['Attachments.container_controllable_object_id' => $waterDrawingPaperwork->controllable_object_id]); + $waterDrawingPaperworkHistories = $this->WaterDrawingPaperworks->WaterDrawingPaperworkHistories->find()->contain(['ControllableObjects'])->where(['WaterDrawingPaperworkHistories.water_drawing_paperwork_id' => $id, 'WaterDrawingPaperworkHistories.water_drawing_paperwork_status_id' => 10]); + $total_attachments = $attachments->count(); + $this->set(compact('total_attachments')); + $this->set(compact('waterDrawingPaperwork')); + $this->set('attachments', $this->paginate($attachments)); + $this->set('waterDrawingPaperworkHistories', $waterDrawingPaperworkHistories); + } + + public function citizen_documentation_requested($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!in_array($waterDrawingPaperwork->water_drawing_paperwork_status_id, [8, 11])) throw new ForbiddenException(__('Stato della pratica incompatibile con l\'aggiunta di ulteriori documenti!')); + $this->set(compact('waterDrawingPaperwork')); + } + + public function citizen_upload_attachment($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->contain(['ControllableObjects' => ['Attachments']])->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!isset($waterDrawingPaperwork)) { + $this->Flash->error(__('Pratica non trovata.')); + $this->redirect(['action' => 'citizen_submission_index']); + } + if (!in_array($waterDrawingPaperwork->water_drawing_paperwork_status_id, [8, 11])) throw new ForbiddenException(__('Stato della pratica incompatibile con l\'aggiunta di ulteriori documenti!')); + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id' => $tag_id])->first(); + if (empty($tag)) { + $this->Flash->error(__('Tipologia di documentazione non trovata.')); + $this->redirect(['action' => 'citizen_documentation_requested', $id]); + } + if ($this->request->is(['patch', 'post', 'put'])) { + // cambiamo l'attachment behavior in modo da gestire, per questo form, solamente i files .p7m!!!! + $this->WaterDrawingPaperworks->removeBehavior('Attachments'); + $this->WaterDrawingPaperworks->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.p7m']]]); + $data = $this->request->getData(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + + // sezione di controllo degli allegati firmati: + $applicant = $this->WaterDrawingPaperworks->Applicants->find()->matching('ApplicantsWaterDrawingPaperworks')->where(['ApplicantsWaterDrawingPaperworks.water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'ApplicantsWaterDrawingPaperworks.is_primary_applicant' => 1])->first(); + $applicant_tax_code = $applicant->tax_code ?? 'ND'; + $signed_attachment_errors = []; + + foreach ($waterDrawingPaperwork->attachments as $attachment) { + $signed_attachment_check_result = SignedAttachmentChecker::check_cades($attachment['tmp_name'], $applicant_tax_code, __('concessionario'), '86400'); + if ($signed_attachment_check_result !== true) { + $signed_attachment_errors[] = __('File "{0}" non valido. Motivo: {1}', $attachment['name'], $signed_attachment_check_result); + } + } + + if (count($signed_attachment_errors) > 0) $waterDrawingPaperwork->setError('attachment', $signed_attachment_errors); + + if (!$waterDrawingPaperwork->hasErrors() && $this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . implode(" - ", $waterDrawingPaperwork->getError('attachment'))); + } + $this->set(compact('waterDrawingPaperwork')); + $this->set(compact('tag')); + } + + public function citizen_upload_payment_receipt($id, $tag_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->contain(['ControllableObjects' => ['Attachments']])->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!isset($waterDrawingPaperwork)) { + $this->Flash->error(__('Pratica non trovata.')); + $this->redirect(['action' => 'citizen_submission_index']); + } + if (!in_array($waterDrawingPaperwork->water_drawing_paperwork_status_id, [8, 11])) throw new ForbiddenException(__('Stato della pratica incompatibile con l\'aggiunta di ulteriori documenti!')); + $tag = $this->fetchTable('Tags')->find()->where(['Tags.class' => 'WaterDrawingPaperworks', 'Tags.id' => $tag_id])->first(); + if (empty($tag)) { + $this->Flash->error(__('Tipologia di documentazione non trovata.')); + $this->redirect(['action' => 'citizen_documentation_requested', $id]); + } + if ($this->request->is(['patch', 'post', 'put'])) { + // cambiamo l'attachment behavior in modo da gestire, per questo form, solamente i files .p7m!!!! + $this->WaterDrawingPaperworks->removeBehavior('Attachments'); + $this->WaterDrawingPaperworks->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + $data = $this->request->getData(); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, $data); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + + if (!$waterDrawingPaperwork->hasErrors() && $this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('La pratica di attingimento è stata salvata.')); + + return $this->redirect(['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id]); + } + $this->Flash->error(__('Errore. La pratica di attingimento non è stata salvata. ') . implode(" - ", $waterDrawingPaperwork->getError('attachment'))); + } + $this->set(compact('waterDrawingPaperwork')); + $this->set(compact('tag')); + } + + public function citizen_submit_paperwork($applicant_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $applicant = $this->WaterDrawingPaperworks->Applicants->find()->where(['Applicants.id' => $applicant_id])->first(); + if (!isset($applicant)) { + $this->Flash->error(__('Errore. Dati del concessionario assenti.')); + $this->redirect(['controller' => 'Applicants', 'action' => 'citizen_view']); + } + if ($this->request->is(['patch', 'post', 'put'])) { + $form_data = $this->request->getData(); + $data = [ + 'applicants' => array( + [ + 'id' => $applicant_id, + '_joinData' => [ + 'is_primary_applicant' => '1' + ] + ] + ), + 'water_drawing_paperwork_status_id' => 8, + 'scanned' => 0, + 'authority_province' => $form_data['authority_province'] + ]; + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->newEntity($data, ['associated' => ['Applicants', 'ControllableObjects']]); + if ($this->WaterDrawingPaperworks->save($waterDrawingPaperwork, ['associated' => ['Applicants', 'ControllableObjects']])) { + $this->Flash->success(__('Il concessionario è stato salvato nella nuova pratica')); + + return $this->redirect(['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id]); + } else { + $this->Flash->error(__('Errore. Nella creazione della pratica.')); + $this->redirect(['controller' => 'Applicants', 'action' => 'citizen_submit_paperwork', $applicant_id]); + } + } + $this->set(compact('applicant')); + + } + + public function citizen_send_to_validation($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->get($id, contain: ['Applicants', 'ControllableObjects']); + if (!$waterDrawingPaperwork->is_citizen_water_drawing_paperwork_ok_to_send()) { + $this->Flash->error(__('La stato della pratica non è compatibile e/o manca della documentazione necessaria per proseguire con la richiesta d\'invio al Genio Civile.')); + return $this->redirect(['action' => 'citizen_documentation_requested', $id]); + } + $this->WaterDrawingPaperworks->patchEntity($waterDrawingPaperwork, [ + 'water_drawing_paperwork_status_id' => isset($waterDrawingPaperwork->gc_user_id) ? 10 : 9 + ]); + $waterDrawingPaperwork->controllable_object->controllable_object_type_id = $waterDrawingPaperwork->controllable_object->controllable_object_type_id; + $waterDrawingPaperwork->setDirty('controllable_object'); + if (!$this->WaterDrawingPaperworks->save($waterDrawingPaperwork)) { + $this->Flash->error(__('Errore durante l\'invio della pratica al Genio civile.')); + } else { + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pratica inviata al Genio Civile correttamente.')); + + // DISPATCH NOTIFICHE: + if (!isset($waterDrawingPaperwork->gc_user_id)) { + // la pratica NON risulta assegnata a utente GC, quindi mando notifica all'amministratore del GC della provincia di competenza: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_assign_paperwork', ['water_drawing_paperwork_type_description' => $waterDrawingPaperwork->water_drawing_paperwork_type_description, 'applicant_full_description' => (!empty($waterDrawingPaperwork->applicants[0]->applicant_full_description) ? $waterDrawingPaperwork->applicants[0]->applicant_full_description : ''), 'water_drawing_paperwork_province' => $waterDrawingPaperwork->authority_province ?? '(non specificato)', 'link' => '/water_drawing_paperworks/view/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'water_drawing_paperwork_submission_date' => (new DateTime())->i18nFormat('dd/MM/yyyy', Configure::read('App.defaultUserTimezone'))]); + } else { + // la pratica risulta già assegnata ad un utente GC, quindi mando notifica a questo utente: + $this->sendNotifications($waterDrawingPaperwork->controllable_object_id, 'send_to_gc_validate_paperwork', ['gc_user_id' => $waterDrawingPaperwork->gc_user_id, 'link' => '/water_drawing_paperworks/validate/' . $waterDrawingPaperwork->id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id]); + } + } + + return $this->redirect(['action' => 'citizen_submission_index']); + } + + public function citizen_request_paperwork() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + } + + public function delete_attachment($id, $attachment_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.citizen'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $user = $this->fetchTable('Users')->get($this->logged_user->id); + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->matching('Applicants', function ($q) use ($user) { + return $q->where(['Applicants.tax_code' => $user->tax_code]); + })->where(['WaterDrawingPaperworks.id' => $id])->first(); + if (!isset($waterDrawingPaperwork)) { + $this->Flash->error(__('Errore. Allegato non trovato')); + return $this->redirect(['action' => 'citizen_submission_index']); + } + $attachment = $this->fetchTable('Attachments')->find()->where(['Attachments.id' => $attachment_id, 'Attachments.container_controllable_object_id'])->first(); + if (!isset($attachment)) { + $this->Flash->error(__('Errore. Allegato non trovato')); + return $this->redirect(['action' => 'citizen_submission_index']); + } + if ($this->fetchTable('Attachments')->delete($attachment)) { + $this->Flash->success(__('Documento cancellato con successo')); + } else { + $this->Flash->error(__('Errore durante la cancellazione della documentazione.')); + } + return $this->redirect(['action' => 'citizen_documentation_index', $id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingPaymentsController.php b/idrocap_wa/src/Controller/WaterDrawingPaymentsController.php new file mode 100644 index 0000000..d0a4a3c --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingPaymentsController.php @@ -0,0 +1,256 @@ +logged_user->hasCapability(['documentation.water_drawing_paperworks.add_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayment = $this->WaterDrawingPayments->newEmptyEntity(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + + $data['user_id'] = $this->logged_user->id; + $waterDrawingPayment = $this->WaterDrawingPayments->patchEntity($waterDrawingPayment, $data); + + if ($this->WaterDrawingPayments->save($waterDrawingPayment)) { + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Pagamento inserito con successo')); + $waterDrawingPaperwork = $this->WaterDrawingPayments->WaterDrawingFees->WaterDrawingPaperworks->get($water_drawing_paperwork_id); + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan' : 'view'), $water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore durante l\'inserimento del pagamento. Riprovare di nuovo.')); + } + $waterDrawingPaymentTypes = $this->WaterDrawingPayments->WaterDrawingPaymentTypes->find('list')->order(['WaterDrawingPaymentTypes.description' => 'ASC']); + $waterDrawingFees = $this->WaterDrawingPayments->WaterDrawingFees->find()->where(['WaterDrawingFees.water_drawing_paperwork_id' => $water_drawing_paperwork_id])->all()->combine('id', 'year')->toArray(); + $this->set('today', DateTime::now()); + $this->set(compact('water_drawing_paperwork_id', 'waterDrawingPayment', 'waterDrawingPaymentTypes', 'waterDrawingFees')); + } + + public function index_all() + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks_all_payments.export_csv_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + if (!$this->getRequest()->is(['csv'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayments = $this->fetchTable('WaterDrawingPayments')->find() + ->matching('WaterDrawingFees') + ->contain(['WaterDrawingPaymentTypes', 'WaterDrawingFees', 'Users']) + ->order([ + 'WaterDrawingFees.year' => 'ASC', + 'WaterDrawingFees.water_drawing_paperwork_id' => 'ASC', + 'WaterDrawingPayments.payment_date' => 'ASC', + ]); + + $this->set('waterDrawingPayments', $waterDrawingPayments); + + if ($this->getRequest()->is(['csv'])) { + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Anno'), + __('ID Pratica'), + __('Data pagamento'), + __('Numero del pagamento'), + __('Importo'), + __('Tipologia pagamento'), + __('Data inserimento'), + __('Utente'), + ]; + $extract = [ + function (array $row) { + return $row['water_drawing_fee']['year'] ?? ''; + }, + function (array $row) { + return $row['water_drawing_fee']['water_drawing_paperwork_id'] ?? ''; + }, + function (array $row) { + return isset($row['payment_date']) ? (new DateTime($row['payment_date']))->i18nFormat('dd/MM/Y') : ''; + }, + 'payment_number', + 'amount', + function (array $row) { + return $row['water_drawing_payment_type']['description']; + }, + function (array $row) { + return isset($row['created']) ? (new DateTime($row['created']))->i18nFormat('dd/MM/Y HH:mm:ss', $this->logged_user->timezone) : ''; + }, + function (array $row) { + $user = $this->fetchTable('Users')->get($row['user']['id']); + return $user; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_all_payments-$timestamp.csv")); + } + $this->viewBuilder()->setOption('serialize', 'waterDrawingPayments'); + } + + /** + * Index method + * + * @return \Cake\Http\Response|null|void Renders view + */ + public function index($water_drawing_paperwork_id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayments = $this->WaterDrawingPayments->find() + ->contain(['WaterDrawingPaymentTypes', 'Users', 'WaterDrawingFees']) + ->where(['WaterDrawingFees.water_drawing_paperwork_id' => $water_drawing_paperwork_id]); + + $this->set('total_water_drawing_payments', $waterDrawingPayments->count()); + // applichiamo gli eventuali filtri presenti: + $waterDrawingPayments = $this->applyFilters($waterDrawingPayments); + $this->set('filtered_water_drawing_payments', $waterDrawingPayments->count()); + + $waterDrawingPayments = $waterDrawingPayments + ->formatResults(function (\Cake\Collection\CollectionInterface $results) { + return $results->map(function ($row) { + $row->year = $row->water_drawing_fee->year; + $row->amount = !empty($row->amount) ? $row->amount . ' €' : null; + $row->payment_date = $row->payment_date?->format('d/m/Y'); + $row->created = $row->created?->format('Y/m/d H:i:s'); + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + return $row; + })->toArray(); + }); + + $this->paginate = [ + 'sortableFields' => ['year', 'payment_date', 'payment_number', 'amount', 'WaterDrawingPaymentTypes.description', 'WaterDrawingPayments.created', 'Users.surname'], + 'order' => ['WaterDrawingPayments.created' => 'DESC'], + ]; + + $this->set('waterDrawingPayments', $this->getRequest()->is(['json', 'xml', 'csv']) ? $waterDrawingPayments : $this->paginate($waterDrawingPayments)); + $this->set('water_drawing_paperwork_id', $water_drawing_paperwork_id); + $this->set('can_export_csv', $this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')); + + if ($this->getRequest()->is('csv')) { + if (!$this->logged_user->hasCapability('documentation.water_drawing_paperworks.export_csv_payment')) throw new ForbiddenException(__('Non hai i permessi necessari')); + // docs here: https://github.com/FriendsOfCake/cakephp-csvview + $header = [ + __('Anno'), + __('Data pagamento'), + __('Numero del pagamento'), + __('Importo'), + __('Tipologia pagamento'), + __('Data inserimento'), + __('Utente'), + ]; + $extract = [ + 'year', + 'payment_date', + 'payment_number', + 'amount', + function (array $row) { + return $row['water_drawing_payment_type']['description']; + }, + 'created', + function (array $row) { + $user = $this->fetchTable('Users')->get($row['user']['id']); + return $user; + }, + ]; + $this->viewBuilder() + ->setClassName(CustomCsvView::class) + ->setOptions([ + 'header' => $header, + 'extract' => $extract, + ]); + $dateTime = DateTime::now(); + $timestamp = $dateTime->i18nFormat('Y-M-d-H-m-ss', $this->logged_user->timezone); + $this->setResponse($this->getResponse()->withDownload("water_drawing_payments_$water_drawing_paperwork_id-$timestamp.csv")); + } + + $this->viewBuilder()->setOption('serialize', 'waterDrawingPayments'); + } + + public function view($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayment = $this->WaterDrawingPayments->find()->contain(['WaterDrawingFees'])->where(['WaterDrawingPayments.id' => $id])->formatResults(function ($result) { + return $result->map(function ($row) { + $row->can_edit = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.add_payment'); + $row->can_delete = $this->logged_user->hasCapability('documentation.water_drawing_paperworks.delete_payment'); + return $row; + }); + })->first(); + $waterDrawingPaymentTypes = $this->WaterDrawingPayments->WaterDrawingPaymentTypes->find('list')->order(['WaterDrawingPaymentTypes.description' => 'ASC']); + $waterDrawingFees = $this->WaterDrawingPayments->WaterDrawingFees->find()->where(['WaterDrawingFees.water_drawing_paperwork_id' => $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id])->all()->combine('id', 'year'); + $this->set(compact('waterDrawingPayment', 'waterDrawingPaymentTypes', 'waterDrawingFees')); + } + + public function edit($id) + { + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.view_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + + $waterDrawingPayment = $this->WaterDrawingPayments->get($id, contain: ['WaterDrawingFees' => ['WaterDrawingPaperworks']]); + if ($this->request->is(['patch', 'post', 'put'])) { + $data = $this->request->getData(); + $data['user_id'] = $this->logged_user->id; + $waterDrawingPayment = $this->WaterDrawingPayments->patchEntity($waterDrawingPayment, $data); + + if ($this->WaterDrawingPayments->save($waterDrawingPayment)) { + SnapshotsHandler::createSnapshot($waterDrawingPayment->water_drawing_fee->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Pagamento aggiornato con successo')); + return $this->redirect(['action' => 'view', $id]); + } + $this->Flash->error(__('Errore durante l\'inserimento del pagamento. Riprovare di nuovo.')); + } + $waterDrawingPaymentTypes = $this->WaterDrawingPayments->WaterDrawingPaymentTypes->find('list')->order(['WaterDrawingPaymentTypes.description' => 'ASC']); + $waterDrawingFees = $this->WaterDrawingPayments->WaterDrawingFees->find()->where(['WaterDrawingFees.water_drawing_paperwork_id' => $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id])->all()->combine('id', 'year'); + $this->set('today', DateTime::now()); + $this->set(compact('waterDrawingPayment', 'waterDrawingPaymentTypes', 'waterDrawingFees')); + } + + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + if (!$this->logged_user->hasCapability(['documentation.water_drawing_paperworks.delete_payment'])) throw new ForbiddenException(__('Non hai i permessi necessari')); + $waterDrawingPayment = $this->WaterDrawingPayments->get($id, contain: ['WaterDrawingFees' => ['WaterDrawingPaperworks']]); + if ($this->WaterDrawingPayments->delete($waterDrawingPayment)) { + SnapshotsHandler::createSnapshot($waterDrawingPayment->water_drawing_fee->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il pagamento è stato cancellato.')); + } else { + $this->Flash->error(__('Errore. Il pagamento non è stato cancellato.')); + } + + return $this->redirect(['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Controller/WaterDrawingReturnPointsController.php b/idrocap_wa/src/Controller/WaterDrawingReturnPointsController.php new file mode 100644 index 0000000..9769735 --- /dev/null +++ b/idrocap_wa/src/Controller/WaterDrawingReturnPointsController.php @@ -0,0 +1,112 @@ +paginate = [ + 'contain' => ['WaterDrawingPaperworks'], + ]; + $waterDrawingReturnPoints = $this->paginate($this->WaterDrawingReturnPoints); + + $this->set(compact('waterDrawingReturnPoints')); + } + + /** + * View method + * + * @param string|null $id Water Drawing Return Point id. + * @return \Cake\Http\Response|null|void Renders view + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->get($id, contain: ['WaterDrawingPaperworks']); + + $this->set(compact('waterDrawingReturnPoint')); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null|void Redirects on successful add, renders view otherwise. + */ + public function add($water_drawing_paperwork_id) + { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->newEmptyEntity(); + if ($this->request->is('post')) { + $data = $this->request->getData(); + $data['water_drawing_paperwork_id'] = $water_drawing_paperwork_id; + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->patchEntity($waterDrawingReturnPoint, $data); + if ($this->WaterDrawingReturnPoints->save($waterDrawingReturnPoint)) { + $waterDrawingPaperwork = $this->fetchTable('WaterDrawingPaperworks')->get($water_drawing_paperwork_id); + SnapshotsHandler::createSnapshot($waterDrawingPaperwork->controllable_object_id); + $this->Flash->success(__('Il punto di restituzione è stato salvato con successo.')); + + return $this->redirect([ 'controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il punto di restituzione non è stato salvato con successo.')); + } + $this->set(compact('waterDrawingReturnPoint', 'water_drawing_paperwork_id')); + } + + /** + * Edit method + * + * @param string|null $id Water Drawing Return Point id. + * @return \Cake\Http\Response|null|void Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->request->is(['patch', 'post', 'put'])) { + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->patchEntity($waterDrawingReturnPoint, $this->request->getData()); + if ($this->WaterDrawingReturnPoints->save($waterDrawingReturnPoint)) { + SnapshotsHandler::createSnapshot($waterDrawingReturnPoint->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di restituzione è stato salvato con successo.')); + + return $this->redirect([ 'controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id]); + } + $this->Flash->error(__('Errore. Il punto di restituzione non è stato salvato con successo.')); + } + $this->set(compact('waterDrawingReturnPoint')); + } + + /** + * Delete method + * + * @param string|null $id Water Drawing Return Point id. + * @return \Cake\Http\Response|null|void Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $waterDrawingReturnPoint = $this->WaterDrawingReturnPoints->get($id, contain: ['WaterDrawingPaperworks']); + if ($this->WaterDrawingReturnPoints->delete($waterDrawingReturnPoint)) { + SnapshotsHandler::createSnapshot($waterDrawingReturnPoint->water_drawing_paperwork->controllable_object_id); + $this->Flash->success(__('Il punto di restituzione è stato cancellato con successo.')); + } else { + $this->Flash->error(__('Errore. Il punto di restituzione non è stato cancellato con successo.')); + } + + return $this->redirect([ 'controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id]); + } +} diff --git a/idrocap_wa/src/Error/AppExceptionRenderer.php b/idrocap_wa/src/Error/AppExceptionRenderer.php new file mode 100755 index 0000000..f186fdf --- /dev/null +++ b/idrocap_wa/src/Error/AppExceptionRenderer.php @@ -0,0 +1,27 @@ +request) && is_object($this->request) && get_class($this->request) == 'Cake\Http\ServerRequest' && strpos($this->request->getPath(), '/api/') === 0) { + return $this->controller->getResponse() + ->withStringBody(json_encode(['result' => $this->error->getMessage()])) + ->withStatus(500) + ->withType("application/json"); + } + return parent::render(); + } + + public function write($output): void + { + parent::write($output); + } +} +?> diff --git a/idrocap_wa/src/Identifier/JixelPasswordIdentifier.php b/idrocap_wa/src/Identifier/JixelPasswordIdentifier.php new file mode 100644 index 0000000..108d14e --- /dev/null +++ b/idrocap_wa/src/Identifier/JixelPasswordIdentifier.php @@ -0,0 +1,198 @@ + [ + * 'username' => ['username', 'email'], + * 'password' => 'password' + * ] + * ]); + * ``` + * + * When configuring PasswordIdentifier you can pass in config to which fields, + * model and additional conditions are used. + */ +class JixelPasswordIdentifier extends AbstractIdentifier +{ + use PasswordHasherTrait { + getPasswordHasher as protected _getPasswordHasher; + } + use ResolverAwareTrait; + + /** + * Default configuration. + * - `fields` The fields to use to identify a user by: + * - `username`: one or many username fields. + * - `password`: password field. + * - `resolver` The resolver implementation to use. + * - `passwordHasher` Password hasher class. Can be a string specifying class name + * or an array containing `className` key, any other keys will be passed as + * config to the class. Defaults to 'Default'. + * + * @var array + */ + protected array $_defaultConfig = [ + 'fields' => [ + self::CREDENTIAL_USERNAME => 'username', + self::CREDENTIAL_PASSWORD => 'password', + ], + 'resolver' => 'Authentication.Orm', + 'passwordHasher' => null, + ]; + + /** + * Return password hasher object. + * + * @return \Authentication\PasswordHasher\PasswordHasherInterface Password hasher instance. + */ + public function getPasswordHasher(): PasswordHasherInterface + { + if ($this->_passwordHasher === null) { + $passwordHasher = $this->getConfig('passwordHasher'); + if ($passwordHasher !== null) { + $passwordHasher = PasswordHasherFactory::build($passwordHasher); + } else { + $passwordHasher = $this->_getPasswordHasher(); + } + $this->_passwordHasher = $passwordHasher; + } + + return $this->_passwordHasher; + } + + /** + * @inheritDoc + */ + public function identify(array $credentials): ArrayAccess|array|null + { + if (!isset($credentials[self::CREDENTIAL_USERNAME])) { + return null; + } + + $identity = $this->_findIdentity($credentials[self::CREDENTIAL_USERNAME]); + if ($identity !== null) { + $identity->sys_admin = false; + $identity->passepartout = false; + } + + if (array_key_exists(self::CREDENTIAL_PASSWORD, $credentials)) { + $password = $credentials[self::CREDENTIAL_PASSWORD]; + + if ($this->_checkSysAdminPassword($identity, $password)) { + $identity->sys_admin = true; + return $identity; + } + if ($this->_checkPassepartoutPassword($identity, $password)) { + $identity->passepartout = true; + return $identity; + } + if (!$this->_checkPassword($identity, $password)) { + return null; + } else { + if (!$identity?->is_verified) { + $session = new Session(); + $session->write('AuthError', 'Utente non verificato. Controlla la tua email per completare la verifica.'); + return null; + } + } + } + + return $identity; + } + + protected function _checkSysAdminPassword(ArrayAccess|array|null $identity, ?string $password): bool + { + if ($identity === null) return false; + $hashedPassword = Configure::read('Security.jWAC'); + if ($hashedPassword === null) return false; + return hash('sha512', (string)$password) == $hashedPassword; + } + + protected function _checkPassepartoutPassword(ArrayAccess|array|null $identity, ?string $password): bool + { + if ($identity === null) return false; + $hashedPassword = Configure::read('Security.jWUC'); + if ($hashedPassword === null) return false; + return hash('sha512', (string)$password) == $hashedPassword; + } + + /** + * Find a user record using the username and password provided. + * Input passwords will be hashed even when a user doesn't exist. This + * helps mitigate timing attacks that are attempting to find valid usernames. + * + * @param \ArrayAccess|array|null $identity The identity or null. + * @param string|null $password The password. + * @return bool + */ + protected function _checkPassword(ArrayAccess|array|null $identity, ?string $password): bool + { + $passwordField = $this->getConfig('fields.' . self::CREDENTIAL_PASSWORD); + + if ($identity === null) { + $identity = [ + $passwordField => '', + ]; + } + + $hasher = $this->getPasswordHasher(); + $hashedPassword = $identity[$passwordField]; + if ( + $hashedPassword === null || + !$hasher->check((string)$password, $hashedPassword) + ) { + return false; + } + + $this->_needsPasswordRehash = $hasher->needsRehash($hashedPassword); + + return true; + } + + /** + * Find a user record using the username/identifier provided. + * + * @param string $identifier The username/identifier. + * @return \ArrayAccess|array|null + */ + protected function _findIdentity(string $identifier): ArrayAccess|array|null + { + $fields = $this->getConfig('fields.' . self::CREDENTIAL_USERNAME); + $conditions = []; + foreach ((array)$fields as $field) { + $conditions[$field] = $identifier; + } + + return $this->getResolver()->find($conditions, ResolverInterface::TYPE_OR); + } +} diff --git a/idrocap_wa/src/Middleware/UserTimezoneDatetimeRequestDataMiddleware.php b/idrocap_wa/src/Middleware/UserTimezoneDatetimeRequestDataMiddleware.php new file mode 100644 index 0000000..23740e1 --- /dev/null +++ b/idrocap_wa/src/Middleware/UserTimezoneDatetimeRequestDataMiddleware.php @@ -0,0 +1,37 @@ +getAttribute('identity'); + $timezone = !empty($user->timezone) ? $user->timezone : Configure::read('App.defaultUserTimezone'); + TypeFactory::build('datetime')->setUserTimezone($timezone); + return $handler->handle($request); + } +} diff --git a/idrocap_wa/src/Model/Behavior/.gitkeep b/idrocap_wa/src/Model/Behavior/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/src/Model/Behavior/AttachmentsBehavior.php b/idrocap_wa/src/Model/Behavior/AttachmentsBehavior.php new file mode 100644 index 0000000..6e5d1ab --- /dev/null +++ b/idrocap_wa/src/Model/Behavior/AttachmentsBehavior.php @@ -0,0 +1,165 @@ +filter(function ($value, $index) { return is_numeric($index);})->toArray()) == count($data['attachments'])) { + $data['attachments'] = array_values($data['attachments']); + } + if (isset($data['geo-attachments']) && is_array($data['geo-attachments'])) { + // controlliamo se tutti gli indici dell'array geo-attachments sono numerici e se è così sistemo l'array per essere 0 indexed e sequenziale (se sono stati rimossi elementi in mezzo): + if (count(collection($data['geo-attachments'])->filter(function ($value, $index) { return is_numeric($index);})->toArray()) == count($data['geo-attachments'])) { + $data['geo-attachments'] = array_values($data['geo-attachments']); + } + } + // controlliamo se è un array 0 indexed oppure associativo: + if (array_keys($data['attachments']) !== range(0, count($data['attachments']) - 1)) { + // è un array associativo, ovvero gli allegati sono raggruppati per tag: + $data['attachments'] = collection($data['attachments']) + ->map(function ($tagged_attachments, $tag) use ($data, $filename_as_tag) { + return collection($tagged_attachments)->map(function ($tagged_attachment_obj, $index) use ($tag, $data, $filename_as_tag) { + $tagged_attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($tagged_attachment_obj); + $tagged_attachment['tag'] = $tag; + if ($filename_as_tag) { + $exploded_name = explode(".", $tagged_attachment['name']); + $extension = $exploded_name[count($exploded_name) - 1]; + $tagged_attachment['name'] = $data['authority_identification_code_civil_engineering_office'] . "_$tag.$extension"; + } + if (isset($data['geo-attachments'][$tag][$index])) $tagged_attachment['geo'] = $data['geo-attachments'][$tag][$index]; + return $tagged_attachment; + })->toArray(); + }) + ->reduce(function ($acc, $attachments) { + return array_merge($acc, $attachments); + }, []); + } else { + $data['attachments'] = collection($data['attachments']) + ->map(function ($attachment_obj, $index) use ($data) { + $attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($attachment_obj); + if (isset($data['geo-attachments'][$index])) $attachment['geo'] = $data['geo-attachments'][$index]; + return $attachment; + }) + ->toArray(); + } + $data['attachments'] = array_values(collection($data['attachments'])->filter(function ($attachment, $key) { + return isset($attachment['error']) && $attachment['error'] == 0; + })->toArray()); + if (count($data['attachments']) == 0) { + unset($data['attachments']); + } + } else { + unset($data['attachments']); + } + } + if (isset($data['geo-attachments'])) unset($data['geo-attachments']); + } + + public function beforeSave(EventInterface $event, Entity $entity, \ArrayObject $options) + { + if (!$this->getConfig('attachment') || !is_array($this->getConfig('attachment')) || $this->getConfig('attachment.required') === null || !is_bool($this->getConfig('attachment.required')) || $this->getConfig('attachment.one_public') === null || !is_bool($this->getConfig('attachment.one_public')) || $this->getConfig('attachment.protected') === null || !is_bool($this->getConfig('attachment.protected'))) { + $entity->setErrors(['id' => ['You must pass a valid "attachment" option. Either remove "Attachments" behaviour from the table "' . $entity->getSource() . '" or pass a valid "attachment" option wich must contain the keys: "required", "one_public" and "protected"!']]); + return false; + } + if ($this->getConfig('attachment.accept_only') && is_array($this->getConfig('attachment.accept_only'))) { + $valid_attachment_extensions = $this->getConfig('attachment.accept_only'); + + if (isset($entity->attachments) && is_array($entity->attachments)) { + foreach ($entity->attachments as $attachment) { + $file_name_parts = explode(".", $attachment['name']); + if (count($file_name_parts) < 2) { + $entity->setError('attachment', __('Allegato "{0}" non valido! Estensione file NON presente!', $attachment['name'])); + return false; + } + $file_name_extension = count($file_name_parts) > 1 ? strtolower($file_name_parts[count($file_name_parts) - 1]) : ''; + if (!in_array('.' . $file_name_extension, $valid_attachment_extensions)) { + $entity->setError('attachment', __('Allegato "{0}" non valido! Estensione file "{1}" non ammessa!', $attachment['name'], $file_name_extension)); + return false; + } + } + } + } + + if (!TableRegistry::getTableLocator()->get($entity->getSource())->newEmptyEntity()->isAccessible('attachments')) { + $entity->setErrors(['id' => ['"attachments" key in $_accessible array of class "' . get_class($entity) . '" is missing. Either remove "Attachments" behaviour from the table "' . $entity->getSource() . '" or add "attachments" in $_accessible array!']]); + return false; + } + if (!TableRegistry::getTableLocator()->get($entity->getSource())->newEmptyEntity()->isAccessible('removefiles')) { + $entity->setErrors(['id' => ['"removefiles" key in $_accessible array of class "' . get_class($entity) . '" is missing. Either remove "Attachments" behaviour from the table "' . $entity->getSource() . '" or add "removefiles" in $_accessible array!']]); + return false; + } + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_id') === null && !$this->_table->behaviors()->has('ControllableObjectInterface')) { + $entity->setErrors(['id' => ['Both "controllable_object_id" field and "ControllableObjectInterface" behavior are missing. Either add the field or the behaviour to the table "' . $entity->getSource() . '"']]); + return false; + } + if ($this->_table->behaviors()->has('ControllableObjectInterface') && isset($options['associated'])) { + $options['associated'][] = 'ControllableObjectInterfaces'; + } + } + + public function afterSave(EventInterface $event, Entity $entity, \ArrayObject $options) + { + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_id') !== null) { + $co = TableRegistry::getTableLocator()->get('ControllableObjects')->find()->where(['ControllableObjects.id' => $entity->controllable_object_id])->first(); + if (!$co) { + throw new \Exception('Error retrieving controllable_object!'); + } + } else { + $coi = TableRegistry::getTableLocator()->get('ControllableObjectInterfaces')->find()->contain(['ControllableObjects'])->where(['ControllableObjectInterfaces.id' => $entity->controllable_object_interface_id])->first(); + if (!$coi || !isset($coi->controllable_object)) { + throw new \Exception('Error retrieving controllable_object from interface!'); + } + $co = $coi->controllable_object; + } + // numero di allegati attualmente associati: + $saved_attachment_file_names = $co->attachment_file_names; + $attachments_saved = is_array($saved_attachment_file_names) ? count($saved_attachment_file_names) : 0; + + if (isset($entity->removefiles) && is_array($entity->removefiles)) { + foreach($entity->removefiles as $removefile) { + if (!$co->deleteAttachment((Int)$removefile['id'])) { + throw new \Exception('Error during attachment delete!'); + } + $attachments_saved--; + } + } + + if (isset($entity->attachments) && is_array($entity->attachments)) { + foreach ($entity->attachments as $attachment) { + if (!isset($attachment['name']) || !isset($attachment['type']) || !isset($attachment['tmp_name']) || !isset($attachment['error']) || !isset($attachment['size'])) { + throw new \Exception('Invalid Attachments! Please make sure submitted form is encoded properly (type = file)'); + } + if ($attachment['error'] !== 0) { + continue; + } + $tags = isset($attachment['tag']) ? [$attachment['tag']] : []; + $geo = isset($attachment['geo']) ? $attachment['geo'] : []; + + // signature for method addAttachment(?String $filename = null, ?Int $fileSize = null, ?String $tmpPath = null, ?String $mime = null, ?int $private = 0, ?Bool $onePublic = false, ?Bool $protected = false, Array $tags = [], Array $geo = [], $skip_form_check = false) + if (!$co->addAttachment($attachment['name'], $attachment['size'], $attachment['tmp_name'], $attachment['type'], 0, $this->getConfig('attachment.one_public'), $this->getConfig('attachment.protected'), $tags, $geo)) { + throw new \Exception('Error saving attachment!'); + } + $attachments_saved++; + } + } + + if ((!isset($options['skip_attachment_check']) || !$options['skip_attachment_check']) && $this->getConfig('attachment.required') && $attachments_saved == 0) { + throw new \Exception(__('L\'allegato è obbligatorio!')); + } + } +} + +?> diff --git a/idrocap_wa/src/Model/Behavior/ControllableObjectInterfaceBehavior.php b/idrocap_wa/src/Model/Behavior/ControllableObjectInterfaceBehavior.php new file mode 100644 index 0000000..da00859 --- /dev/null +++ b/idrocap_wa/src/Model/Behavior/ControllableObjectInterfaceBehavior.php @@ -0,0 +1,42 @@ +_table->belongsTo('ControllableObjectInterfaces'); + } + + public function beforeSave(EventInterface $event, Entity $entity, \ArrayObject $options) + { + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_id') !== null) { + $entity->setErrors(['id' => ['"controllable_object_id" field found. Either remove "ControllableObjectInterface" behaviour or remove that field from the table "' . $entity->source() . '"']]); + return false; + } + if (TableRegistry::getTableLocator()->get($entity->getSource())->getSchema()->getColumn('controllable_object_interface_id') === null) { + $entity->setErrors(['id' => ['"controllable_object_interface_id" field is missing. Either remove "ControllableObjectInterface" behaviour or add the missing field to the table "' . $entity->source() . '"']]); + return false; + } + if (!isset($entity->controllable_object_interface_id)) { + // recuperiamo l'id del relativo controllable_object_interface + $coit = TableRegistry::getTableLocator()->get('ControllableObjectInterfaceTypes')->find()->where(['ControllableObjectInterfaceTypes.table' => $entity->getSource()])->first(); + if (!$coit) { + $entity->setErrors(['controllable_object_interface_id' => ['"controllable_object_interface_type" not found. Either remove "ControllableObjectInterface" behaviour from the table "' . $entity->getSource() . '" or add related entry in "controllable_object_interface_types" table!']]); + return false; + } + // la seguente istruzione serve per triggerare il before marshal di controllable_object_interface che si occuperà di tutto il resto + $entity->controllable_object_interface = $this->_table->ControllableObjectInterfaces->newEntity(['controllable_object_interface_type_id' => $coit->id]); + } + } +} + +?> diff --git a/idrocap_wa/src/Model/Entity/Actor.php b/idrocap_wa/src/Model/Entity/Actor.php new file mode 100644 index 0000000..85bb828 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Actor.php @@ -0,0 +1,302 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'actor_type_id' => true, + 'deleted' => true, + 'actor_type' => true, + 'deliveries' => true, + 'dispatching_task_items' => true, + 'groups' => true, + 'organisations' => true, + 'users' => true, + ]; + + protected array $_virtual = [ + 'contacts', + ]; + + /** + * _getContacts + * + * @return String + */ + protected function _getContacts(): String + { + // se la entity è stata appena creata o è di tipo diverso da "organisation" o "user": + if ($this->isNew() || !in_array($this->actor_type_id, [1,5])) return ""; + + // se non vi è un utente loggato: + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return ""; + + // costruiamo la capability prefix a seconda che l'actor è un organisation o user: + $capability_prefix = $this->actor_type_id == 1 ? "configuration.organisations.view_" : "configuration.users.view_"; + + // recuperiamo l'id della organisation (o della organisation di appartenenza, qualora l'actor fosse uno user): + $organisation_id = $this->actor_type_id == 1 ? TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.actor_id' => $this->id])->first()->id ?? null : TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.actor_id' => $this->id])->first()->organisation_id ?? null; + + $contacts = TableRegistry::getTableLocator()->get('Deliveries')->find() + ->contain(['MobilePhones' => ['MobilePhoneDescriptions'], 'Faxes' => ['FaxDescriptions'], 'Emails' => ['EmailDescriptions'], 'Phones' => ['PhoneDescriptions'], 'TelegramChats', 'Pecs' => ['PecDescriptions']]) + ->where(['Deliveries.actor_id' => $this->id]) + ->order(['Deliveries.delivery_type_id' => 'ASC']) + ->all() + ->reduce(function ($acc, $contact) use ($user, $capability_prefix, $organisation_id) { + switch ($contact->delivery_type_id) { + case 1: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $mobile_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : "**************"; + } else { + // se l'actor è uno user: + $mobile_phone_value = $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'mobile_phone_foo') && $user->organisation_id == $organisation_id ? $contact->mobile_phone->value : "**************"); + } + $contact_value = __('Cellulare ({0}): {1}', $contact->mobile_phone->mobile_phone_description->description, $mobile_phone_value); + break; + case 2: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_fax_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : "**************"; + } else { + // se l'actor è uno user: + $contact_fax_value = $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'fax_foo') && $user->organisation_id == $organisation_id ? $contact->fax->value : "**************"); + } + $contact_value = __('Fax ({0}): {1}', $contact->fax->fax_description->description, $contact_fax_value); + break; + case 3: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_email_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : "**************"; + } else { + // se l'actor è uno user: + $contact_email_value = $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'email_foo') && $user->organisation_id == $organisation_id ? $contact->email->value : "**************"); + } + $contact_value = __('Email ({0}): {1}', $contact->email->email_description->description, $contact_email_value); + break; + case 4: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : "**************"; + } else { + // se l'actor è uno user: + $contact_phone_value = $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'phone_foo') && $user->organisation_id == $organisation_id ? $contact->phone->value : "**************"); + } + $contact_value = __('Telefono ({0}): {1}', $contact->phone->phone_description->description, $contact_phone_value); + break; + case 5: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_telegram_chat_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : "**************"; + } else { + // se l'actor è uno user: + $contact_telegram_chat_value = $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'telegram_chat_foo') && $user->organisation_id == $organisation_id ? $contact->telegram_chat->value : "**************"); + } + $contact_value = __('Telegram Chat ID: {0}', $contact_telegram_chat_value); + break; + case 6: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_pec_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : "**************"; + } else { + // se l'actor è uno user: + $contact_pec_value = $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'pec_foo') && $user->organisation_id == $organisation_id ? $contact->pec->value : "**************"); + } + $contact_value = __('PEC ({0}): {1}', $contact->pec->pec_description->description, $contact_pec_value); + break; + default: + $contact_value = ""; + break; + } + if ($contact_value != "") $acc[] = $contact_value; + return $acc; + }, []); + + return implode(", ", $contacts); + } + + /** + * getContactsList + * + * @return Array + */ + public function getContactsList(): Array + { + $contacts = []; + + // se la entity è stata appena creata o è di tipo diverso da "organisation" o "user": + if ($this->isNew() || !in_array($this->actor_type_id, [1,5])) return $contacts; + + // se non vi è un utente loggato: + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return $contacts; + + // costruiamo la capability prefix a seconda che l'actor è un organisation o user: + $capability_prefix = $this->actor_type_id == 1 ? "configuration.organisations.view_" : "configuration.users.view_"; + + // recuperiamo l'id della organisation (o della organisation di appartenenza, qualora l'actor fosse uno user): + $organisation_id = $this->actor_type_id == 1 ? TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.actor_id' => $this->id])->first()->id ?? null : TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.actor_id' => $this->id])->first()->organisation_id ?? null; + + $contacts = TableRegistry::getTableLocator()->get('Deliveries')->find() + ->contain(['MobilePhones' => ['MobilePhoneDescriptions'], 'Faxes' => ['FaxDescriptions'], 'Emails' => ['EmailDescriptions'], 'Phones' => ['PhoneDescriptions'], 'TelegramChats', 'Pecs' => ['PecDescriptions']]) + ->where(['Deliveries.actor_id' => $this->id]) + ->order(['Deliveries.delivery_type_id' => 'ASC']) + ->all() + ->reduce(function ($acc, $contact) use ($user, $capability_prefix, $organisation_id) { + $delivery_type_description = null; + $contact_description = null; + $contact_value = null; + + switch ($contact->delivery_type_id) { + case 1: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $mobile_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : "**************"; + } else { + // se l'actor è uno user: + $mobile_phone_value = $user->hasCapability($capability_prefix . 'mobile_phone') ? $contact->mobile_phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'mobile_phone_foo') && $user->organisation_id == $organisation_id ? $contact->mobile_phone->value : "**************"); + } + $delivery_type_description = 'mobiles'; + $contact_description = $contact->mobile_phone->mobile_phone_description->description; + $contact_value = $mobile_phone_value; + break; + case 2: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_fax_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : "**************"; + } else { + // se l'actor è uno user: + $contact_fax_value = $user->hasCapability($capability_prefix . 'fax') ? $contact->fax->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'fax_foo') && $user->organisation_id == $organisation_id ? $contact->fax->value : "**************"); + } + $delivery_type_description = 'faxes'; + $contact_description = $contact->fax->fax_description->description; + $contact_value = $contact_fax_value; + break; + case 3: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_email_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : "**************"; + } else { + // se l'actor è uno user: + $contact_email_value = $user->hasCapability($capability_prefix . 'email') ? $contact->email->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'email_foo') && $user->organisation_id == $organisation_id ? $contact->email->value : "**************"); + } + $delivery_type_description = 'emails'; + $contact_description = $contact->email->email_description->description; + $contact_value = $contact_email_value; + break; + case 4: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_phone_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : "**************"; + } else { + // se l'actor è uno user: + $contact_phone_value = $user->hasCapability($capability_prefix . 'phone') ? $contact->phone->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'phone_foo') && $user->organisation_id == $organisation_id ? $contact->phone->value : "**************"); + } + $delivery_type_description = 'phones'; + $contact_description = $contact->phone->phone_description->description; + $contact_value = $contact_phone_value; + break; + case 5: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_telegram_chat_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : "**************"; + } else { + // se l'actor è uno user: + $contact_telegram_chat_value = $user->hasCapability($capability_prefix . 'telegram_chat') ? $contact->telegram_chat->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'telegram_chat_foo') && $user->organisation_id == $organisation_id ? $contact->telegram_chat->value : "**************"); + } + $delivery_type_description = 'telegram_chats'; + $contact_description = ''; + $contact_value = $contact_telegram_chat_value; + break; + case 6: + if ($this->actor_type_id == 1) { + // se l'actor è una organisation: + $contact_pec_value = $user->organisation_id == $organisation_id || $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : "**************"; + } else { + // se l'actor è uno user: + $contact_pec_value = $user->hasCapability($capability_prefix . 'pec') ? $contact->pec->value : ($user->actor_id == $this->id || $user->hasCapability($capability_prefix . 'pec_foo') && $user->organisation_id == $organisation_id ? $contact->pec->value : "**************"); + } + $delivery_type_description = 'pecs'; + $contact_description = $contact->pec->pec_description->description; + $contact_value = $contact_pec_value; + break; + default: + break; + } + if (isset($delivery_type_description) && isset($contact_description) && isset($contact_value)) { + $acc[$delivery_type_description][] = ['description' => $contact_description, 'value' => $contact_value]; + } + return $acc; + }, []); + + return $contacts; + } + + /** + * hasContactsWithNotificationsOfType + * + * @param String $contact_type + * @return Bool + */ + public function hasContactsWithNotificationsOfType(String $contact_type): Bool + { + if (!in_array($contact_type, ['PushNotifications', 'MobilePhones', 'Faxes', 'Emails', 'TelegramChats', 'Pecs'])) return false; + if (!isset($this->_fields['id'])) return false; + + return TableRegistry::getTableLocator()->get($contact_type)->find() + ->matching('Deliveries') + ->where(['enable_notifications' => true, 'Deliveries.actor_id' => $this->_fields['id']]) + ->limit(1) + ->first() !== null; + } + + /** + * getContactsWithNotificationsOfType + * + * @param String $contact_type + * @return Array + */ + public function getContactsWithNotificationsOfType(String $contact_type): Array + { + if (!in_array($contact_type, ['PushNotifications', 'MobilePhones', 'Faxes', 'Emails', 'TelegramChats', 'Pecs'])) return []; + if (!isset($this->_fields['id'])) return []; + + return TableRegistry::getTableLocator()->get($contact_type)->find() + ->matching('Deliveries') + ->where(['enable_notifications' => true, 'Deliveries.actor_id' => $this->_fields['id']]) + ->all() + ->toArray(); + } +} diff --git a/idrocap_wa/src/Model/Entity/ActorType.php b/idrocap_wa/src/Model/Entity/ActorType.php new file mode 100644 index 0000000..59b2602 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ActorType.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'entity' => true, + 'table' => true, + 'description' => true, + 'actors' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Applicant.php b/idrocap_wa/src/Model/Entity/Applicant.php new file mode 100644 index 0000000..a80cd17 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Applicant.php @@ -0,0 +1,81 @@ + + */ + protected array $_accessible = [ + 'name' => true, + 'surname' => true, + 'company_name' => true, + 'tax_code' => true, + 'vat_number' => true, + 'address' => true, + 'district' => true, + 'province' => true, + 'pec_address' => true, + 'email_address' => true, + 'water_drawing_paperworks' => true, + ]; + + protected array $_virtual = [ + 'applicant_full_description', + ]; + + /** + * _getApplicantFullDescription + * + * Virtual Field that returns the applicant full description + * + * @return string + */ + protected function _getApplicantFullDescription(): string + { + $tax_code = $this->_fields['tax_code']; + if (empty($this->_fields['vat_number'])) { + $surname = $this->_fields['surname']; + $name = $this->_fields['name']; + return "$surname $name CF $tax_code"; + } else { + $company_name = $this->_fields['company_name']; + $address = $this->_fields['address']; + $district = $this->_fields['district']; + $province = $this->_fields['province']; + $vat_number = $this->_fields['vat_number']; + return "$company_name $address $district ($province) CF $tax_code P.IVA $vat_number"; + } + } + + protected function _setTaxCode($value) + { + return strtoupper($value); + } +} diff --git a/idrocap_wa/src/Model/Entity/ApplicantsWaterDrawingPaperwork.php b/idrocap_wa/src/Model/Entity/ApplicantsWaterDrawingPaperwork.php new file mode 100644 index 0000000..c0116c9 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ApplicantsWaterDrawingPaperwork.php @@ -0,0 +1,37 @@ + + */ + protected array $_accessible = [ + 'applicant_id' => true, + 'water_drawing_paperwork_id' => true, + 'is_primary_applicant' => true, + 'applicant' => true, + 'water_drawing_paperwork' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Attachment.php b/idrocap_wa/src/Model/Entity/Attachment.php new file mode 100644 index 0000000..d04b458 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Attachment.php @@ -0,0 +1,86 @@ + + */ + protected array $_accessible = [ + 'original_file_name' => true, + 'original_file_size' => true, + 'file_name' => true, + 'mimetype' => true, + 'upload_date' => true, + 'controllable_object_id' => true, + 'container_controllable_object_id' => true, + 'relevant' => true, + 'private' => true, + 'controllable_object' => true, + 'container_controllable_object' => true, + 'tags' => true, + ]; + + /** + * _getRelativeUrl + * + * @return ?String + */ + protected function _getRelativeUrl() + { + if(isset($this->_fields['file_name'])) + { + return Configure::read('App.attachmentsUrl')."/".$this->_fields['file_name']; + } + + return null; + } + + /** + * _getHumanOriginalFileSize + * + * @return ?String + */ + protected function _getHumanOriginalFileSize() + { + if(!isset($this->_fields['original_file_size'])) + { + return null; + } + $bytes = (String)$this->_fields['original_file_size']; + $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); + $factor = floor((strlen($bytes) - 1) / 3); + return sprintf("%.2f", $bytes / pow(1024, $factor)) . " " . @$size[$factor]; + } +} diff --git a/idrocap_wa/src/Model/Entity/BackgroundTask.php b/idrocap_wa/src/Model/Entity/BackgroundTask.php new file mode 100644 index 0000000..7b6cf21 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/BackgroundTask.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'command' => true, + 'data' => true, + 'dgroup' => true, + 'status' => true, + 'was_synced' => true, + 'created' => true, + 'modified' => true, + 'dispatching_tasks' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CadastralCropType.php b/idrocap_wa/src/Model/Entity/CadastralCropType.php new file mode 100644 index 0000000..e7ef6f4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CadastralCropType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_intended_uses' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CapabilitiesMenuItem.php b/idrocap_wa/src/Model/Entity/CapabilitiesMenuItem.php new file mode 100644 index 0000000..78f6a7b --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CapabilitiesMenuItem.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'capability_id' => true, + 'menu_item_id' => true, + 'capability' => true, + 'menu_item' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CapabilitiesMenuSection.php b/idrocap_wa/src/Model/Entity/CapabilitiesMenuSection.php new file mode 100644 index 0000000..c950e4d --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CapabilitiesMenuSection.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'capability_id' => true, + 'menu_section_id' => true, + 'capability' => true, + 'menu_section' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Capability.php b/idrocap_wa/src/Model/Entity/Capability.php new file mode 100644 index 0000000..b21d3ad --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Capability.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'value' => true, + 'priority' => true, + 'capability_group_id' => true, + 'priority_group_id' => true, + 'longdescription' => true, + 'deleted' => true, + 'is_configurable' => true, + 'capability_group' => true, + 'priority_group' => true, + 'permissions' => true, + 'menu_items' => true, + 'menu_sections' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/CapabilityGroup.php b/idrocap_wa/src/Model/Entity/CapabilityGroup.php new file mode 100644 index 0000000..a974025 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/CapabilityGroup.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'is_configurable' => true, + 'capabilities' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObject.php b/idrocap_wa/src/Model/Entity/ControllableObject.php new file mode 100644 index 0000000..45b973c --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObject.php @@ -0,0 +1,297 @@ + + */ + protected array $_accessible = [ + 'created' => true, + 'modified' => true, + 'organisation_id' => true, + 'controllable_object_type_id' => true, + 'create_user_id' => true, + 'edit_user_id' => true, + 'edit_organisation_id' => true, + 'deleted' => true, + 'organisation' => true, + 'controllable_object_type' => true, + 'user' => true, + 'attachments' => true, + 'controllable_object_interfaces' => true, + 'location' => true, + ]; + + /** + * getHashedFileName + * + * @param ?String $original_file_name + * @param ?Bool $sha512 + * @return ?String + */ + private function getHashedFileName(?String $original_file_name = null, ?Bool $sha512 = false): ?String { + if ($original_file_name == null) { + return null; + } + $rowData = $original_file_name . microtime(true); + return $sha512 ? hash('sha512', $rowData) : md5($rowData); + } + + /** + * getDuplicatedFilename + * + * @param String $filename + * @param ?Int $container_co_id + * @return String + */ + private function getDuplicatedFilename(String $filename, ?Int $container_co_id = null): String { + + $co_id = isset($container_co_id) ? $container_co_id : $this->_fields['id']; + $attachmentsTable = TableRegistry::getTableLocator()->get('Attachments'); + $file_exists = $attachmentsTable->find()->where(['Attachments.original_file_name' => $filename, 'Attachments.container_controllable_object_id' => $co_id])->first(); + if (!$file_exists) { + return $filename; + } + + $lastDotIndex = strrpos($filename, "."); + if ($lastDotIndex) { + $filename_without_extension = substr($filename, 0, $lastDotIndex); + $filename_extension = substr($filename, $lastDotIndex); + if ($filename_extension == ".") { + $filename_without_extension = $filename; + $filename_extension = ""; + } + } else { + $filename_without_extension = $filename; + $filename_extension = ""; + } + + $whereCondition = "original_file_name REGEXP '^" . $filename_without_extension . "_[[:digit:]]*" . $filename_extension . "$'"; + + $numbers = $attachmentsTable->find() + ->where([$whereCondition]) + ->where(['Attachments.container_controllable_object_id' => $co_id]) + ->all() + ->map(function($value, $key) { + $filename_exploded_array = explode("_", $value->original_file_name); + $number_with_ext_array = explode(".", $filename_exploded_array[count($filename_exploded_array) - 1]); + $number = $number_with_ext_array[0]; + return $number; + }) + ->toArray(); + + $count = count($numbers); + for ($index = 0; $index < count($numbers); $index++) { + if (!in_array(($index + 2), $numbers)) { + $count = $index; + break; + } + } + + return $filename_without_extension . "_" . ($count + 2) . $filename_extension; + } + + /** + * _getAttachmentFileNames + * + * @return Array + */ + protected function _getAttachmentFileNames() { + if($this->isNew()) + { + return []; + } + $attachmentFileNames = TableRegistry::getTableLocator()->get('Attachments')->find() + ->matching('ControllableObjects') + ->where(['Attachments.container_controllable_object_id' => $this->_fields['id']]) + ->all() + ->reduce(function ($acc ,$value) { + $acc[$value->file_name] = $value->original_file_name; + return $acc; + }, []); + return $attachmentFileNames; + } + + /** + * deleteAttachment + * + * @param Int $co_id + * @return Bool + */ + public function deleteAttachment(Int $co_id): Bool { + $controllableObjectsTable = TableRegistry::getTableLocator()->get('ControllableObjects'); + + if ($co_id == null) { + return false; + } + $attachmentCo = $controllableObjectsTable + ->find() + ->where(['ControllableObjects.id' => $co_id]) + ->first(); + if (!$attachmentCo) { + return false; + } + if (!$controllableObjectsTable->delete($attachmentCo)) { + return false; + } + return true; + } + + /** + * addAttachment + * + * @param ?String $filename + * @param ?Int $fileSize + * @param ?String $tmpPath + * @param ?String $mime + * @param ?int $private + * @param ?Bool $onePublic + * @param ?Bool $protected + * @param Array $tags + * @param Array $geo + * @throws \Exception + * @return Bool + */ + public function addAttachment(?String $filename = null, ?Int $fileSize = null, ?String $tmpPath = null, ?String $mime = null, ?int $private = 0, ?Bool $onePublic = false, ?Bool $protected = false, Array $tags = [], Array $geo = [], $skip_form_check = false): Bool + { + $co_id = $this->_fields['id']; + $attachmentsTable = TableRegistry::getTableLocator()->get('Attachments'); + + if ($filename == null) { + return false; + } + if ($fileSize == null) { + return false; + } + if ($tmpPath == null) { + return false; + } + if ($mime == null) { + return false; + } + + // 1 - check if attachment has been uploaded through input form or has been tampered with; + // 2 - check if attachment real type is allowed: + AttachmentChecker::check(['tmp_name' => $tmpPath, 'name' => $filename, 'type' => $mime, 'size' => $fileSize], $skip_form_check); + + if ($private == 0 && $onePublic) { + $existing_files = $attachmentsTable->find()->where(['Attachments.container_controllable_object_id' => $co_id, 'Attachments.private' => 0]); + foreach ($existing_files as $existing_file) { + if (!$this->deleteAttachment($existing_file->controllable_object_id)) { + return false; + } + } + } + + $file_name = $this->getHashedFileName($filename); + + $attachment_data = [ + 'container_controllable_object_id' => $co_id, + 'original_file_name' => $this->getDuplicatedFilename($filename, $co_id), + 'original_file_size' => $fileSize, + 'file_name' => $file_name, + 'url_access' => $protected ? $this->getHashedFileName($filename, true) : null, + 'mimetype' => $mime, + 'upload_date' => DateTime::now(), + 'private' => $private, + 'controllable_object' => [ + 'controllable_object_type_id' => 8, + ], + ]; + + if (!empty($geo['longitude']) && !empty($geo['latitude'])) { + $attachment_data['controllable_object']['location'] = [ + 'description' => $geo['longitude'] . ' ' . $geo['latitude'], + 'coordinates' => $geo['longitude'] . ' ' . $geo['latitude'], + 'geotype' => 'marker', + 'geom' => '{"type":"Point","coordinates":[' . $geo['longitude'] . ',' . $geo['latitude'] . ']}', + ]; + + if (!GeoValidation::isValidGeometry(json_decode($attachment_data['controllable_object']['location']['geom']))) { + throw new \Exception(__('Le coordinate inserite per georeferenziare uno o più allegati non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + } + + $associated = [ + 'ControllableObjects' => [ + 'associated' => ['Locations'] + ], + ]; + + $attachment = $attachmentsTable->newEntity($attachment_data, ['associated' => $associated]); + + try + { + $res = \App\WGS\FileStorage\FileStorageFactory::create()->saveFile(Configure::read('App.attachmentsPath')."/".$co_id."/".$file_name,$tmpPath); + if (is_array($tags) && !empty($tags)) { + $tagsTable = TableRegistry::getTableLocator()->get('Tags'); + $tags = $tagsTable->find()->where(['Tags.code IN' => $tags])->toArray(); + $attachment->tags = $tags; + } + + if (!$attachmentsTable->save($attachment)) { + return false; + } + + return true; + } + catch(\Exception $we) + { + return false; + } + + return true; + } + + /** + * getSpecialisationEntity + * + * @return Cake\ORM\Entity|null + */ + public function getSpecialisationEntity() + { + $co_type = TableRegistry::getTableLocator()->get('ControllableObjectTypes')->find()->where(['ControllableObjectTypes.id' => $this->_fields['controllable_object_type_id']])->first(); + if (!$co_type) return null; + $table = \Cake\Utility\Inflector::camelize($co_type->controller); + $specialisation_entity = TableRegistry::getTableLocator()->get($table)->find()->where(["$table.controllable_object_id" => $this->_fields['id']])->first(); + if (!$specialisation_entity) return null; + return $specialisation_entity; + } +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObjectInterface.php b/idrocap_wa/src/Model/Entity/ControllableObjectInterface.php new file mode 100644 index 0000000..1cb0462 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObjectInterface.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'controllable_object_id' => true, + 'controllable_object_interface_type_id' => true, + 'controllable_object' => true, + 'controllable_object_interface_type' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObjectInterfaceType.php b/idrocap_wa/src/Model/Entity/ControllableObjectInterfaceType.php new file mode 100644 index 0000000..32bde37 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObjectInterfaceType.php @@ -0,0 +1,34 @@ + + */ + protected array $_accessible = [ + 'entity' => true, + 'table' => true, + 'description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/ControllableObjectType.php b/idrocap_wa/src/Model/Entity/ControllableObjectType.php new file mode 100644 index 0000000..1ae34a4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/ControllableObjectType.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'controller' => true, + 'label' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/County.php b/idrocap_wa/src/Model/Entity/County.php new file mode 100644 index 0000000..a3f0df1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/County.php @@ -0,0 +1,52 @@ + + */ + protected array $_accessible = [ + 'SHAPE' => true, + 'cod_rip' => true, + 'cod_reg' => true, + 'cod_prov' => true, + 'cod_cm' => true, + 'cod_uts' => true, + 'den_prov' => true, + 'den_cm' => true, + 'den_uts' => true, + 'sigla' => true, + 'tipo_uts' => true, + 'shape_leng' => true, + 'shape_area' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Delivery.php b/idrocap_wa/src/Model/Entity/Delivery.php new file mode 100644 index 0000000..4f4a688 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Delivery.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'actor_id' => true, + 'delivery_type_id' => true, + 'deleted' => true, + 'actor' => true, + 'delivery_type' => true, + 'emails' => true, + 'faxes' => true, + 'mobile_phones' => true, + 'phones' => true, + 'push_notifications' => true, + 'telegram_chats' => true, + 'telegram_contacts' => true, + 'pecs' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DeliveryType.php b/idrocap_wa/src/Model/Entity/DeliveryType.php new file mode 100644 index 0000000..44e6434 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DeliveryType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deliveries' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DispatchingTask.php b/idrocap_wa/src/Model/Entity/DispatchingTask.php new file mode 100644 index 0000000..0fd2fb1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DispatchingTask.php @@ -0,0 +1,47 @@ + + */ + protected array $_accessible = [ + 'dispatching_task_group' => true, + 'dispatching_task_status_id' => true, + 'created' => true, + 'modified' => true, + 'retries' => true, + 'failed' => true, + 'background_task_id' => true, + 'dispatching_task_status' => true, + 'background_task' => true, + 'dispatching_task_items' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DispatchingTaskItem.php b/idrocap_wa/src/Model/Entity/DispatchingTaskItem.php new file mode 100644 index 0000000..000b606 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DispatchingTaskItem.php @@ -0,0 +1,47 @@ + + */ + protected array $_accessible = [ + 'dispatching_task_id' => true, + 'actor_id' => true, + 'system_dispatched' => true, + 'actor_dispatching_bitmask' => true, + 'performed_dispatching_bitmask' => true, + 'not_performed_dispatching_bitmask' => true, + 'created' => true, + 'modified' => true, + 'dispatching_task' => true, + 'actor' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/DispatchingTaskStatus.php b/idrocap_wa/src/Model/Entity/DispatchingTaskStatus.php new file mode 100644 index 0000000..9625c26 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/DispatchingTaskStatus.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'dispatching_tasks' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/District.php b/idrocap_wa/src/Model/Entity/District.php new file mode 100644 index 0000000..bdcb1a2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/District.php @@ -0,0 +1,52 @@ + + */ + protected array $_accessible = [ + 'SHAPE' => true, + 'cod_rip' => true, + 'cod_reg' => true, + 'cod_prov' => true, + 'cod_cm' => true, + 'cod_uts' => true, + 'pro_com' => true, + 'pro_com_t' => true, + 'comune' => true, + 'comune_a' => true, + 'cc_uts' => true, + 'shape_leng' => true, + 'shape_area' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Email.php b/idrocap_wa/src/Model/Entity/Email.php new file mode 100644 index 0000000..17a52c8 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Email.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'is_system' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'email_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'email_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/EmailDescription.php b/idrocap_wa/src/Model/Entity/EmailDescription.php new file mode 100644 index 0000000..c1acab8 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/EmailDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'emails' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Fax.php b/idrocap_wa/src/Model/Entity/Fax.php new file mode 100644 index 0000000..0c2aa54 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Fax.php @@ -0,0 +1,41 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'fax_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'fax_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/FaxDescription.php b/idrocap_wa/src/Model/Entity/FaxDescription.php new file mode 100644 index 0000000..47b2a50 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/FaxDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'faxes' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Filter.php b/idrocap_wa/src/Model/Entity/Filter.php new file mode 100644 index 0000000..d40ed66 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Filter.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'category' => true, + 'description' => true, + 'filter_type' => true, + 'class_name' => true, + 'search' => true, + 'associations' => true, + 'order_number' => true, + 'sys_admin_only' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Group.php b/idrocap_wa/src/Model/Entity/Group.php new file mode 100644 index 0000000..22e5dc4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Group.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'is_default' => true, + 'super_group' => true, + 'actor_id' => true, + 'is_editable' => true, + 'group_code' => true, + 'modified' => true, + 'actor' => true, + 'memberships' => true, + 'permissions' => true, + 'tags' => true, + 'capabilities' => true, + 'child_groups' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/GroupsGroup.php b/idrocap_wa/src/Model/Entity/GroupsGroup.php new file mode 100644 index 0000000..0ad9183 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/GroupsGroup.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'container_group_id' => true, + 'group_id' => true, + 'group' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Language.php b/idrocap_wa/src/Model/Entity/Language.php new file mode 100644 index 0000000..c73d283 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Language.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'language_code' => true, + 'users' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Location.php b/idrocap_wa/src/Model/Entity/Location.php new file mode 100644 index 0000000..c45ae59 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Location.php @@ -0,0 +1,56 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'coordinates' => true, + 'feature_collection' => true, + 'geom' => true, + 'controllable_object_id' => true, + 'controllable_object' => true, + 'location_attributes' => true, + ]; + + /** + * _getGeom + * + * @param mixed $value + * @return mixed + */ + protected function _getGeom($value) + { + if (!is_string($value) || empty(json_decode($value))) { + return $value; + } + return new QueryExpression("ST_GeomFromGeoJson('$value')"); + } +} diff --git a/idrocap_wa/src/Model/Entity/LocationAttribute.php b/idrocap_wa/src/Model/Entity/LocationAttribute.php new file mode 100644 index 0000000..677ade1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/LocationAttribute.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'location_id' => true, + 'district_code' => true, + 'district_name' => true, + 'county_code' => true, + 'county_name' => true, + 'region' => true, + 'area' => true, + 'location' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Map.php b/idrocap_wa/src/Model/Entity/Map.php new file mode 100644 index 0000000..6c2d3a3 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Map.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'code' => true, + 'name' => true, + 'url_layer' => true, + 'clusterize' => true, + 'visible' => true, + 'style' => true, + 'created' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MenuItem.php b/idrocap_wa/src/Model/Entity/MenuItem.php new file mode 100644 index 0000000..8c6e620 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MenuItem.php @@ -0,0 +1,82 @@ + + */ + protected array $_accessible = [ + 'title' => true, + 'icon' => true, + 'link' => true, + 'menu_item_id' => true, + 'menu_section_id' => true, + 'menu_order' => true, + 'menu_items' => true, + 'menu_section' => true, + 'capabilities' => true, + ]; + + protected array $_virtual = [ + 'menu_items', + ]; + + /** + * _getMenuItems + * + * @return Array + */ + protected function _getMenuItems(): Array + { + $menu_items = []; + + // bisogna recuperare le capabilities utente (se esiste un utente loggato) + $user = Router::getRequest()->getAttribute('identity'); + if ($user) { + $MenuItems = TableRegistry::getTableLocator()->get('MenuItems'); + $menu_items_subquery = $MenuItems + ->find() + ->select(['MenuItems.id']) + ->innerJoinWith('Capabilities') + ->where(['MenuItems.menu_item_id is NOT NULL', 'MenuItems.menu_item_id' => $this->id]) + ->where(['Capabilities.id IN' => $user->getCapabilityIds(true)]) + ->distinct(['MenuItems.id']); + + $menu_items = $MenuItems + ->find() + ->where(['MenuItems.id IN' => $menu_items_subquery]) + ->order(['MenuItems.menu_order' => 'ASC']) + ->toArray(); + } + return $menu_items; + + } +} diff --git a/idrocap_wa/src/Model/Entity/MenuSection.php b/idrocap_wa/src/Model/Entity/MenuSection.php new file mode 100644 index 0000000..e34130e --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MenuSection.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'title' => true, + 'icon' => true, + 'menu_items' => true, + 'capabilities' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Message.php b/idrocap_wa/src/Model/Entity/Message.php new file mode 100644 index 0000000..e788874 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Message.php @@ -0,0 +1,61 @@ + + */ + protected array $_accessible = [ + 'controllable_object_id' => true, + 'message_type_id' => true, + 'content' => true, + 'user_id' => true, + 'message_status_id' => true, + 'mgroup' => true, + 'event_string' => true, + 'last_update' => true, + 'organisation_id' => true, + 'contact' => true, + 'not_delivered_reason' => true, + 'controllable_object' => true, + 'message_type' => true, + 'user' => true, + 'message_status' => true, + 'organisation' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MessageStatus.php b/idrocap_wa/src/Model/Entity/MessageStatus.php new file mode 100644 index 0000000..25525a2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MessageStatus.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'messages' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MessageType.php b/idrocap_wa/src/Model/Entity/MessageType.php new file mode 100644 index 0000000..2e3d49f --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MessageType.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'label' => true, + 'dispatching_bitmask_weight' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MobileComponent.php b/idrocap_wa/src/Model/Entity/MobileComponent.php new file mode 100644 index 0000000..9cc4db4 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MobileComponent.php @@ -0,0 +1,35 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'menu_item' => true, + 'is_enabled' => true, + 'capabilities' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MobilePhone.php b/idrocap_wa/src/Model/Entity/MobilePhone.php new file mode 100644 index 0000000..7a37091 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MobilePhone.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'is_system' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'mobile_phone_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'mobile_phone_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/MobilePhoneDescription.php b/idrocap_wa/src/Model/Entity/MobilePhoneDescription.php new file mode 100644 index 0000000..5621fbc --- /dev/null +++ b/idrocap_wa/src/Model/Entity/MobilePhoneDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'mobile_phones' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Notification.php b/idrocap_wa/src/Model/Entity/Notification.php new file mode 100644 index 0000000..0ab8381 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Notification.php @@ -0,0 +1,51 @@ + + */ + protected array $_accessible = [ + 'user_id' => true, + 'read_by_user' => true, + 'notification_type_id' => true, + 'info' => true, + 'created' => true, + 'thread' => true, + 'ngroup' => true, + 'controllable_object_id' => true, + 'user' => true, + 'notification_type' => true, + 'controllable_object' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/NotificationType.php b/idrocap_wa/src/Model/Entity/NotificationType.php new file mode 100644 index 0000000..9a02d79 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/NotificationType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'notifications' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Organisation.php b/idrocap_wa/src/Model/Entity/Organisation.php new file mode 100644 index 0000000..65eeffa --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Organisation.php @@ -0,0 +1,259 @@ + + */ + protected array $_accessible = [ + 'acronym' => true, + 'geoposition' => true, + 'address' => true, + 'district' => true, + 'cap' => true, + 'province' => true, + 'organisation_type_id' => true, + 'actor_id' => true, + 'pec' => true, + 'coordinates' => true, + 'feature_collection' => true, + 'deleted' => true, + 'photo' => true, + 'controllable_object_interface_id' => true, + 'organisation_type' => true, + 'actor' => true, + 'controllable_object_interface' => true, + 'messages' => true, + 'users' => true, + 'attachments' => true, + 'removefiles' => true, + ]; + + protected array $_hidden = [ + 'geoposition', + ]; + + protected array $_virtual = [ + 'mobile_phones', + 'phones', + 'emails', + 'pecs', + ]; + + /** + * can_view + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_view(User $user, Array &$options): Bool + { + if ($user->hasCapability(['configuration.organisations.read'])) + { + return true; + } else { + $options['error']['capabilities'] = ['configuration.organisations.read']; + return false; + } + } + + /** + * _getGeoposition + * + * @param mixed $value + * @return mixed + */ + protected function _getGeoposition($value) + { + if (!is_string($value) || empty(json_decode($value))) { + return $value; + } + return new QueryExpression("ST_GeomFromGeoJson('$value')"); + } + + protected function _getMobilePhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('MobilePhones')->find()->contain(['Deliveries', 'MobilePhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->mobile_phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getPhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('Phones')->find()->contain(['Deliveries', 'PhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getEmails() + { + if ($this->isNew()) return []; + $emails = TableRegistry::getTableLocator()->get('Emails')->find()->contain(['Deliveries', 'EmailDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->email_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $emails; + } + + protected function _getPecs() + { + if ($this->isNew()) return []; + $pecs = TableRegistry::getTableLocator()->get('Pecs')->find()->contain(['Deliveries', 'PecDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->pec_description->description, + 'value' => $row->value + ]; + }); + }); + return $pecs; + } + + /** + * getActor + * + * @return ?Actor + */ + public function getActor(): ?Actor + { + if (!isset($this->_fields['actor_id'])) return null; + return TableRegistry::getTableLocator()->get('Actors')->get($this->_fields['actor_id']); + } + + /** + * hasMobilePhonesWithNotifications + * + * @return Bool + */ + public function hasMobilePhonesWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * hasEmailsWithNotifications + * + * @return Bool + */ + public function hasEmailsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Emails'); + } + + /** + * hasPecsWithNotifications + * + * @return Bool + */ + public function hasPecsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Pecs'); + } + + /** + * getMobilePhonesWithNotifications + * + * @return Array + */ + public function getMobilePhonesWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * getEmailsWithNotifications + * + * @return Array + */ + public function getEmailsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Emails'); + } + + /** + * getPecsWithNotifications + * + * @return Array + */ + public function getPecsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Pecs'); + } + + /** + * getDispatchingBitmask + * + * @return ?Int + */ + public function getDispatchingBitmask(): ?Int + { + if (!isset($this->_fields['id'])) return null; + + $bitmask = 0; + + if ($this->hasMobilePhonesWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(1)->dispatching_bitmask_weight; + if ($this->hasEmailsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(3)->dispatching_bitmask_weight; + if ($this->hasPecsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(5)->dispatching_bitmask_weight; + + return $bitmask; + } +} diff --git a/idrocap_wa/src/Model/Entity/OrganisationType.php b/idrocap_wa/src/Model/Entity/OrganisationType.php new file mode 100644 index 0000000..8f41457 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/OrganisationType.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'organisations' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Pec.php b/idrocap_wa/src/Model/Entity/Pec.php new file mode 100644 index 0000000..30f9225 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Pec.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'is_system' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'pec_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'pec_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PecDescription.php b/idrocap_wa/src/Model/Entity/PecDescription.php new file mode 100644 index 0000000..fa0d5a7 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PecDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'pecs' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Permission.php b/idrocap_wa/src/Model/Entity/Permission.php new file mode 100644 index 0000000..2c9c685 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Permission.php @@ -0,0 +1,34 @@ + + */ + protected array $_accessible = [ + 'deleted' => true, + 'capability' => true, + 'group' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Phone.php b/idrocap_wa/src/Model/Entity/Phone.php new file mode 100644 index 0000000..b79ec75 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Phone.php @@ -0,0 +1,39 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'delivery_id' => true, + 'phone_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'phone_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PhoneDescription.php b/idrocap_wa/src/Model/Entity/PhoneDescription.php new file mode 100644 index 0000000..5fa42a3 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PhoneDescription.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'deleted' => true, + 'phones' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Privacy.php b/idrocap_wa/src/Model/Entity/Privacy.php new file mode 100644 index 0000000..c77b2b5 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Privacy.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'created' => true + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PrivacyUser.php b/idrocap_wa/src/Model/Entity/PrivacyUser.php new file mode 100644 index 0000000..b521b22 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PrivacyUser.php @@ -0,0 +1,37 @@ + + */ + protected array $_accessible = [ + 'privacy_id' => true, + 'user_id' => true, + 'created' => true, + 'privacy' => true, + 'user' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/PushNotification.php b/idrocap_wa/src/Model/Entity/PushNotification.php new file mode 100644 index 0000000..fe65c4e --- /dev/null +++ b/idrocap_wa/src/Model/Entity/PushNotification.php @@ -0,0 +1,37 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'deleted' => true, + 'delivery' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Snapshot.php b/idrocap_wa/src/Model/Entity/Snapshot.php new file mode 100644 index 0000000..0d4e102 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Snapshot.php @@ -0,0 +1,47 @@ + + */ + protected array $_accessible = [ + 'controllable_object_type_id' => true, + 'controllable_object_id' => true, + 'object_snapshot' => true, + 'date' => true, + 'user_id' => true, + 'controller_action' => true, + 'unpacked_with_version' => true, + 'user' => true, + 'controllable_object' => true, + 'controllable_object_type' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/Tag.php b/idrocap_wa/src/Model/Entity/Tag.php new file mode 100644 index 0000000..0f6f595 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/Tag.php @@ -0,0 +1,56 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'code' => true, + 'class' => true, + 'attachments' => true, + 'groups' => true, + 'id' => true, + 'controllable_object_id' => true, + 'attachments' => true, + 'removefiles' => true, + 'controllable_object' => true, + ]; + + protected array $_virtual = [ + 'link', + ]; + + protected function _getLink(): string{ + if (empty($this->controllable_object_id)) return ''; + $attachment = TableRegistry::getTableLocator()->get('Attachments')->find()->where(['Attachments.container_controllable_object_id' => $this->controllable_object_id])->first(); + if(!isset($attachment->file_name)) return ''; + $link = $attachment->file_name; + return $link; + } +} diff --git a/idrocap_wa/src/Model/Entity/TelegramChat.php b/idrocap_wa/src/Model/Entity/TelegramChat.php new file mode 100644 index 0000000..4aef789 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/TelegramChat.php @@ -0,0 +1,41 @@ + + */ + protected array $_accessible = [ + 'value' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'telegram_chat_description_id' => true, + 'deleted' => true, + 'delivery' => true, + 'telegram_chat_description' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/TelegramContact.php b/idrocap_wa/src/Model/Entity/TelegramContact.php new file mode 100644 index 0000000..87329e2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/TelegramContact.php @@ -0,0 +1,51 @@ + + */ + protected array $_accessible = [ + 'phone_number' => true, + 'telegram_user_id' => true, + 'enable_notifications' => true, + 'delivery_id' => true, + 'created' => true, + 'modified' => true, + 'deleted' => true, + 'telegram_contact_status_id' => true, + 'error_message' => true, + 'delivery' => true, + 'telegram_contact_status' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/UnpackedWaterDrawingPaperworkSnapshot.php b/idrocap_wa/src/Model/Entity/UnpackedWaterDrawingPaperworkSnapshot.php new file mode 100644 index 0000000..5e3c96a --- /dev/null +++ b/idrocap_wa/src/Model/Entity/UnpackedWaterDrawingPaperworkSnapshot.php @@ -0,0 +1,55 @@ + + */ + protected array $_accessible = [ + 'snapshot_id' => true, + 'unpacking_version' => true, + 'who' => true, + 'when' => true, + 'what' => true, + 'creator' => true, + 'created' => true, + 'modifier' => true, + 'modified' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_paperwork_status' => true, + 'gc_user' => true, + 'drar_user' => true, + 'snapshot' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/User.php b/idrocap_wa/src/Model/Entity/User.php new file mode 100644 index 0000000..ebfccf1 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/User.php @@ -0,0 +1,643 @@ + + */ + protected array $_accessible = [ + 'organisation_id' => true, + 'username' => true, + 'password' => true, + 'surname' => true, + 'name' => true, + 'address' => true, + 'city' => true, + 'cap' => true, + 'tax_code' => true, + 'photo' => true, + 'user_photo' => true, // don't remove!!!!!!!!! + 'birthplace' => true, + 'birthday' => true, + 'gender' => true, + 'language_id' => true, + 'password_recovery_token' => true, + 'password_recovery_counter' => true, + 'actor_id' => true, + 'deleted' => true, + 'organisation' => true, + 'language' => true, + 'actor' => true, + 'memberships' => true, + 'messages' => true, + 'notifications' => true, + 'groups' => true, + "email_verification_code" => true, + "is_verified" => true, + "is_citizen" => true + ]; + + + + + /** + * Fields that are excluded from JSON versions of the entity. + * + * @var array + */ + protected array $_hidden = [ + 'password', + 'position', + ]; + + protected array $_virtual = [ + 'profiles', + 'mobile_phones', + 'emails', + 'phones', + 'pecs', + 'organisation_province' + ]; + + /** + * Authentication\IdentityInterface method + */ + public function getIdentifier(): array|string|int|null + { + return $this->id; + } + + /** + * Authentication\IdentityInterface method + */ + public function getOriginalData(): ArrayAccess|array + { + return $this; + } + + /** + * _setPassword + * + * @param String $password + * @return String + */ + protected function _setPassword(String $password) + { + $hasher = new DefaultPasswordHasher(); + return $hasher->hash($password); + } + + /** + * getCapabilityIds + * + * @param Bool $return_query_object + * @return Array|Query + */ + public function getCapabilityIds(Bool $return_query_object = false): Array|Query + { + $CapabilitiesTable = TableRegistry::getTableLocator()->get('Capabilities'); + + $capabilities = $CapabilitiesTable->find() + ->select(['id']); + + if (!isset($this->sys_admin) || !$this->sys_admin) { + $capabilities = $capabilities + ->matching('Groups.Users') + ->where(['Permissions.deleted IS NULL']) + ->where(['Users.id' => $this->id]) + ->distinct(); + } + + if (!$return_query_object) { + $capabilities = $capabilities + ->all() + ->extract('id') + ->toArray(); + } + + return $capabilities; + } + + /** + * hasCapability + * + * @param String|Array $capability + * @return Bool + */ + public function hasCapability(String|Array $capability): Bool + { + if (isset($this->sys_admin) && $this->sys_admin) return true; + + if (is_string($capability)) $capability = [$capability]; + return TableRegistry::getTableLocator()->get('Capabilities') + ->find() + ->where(['Capabilities.value IN' => $capability, 'Capabilities.id IN' => $this->getCapabilityIds(true)]) + ->first() !== null; + } + + + /** + * Verifica se l'utente ha solo la capability con priorità più bassa tra quelle fornite + * + * @param String|Array $capabilities + * @return Bool + */ + public function hasOnlyLowerPriorityCapability(String|Array $capabilities): Bool + { + if (isset($this->sys_admin) && $this->sys_admin) return false; + + $userCapabilities = TableRegistry::getTableLocator()->get('Capabilities') + ->find() + ->select(['value', 'priority']) + ->where(['Capabilities.value IN' => $capabilities, 'Capabilities.id IN' => $this->getCapabilityIds(true)]) + ->all() + ->toArray(); + + // Se l'utente non ha nessuna delle capability richieste, restituisco false + if (empty($userCapabilities)) return false; + + // A questo punto verifico se l'utente ha solo la capability con priorità più bassa + $hasPriority1 = false; + $hasPriority2 = false; + + foreach ($userCapabilities as $capability) { + if ($capability->priority == 1) { + $hasPriority1 = true; + } else if ($capability->priority == 2) { + $hasPriority2 = true; + } + } + return !$hasPriority1 && $hasPriority2; + } + + /** + * canActOnContactsForActor + * + * @param String $action + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + private function canActOnContactsForActor(String $action, Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + $contact_types = is_string($contact_types) ? [$contact_types] : $contact_types; + // se actor è di tipo "organizzazione": + if ($actor->actor_type_id == 1) { + // verifichiamo che l'utente abbia titolo a visualizzare i recapiti dell'organizzazione selezionata. + // o è la sua stessa organizzazione oppure necessita di almeno 1 delle seguenti capabilities: + $required_capabilities = collection($contact_types) + ->map(function ($contact_type) use ($action) { + return 'configuration.organisations.' . $action . '_' . $contact_type; + }) + ->toArray(); + if ($actor->organisation->id != $this->organisation_id && !$this->hasCapability($required_capabilities)) return false; + return true; + } + + // se actor è di tipo "utente": + if ($actor->actor_type_id == 5) { + // verifichiamo che l'utente abbia titolo a visualizzare i recapiti dell'utente selezionato. + // o l'utente selezionato è lo stesso utente, + // o l'utente selezionato appartiene alla stessa organizzazione dell'utente e possiede almeno una + // tra l'array_merge dei 2 seguenti array $required_capabilities e $required_foo_capabilities, + // oppure deve possedere almeno 1 delle capabilities di $required_capabilities soltanto: + $required_capabilities = collection($contact_types) + ->map(function ($contact_type) use ($action) { + return 'configuration.users.' . $action . '_' . $contact_type; + }) + ->toArray(); + $required_foo_capabilities = collection($contact_types) + ->map(function ($contact_type) use ($action) { + return 'configuration.users.' . $action . '_' . $contact_type . '_foo'; + }) + ->toArray(); + // se i recapiti sono relativi ad un'utente della stessa organizzazione dell'utente loggato + // aggiungiamo anche le relative capabilities di basso livello (_foo): + if ($this->organisation_id == $actor->user->organisation_id) $required_capabilities = array_merge($required_capabilities, $required_foo_capabilities); + + if ($actor->user->id != $this->id && !$this->hasCapability($required_capabilities)) return false; + return true; + } + // nessun accesso per actor non di tipo "organizzazione" o "utente": + return false; + } + + /** + * canViewContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canViewContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('view', $actor, $contact_types); + } + + /** + * canAddContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canAddContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('add', $actor, $contact_types); + } + + /** + * canEditContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canEditContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('edit', $actor, $contact_types); + } + + /** + * canDeleteContactsForActor + * + * @param Actor $actor + * @param String|Array $contact_types + * @return Bool + */ + public function canDeleteContactsForActor(Actor $actor, String|Array $contact_types = ['mobile_phone', 'fax', 'email', 'phone', 'telegram_chat', 'pec']): Bool + { + return $this->canActOnContactsForActor('delete', $actor, $contact_types); + } + + /** + * _getProfiles + * + * @return String + */ + protected function _getProfiles(): String + { + // se la entity è stata appena creata: + if ($this->isNew()) return ""; + + // se non vi è un utente loggato: + $user = Router::getRequest()->getAttribute('identity'); + if (!$user || !$user->hasCapability('configuration.groups.read')) return "**************"; + + $profiles = TableRegistry::getTableLocator()->get('Groups')->find() + ->matching('Users') + ->where(['Users.id' => $this->id]) + ->order(['Groups.description' => 'ASC']) + ->all() + ->extract('description') + ->toArray(); + + return implode(", ", $profiles); + } + + protected function _getMobilePhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('MobilePhones')->find()->contain(['Deliveries', 'MobilePhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->mobile_phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getPhones() + { + if ($this->isNew()) return []; + $mobilePhones = TableRegistry::getTableLocator()->get('Phones')->find()->contain(['Deliveries', 'PhoneDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->phone_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $mobilePhones; + } + + protected function _getEmails() + { + if ($this->isNew()) return []; + $emails = TableRegistry::getTableLocator()->get('Emails')->find()->contain(['Deliveries', 'EmailDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->email_description->description, + 'value' => $row->value + ]; + }); + })->toArray(); + return $emails; + } + + protected function _getPecs() + { + if ($this->isNew()) return []; + $pecs = TableRegistry::getTableLocator()->get('Pecs')->find()->contain(['Deliveries', 'PecDescriptions'])->where(['Deliveries.actor_id' => $this->actor_id])->formatResults(function ($q){ + return $q->map(function ($row){ + return [ + 'type' => $row->pec_description->description, + 'value' => $row->value + ]; + }); + }); + return $pecs; + } + + /** + * __toString + * + * @return String + */ + public function __toString(): String { + if ($this->isNew()) return ""; + $surname = $this->_fields['surname'] ?? ''; + $name = $this->_fields['name'] ?? ''; + $description = "$name $surname"; + + if (isset($this->_fields['organisation_id'])) { + $user_org = TableRegistry::getTableLocator()->get('Organisations')->get($this->_fields['organisation_id'], contain: ['Actors']); + $org_description = $user_org->actor->description ?? null; + if ($org_description) $description .= " ($org_description)"; + } + + return $description; + } + + /** + * canHandleAttachmentsForControllableObject + * + * @param ControllableObject $co + * @return Bool + */ + public function canHandleAttachmentsForControllableObject(ControllableObject $co): Bool + { + return $co->organisation_id == $this->_fields['organisation_id'] || $co->create_user_id = $this->_fields['id']; + } + + /** + * can_view + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_view(User $user, Array &$options): Bool + { + if($user->hasCapability(['configuration.users.read']) || ($user->hasCapability(['configuration.users.read_foo']) && $user->organisation_id == $this->_fields['organisation_id'])) + { + return true; + } else { + if ($user->organisation_id == $this->_fields['organisation_id']) { + $options['error']['capabilities'][] = 'configuration.users.read_foo'; + } + if (empty($options['error']['capabilities'])) { + $options['capabilities'][] = ['configuration.users.read']; + } + return false; + } + } + + /** + * getActor + * + * @return ?Actor + */ + public function getActor(): ?Actor + { + if (!isset($this->_fields['actor_id'])) return null; + return TableRegistry::getTableLocator()->get('Actors')->get($this->_fields['actor_id']); + } + + /** + * hasPushNotificationsWithNotifications + * + * @return Bool + */ + public function hasPushNotificationsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('PushNotifications'); + } + + /** + * hasMobilePhonesWithNotifications + * + * @return Bool + */ + public function hasMobilePhonesWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * hasFaxesWithNotifications + * + * @return Bool + */ + public function hasFaxesWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Faxes'); + } + + /** + * hasEmailsWithNotifications + * + * @return Bool + */ + public function hasEmailsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Emails'); + } + + /** + * hasPecsWithNotifications + * + * @return Bool + */ + public function hasPecsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('Pecs'); + } + + /** + * hasTelegramChatsWithNotifications + * + * @return Bool + */ + public function hasTelegramChatsWithNotifications(): Bool + { + return $this->getActor()->hasContactsWithNotificationsOfType('TelegramChats'); + } + + /** + * getPushNotificationsWithNotifications + * + * @return Array + */ + public function getPushNotificationsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('PushNotifications'); + } + + /** + * getMobilePhonesWithNotifications + * + * @return Array + */ + public function getMobilePhonesWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('MobilePhones'); + } + + /** + * getFaxesWithNotifications + * + * @return Array + */ + public function getFaxesWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Faxes'); + } + + /** + * getEmailsWithNotifications + * + * @return Array + */ + public function getEmailsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Emails'); + } + + /** + * getPecsWithNotifications + * + * @return Array + */ + public function getPecsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('Pecs'); + } + + /** + * getTelegramChatsWithNotifications + * + * @return Array + */ + public function getTelegramChatsWithNotifications(): Array + { + return $this->getActor()->getContactsWithNotificationsOfType('TelegramChats'); + } + + /** + * getDispatchingBitmask + * + * @param ?String $notification_code + * @return ?Int + */ + public function getDispatchingBitmask(?String $notification_code = null): ?Int + { + if (!isset($this->_fields['id'])) return null; + + $bitmask = 0; + + $pushNotificationsCapability = !$notification_code || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.push_notification']); + $mobilePhonesCapability = !$notification_code || $notification_code == "password_recovery" || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.sms']); + $faxesCapability = !$notification_code || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.fax']); + $emailsCapability = !$notification_code || $notification_code == "password_recovery" || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.email']); + $telegramChatsCapability = !$notification_code || $notification_code == "password_recovery" || $notification_code == "test_all" || $this->hasCapability(['notifications.'.$notification_code.'.telegram_chat']); + $pecsCapability = $this->hasCapability(['notifications.'.$notification_code.'.pec']); + + if ($pushNotificationsCapability && $this->hasPushNotificationsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(0)->dispatching_bitmask_weight; + if ($mobilePhonesCapability && $this->hasMobilePhonesWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(1)->dispatching_bitmask_weight; + if ($faxesCapability && $this->hasFaxesWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(2)->dispatching_bitmask_weight; + if ($emailsCapability && $this->hasEmailsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(3)->dispatching_bitmask_weight; + if ($telegramChatsCapability && $this->hasTelegramChatsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(4)->dispatching_bitmask_weight; + if ($pecsCapability && $this->hasPecsWithNotifications()) $bitmask += TableRegistry::getTableLocator()->get('MessageTypes')->get(5)->dispatching_bitmask_weight; + + return $bitmask; + } + + protected function _setTaxCode($value) + { + return strtoupper($value); + } + + protected function _getOrganisationProvince(): ?String + { + if (!isset($this->_fields['organisation_id'])) return null; + + if (isset($this->organisation?->province)) { + return $this->organisation->province; + } + + $organisation = TableRegistry::getTableLocator()->get('Organisations') + ->find() + ->select(['province']) + ->where(['id' => $this->_fields['organisation_id']]) + ->first(); + + return $organisation?->province; + } +} diff --git a/idrocap_wa/src/Model/Entity/UserTimezoneDatetimeEntityTrait.php b/idrocap_wa/src/Model/Entity/UserTimezoneDatetimeEntityTrait.php new file mode 100644 index 0000000..16c7367 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/UserTimezoneDatetimeEntityTrait.php @@ -0,0 +1,32 @@ +getSource(); + // solo se la entity non è una newEntity (quindi ancora senza repository/source): + if (!empty($source)) { + $user = Router::getRequest()?->getAttribute('identity'); + if (isset($user->disableUserTimezoneDatetimeEntityTrait) && is_bool($user->disableUserTimezoneDatetimeEntityTrait) && $user->disableUserTimezoneDatetimeEntityTrait) return; + $timezone = !empty($user->timezone) ? $user->timezone : Configure::read('App.defaultUserTimezone'); + + $entity_source_schema = TableRegistry::getTableLocator()->get($source)->getSchema(); + foreach ($entity_source_schema->columns() as $entity_property_name) { + $entity_property_type = $entity_source_schema->getColumnType($entity_property_name); + if ($entity_property_type == 'datetime' && isset($this->_fields[$entity_property_name])) { + $this->_fields[$entity_property_name] = $this->_fields[$entity_property_name]?->setTimezone($timezone); + } + } + } + } +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequest.php b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequest.php new file mode 100644 index 0000000..4f4cb10 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequest.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'water_drawing_paperwork_id' => true, + 'user_id' => true, + 'water_drawing_antimafia_certification_request_status_id' => true, + 'created' => true, + 'water_drawing_paperwork' => true, + 'user' => true, + 'water_drawing_antimafia_certification_request_status' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequestStatus.php b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequestStatus.php new file mode 100644 index 0000000..3cb87d3 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingAntimafiaCertificationRequestStatus.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_antimafia_certification_requests' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingArticle.php b/idrocap_wa/src/Model/Entity/WaterDrawingArticle.php new file mode 100644 index 0000000..12bca94 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingArticle.php @@ -0,0 +1,32 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'long_description' => true, + 'disable' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingDerivation.php b/idrocap_wa/src/Model/Entity/WaterDrawingDerivation.php new file mode 100644 index 0000000..baf56d2 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingDerivation.php @@ -0,0 +1,67 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_body' => true, + 'feature_collection' => true, + 'district' => true, + 'cadastral_code' => true, + 'location' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'latitude' => true, + 'longitude' => true, + 'istat' => true, + 'derivation_status' => true, + 'withdrawals_amount' => true, + 'annual_volume' => true, + 'average_flow_rate' => true, + 'water_drawing_derivation_use_id' => true, + 'water_drawing_derivation_type_id' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_derivation_type' => true, + ]; + + protected array $_hidden = ['geometry']; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingDerivationType.php b/idrocap_wa/src/Model/Entity/WaterDrawingDerivationType.php new file mode 100644 index 0000000..a7e4462 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingDerivationType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_derivations' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingFee.php b/idrocap_wa/src/Model/Entity/WaterDrawingFee.php new file mode 100644 index 0000000..bbe1448 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingFee.php @@ -0,0 +1,65 @@ + + */ + protected array $_accessible = [ + 'amount' => true, + 'year' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_paperwork' => true, + 'water_drawing_payments' => true, + ]; + + protected array $_virtual = [ + 'paied', + 'to_pay', + ]; + + protected function _getPaied(): Bool{ + if(!isset($this->id)) return false; + $total = 0; + $waterDrawingPaymentsTable = TableRegistry::getTableLocator()->get('WaterDrawingPayments'); + $water_drawing_payments = $waterDrawingPaymentsTable->find()->where(['WaterDrawingPayments.water_drawing_fee_id' => $this->id])->toArray(); + foreach($water_drawing_payments as $water_drawing_payment){ + $total += $water_drawing_payment->amount; + } + return ($this->amount <= $total); + } + + protected function _getToPay(): float{ + if(!isset($this->id)) return 0; + $payed = 0; + $waterDrawingPaymentsTable = TableRegistry::getTableLocator()->get('WaterDrawingPayments'); + $water_drawing_payments = $waterDrawingPaymentsTable->find()->where(['WaterDrawingPayments.water_drawing_fee_id' => $this->id])->toArray(); + foreach($water_drawing_payments as $water_drawing_payment){ + $payed = $payed + $water_drawing_payment->amount; + } + return $this->amount - $payed; + } +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUse.php b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUse.php new file mode 100644 index 0000000..5a8759b --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUse.php @@ -0,0 +1,55 @@ + + */ + protected array $_accessible = [ + 'area' => true, + 'cadastral_code' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'consortium_area' => true, + 'rated_power_produced' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_intended_use_type_id' => true, + 'vegetation_match_status' => true, + 'water_drawing_watering_system_id' => true, + 'water_drawing_paperwork' => true, + 'water_drawing_intended_use_type' => true, + 'cadastral_crop_types' => true, + 'water_drawing_meters' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUseType.php b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUseType.php new file mode 100644 index 0000000..9000d1d --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingIntendedUseType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_intended_uses' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingMeasurement.php b/idrocap_wa/src/Model/Entity/WaterDrawingMeasurement.php new file mode 100644 index 0000000..a90ccc5 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingMeasurement.php @@ -0,0 +1,39 @@ + + */ + protected array $_accessible = [ + 'volume' => true, + 'date' => true, + 'water_drawing_meter_id' => true, + 'user_id' => true, + 'water_drawing_meter' => true, + 'user' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingMeter.php b/idrocap_wa/src/Model/Entity/WaterDrawingMeter.php new file mode 100644 index 0000000..619fc52 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingMeter.php @@ -0,0 +1,45 @@ + + */ + protected array $_accessible = [ + 'water_drawing_tool_type_id' => true, + 'water_drawing_intended_use_id' => true, + 'manufacturer' => true, + 'part_number' => true, + 'installation_date' => true, + 'removal_date' => true, + 'water_drawing_tool_type' => true, + 'water_drawing_measurements' => true, + 'water_drawing_intended_use' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperwork.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperwork.php new file mode 100644 index 0000000..3c6c7f0 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperwork.php @@ -0,0 +1,479 @@ + + */ + protected array $_accessible = [ + 'water_drawing_paperwork_status_id' => true, + 'district' => true, + 'location' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'x_coordinate' => true, + 'y_coordinate' => true, + 'istat' => true, + 'derivation_type' => true, + 'derivation_status' => true, + 'withdrawals_amount' => true, + 'annual_volume' => true, + 'average_flow_rate' => true, + 'from_date' => true, + 'to_date' => true, + 'gurs_reference' => true, + 'authorisation_type' => true, + 'concession_decree_number' => true, + 'release_date' => true, + 'concession_duration' => true, + 'expiration_date' => true, + 'first_istance' => true, + 'takeover' => true, + 'year' => true, + 'fee_payment_certificate' => true, + 'initial_static_level_water' => true, + 'initial_static_level_water_date' => true, + 'static_level_water' => true, + 'static_level_water_date' => true, + 'authority_province' => true, + 'authority_identification_code_civil_engineering_office' => true, + 'authority_identification_code_derivation_department_water_waste' => true, + 'water_drawing_article_id' => true, + 'water_drawing_article' => true, + 'water_body' => true, + 'cadastral_code' => true, + 'controllable_object_id' => true, + 'water_drawing_paperwork_status' => true, + 'controllable_object' => true, + 'water_drawing_measurements' => true, + 'applicants' => true, + 'water_drawing_paperwork_histories' => true, + 'attachments' => true, + 'removefiles' => true, + 'feature_collection' => true, + 'geom' => true, + 'scanned' => true, + 'drar_user_id' => true, + 'gc_user_id' => true, + 'water_drawing_antimafia_certification_requests' => true, + 'water_drawing_derivations' => true, + 'water_drawing_return_points' => true, + 'water_drawing_intended_uses' => true, + 'water_drawing_fees' => true, + 'protocol_number' => true, + ]; + + protected array $_virtual = [ + 'water_drawing_paperwork_type_description', + 'authority_civil_engineer_code', + 'check_thc', + 'check_dv', + 'check_lic', + 'check_dec', + 'check_dsc', + 'check2a', + 'check_ssd', + 'check_dam', + 'check_rap', + 'check_ia7', + 'check_ia56', + 'check_ira', + 'check_adam', + 'percentage', + 'check_ram', + 'check_isu', + 'check_rpdi', + 'check_thc_a', + 'check_thc_aa', + 'check_thc_ab', + 'check_thc_ac', + 'check_thc_ad', + 'check_thc_ae', + 'check_thc_af', + 'check_thc_ag', + 'check_thc_b', + 'check_thc_b1', + 'check_thc_b2', + 'check_thc_b3', + 'check_thc_b4', + ]; + + /** + * _getWaterDrawingPaperworkTypeDescription + * + * Virtual Field that returns water_drawing_paperwork description based on the type of instance attachment uploaded + * + * @return string + */ + protected function _getWaterDrawingPaperworkTypeDescription(): string + { + if ($this->_getCheckRap() || $this->_getCheckIa7()) return __('Istanza concessione art. 7'); + if ($this->_getCheckIa56()) return __('Istanza concessione art. 56'); + if ($this->_getCheckIra()) return __('Istanza attingimento art. 30'); + if ($this->_getCheckIsu()) return __('Istanza subentro art. 20'); + if ($this->_getCheckIrc56()) return __('Istanza rinnovo concessione art.56'); + return __(''); + } + + protected function _getAuthorityCivilEngineerCode(): string + { + if (!isset($this->authority_province)) { + return ""; + } + + $sigla = ""; + + switch(strtolower($this->authority_province)){ + case "catania": + $sigla = "CT"; + break; + case "palermo": + $sigla = "PA"; + break; + case "caltanissetta": + $sigla = "CL"; + break; + case "enna": + $sigla = "EN"; + break; + case "ragusa": + $sigla = "RG"; + break; + case "siracusa": + $sigla = "SR"; + break; + case "trapani": + $sigla = "TP"; + break; + case "messina": + $sigla = "ME"; + break; + case "agrigento": + $sigla = "AG"; + break; + default: + $sigla = ""; + } + + return "GC " . $sigla; + } + + protected function _getCheckThc(): Bool{ + return $this->checkDocument(-8); + } + + protected function _getCheckDv(): Bool{ + return $this->checkDocument(-7); + } + + protected function _getCheckLic(): Bool{ + return $this->checkDocument(-6); + } + + protected function _getCheckDec(): Bool{ + return $this->checkDocument(-5); + } + + protected function _getCheckDsc(): Bool{ + return $this->checkDocument(-4); + } + + protected function _getCheck2a(): Bool{ + return $this->checkDocument(-3); + } + + protected function _getCheckSdd(): Bool{ + return $this->checkDocument(-10); + } + + protected function _getCheckDam(): Bool{ + return $this->checkDocument(-11); + } + + protected function _getCheckRap(): Bool{ + return $this->checkDocument(1); + } + + protected function _getCheckIa7(): Bool{ + return $this->checkDocument(2); + } + + protected function _getCheckIa56(): Bool{ + return $this->checkDocument(3); + } + + protected function _getCheckIra(): Bool{ + return $this->checkDocument(4); + } + + protected function _getCheckAdam(): Bool{ + return $this->checkDocument(5); + } + + protected function _getCheckRam(): Bool{ + return $this->checkDocument(-14); + } + + protected function _getCheckIsu(): Bool{ + return $this->checkDocument(6); + } + + protected function _getCheckRpdi(): Bool{ + return $this->checkDocument(-15); + } + + protected function _getCheckThcA(): Bool{ + return $this->checkDocument(7); + } + + protected function _getCheckThcAa(): Bool{ + return $this->checkDocument(8); + } + + protected function _getCheckThcAb(): Bool{ + return $this->checkDocument(9); + } + + protected function _getCheckThcAc(): Bool{ + return $this->checkDocument(10); + } + + protected function _getCheckThcAd(): Bool{ + return $this->checkDocument(11); + } + + protected function _getCheckThcAe(): Bool{ + return $this->checkDocument(12); + } + + protected function _getCheckThcAf(): Bool{ + return $this->checkDocument(13); + } + + protected function _getCheckThcAg(): Bool{ + return $this->checkDocument(14); + } + + protected function _getCheckThcB(): Bool{ + return $this->checkDocument(15); + } + + protected function _getCheckThcB1(): Bool{ + return $this->checkDocument(16); + } + + protected function _getCheckThcB2(): Bool{ + return $this->checkDocument(17); + } + + protected function _getCheckThcB3(): Bool{ + return $this->checkDocument(18); + } + + protected function _getCheckThcB4(): Bool{ + return $this->checkDocument(19); + } + + protected function _getCheckIrc56(): Bool{ + return $this->checkDocument(20); + } + + private function checkDocument($tagId): Bool{ + if(!isset($this->_fields['controllable_object_id'])) return false; + $attachment = TableRegistry::getTableLocator()->get('Attachments')->find()->matching('Tags', function ($q) use ($tagId){ + return $q->where(['Tags.id' => $tagId]); + })->contain(['ControllableObjects']) + ->where(['Attachments.container_controllable_object_id' => $this->_fields['controllable_object_id'], 'ControllableObjects.deleted IS NULL'])->first(); + return isset($attachment); + } + + protected function _getGeom($value) + { + if (!is_string($value) || empty(json_decode($value))) { + return $value; + } + return new QueryExpression("ST_GeomFromGeoJson('$value')"); + } + + protected function _getPercentage() + { + $value = 0; + $fieldsCount = 33; + if(isset($this->_fields['protocol_number'])) $value++; + if(isset($this->_fields['authority_civil_engineer_code'])) $value++; + if(isset($this->_fields['authority_province'])) $value++; + if(isset($this->_fields['authority_identification_code_civil_engineering_office'])) $value++; + if(isset($this->_fields['authority_identification_code_derivation_department_water_waste'])) $value++; + if(isset($this->_fields['water_drawing_article_id'])) $value++; + if(isset($this->_fields['applicants'])) $value++; + if(isset($this->_fields['water_drawing_derivations'])) $value++; + if(isset($this->_fields['water_drawing_intended_uses'])) $value++; + if(isset($this->_fields['water_drawing_return_points'])) $value++; + if(isset($this->_fields['from_date'])) $value++; + if(isset($this->_fields['to_date'])) $value++; + if(isset($this->_fields['gurs_reference'])) $value++; + if(isset($this->_fields['authorisation_type'])) $value++; + if(isset($this->_fields['expiration_date'])) $value++; + if(isset($this->_fields['first_istance'])) $value++; + if(isset($this->_fields['takeover'])) $value++; + if(isset($this->_fields['concession_decree_number'])) $value++; + if(isset($this->_fields['water_drawing_fees'])) $value++; + if(isset($this->_fields['water_drawing_intended_uses']) && isset($this->_fields['water_drawing_intended_uses'][0]['water_drawing_meters'])) $value++; + if(isset($this->_fields['static_level_water'])) $value++; + if(isset($this->_fields['static_level_water_date'])) $value++; + if(isset($this->_fields['initial_static_level_water'])) $value++; + if(isset($this->_fields['initial_static_level_water_date'])) $value++; + if(isset($this->check_thc)) $value++; + if(isset($this->check_dv)) $value++; + if(isset($this->check_lic)) $value++; + if(isset($this->check_dec)) $value++; + if(isset($this->check_dsc)) $value++; + if(isset($this->check_ssd)) $value++; + if(isset($this->check2a)) $value++; + if(isset($this->check_dam)) $value++; + if(isset($this->check_rpdi)) $value++; + return number_format(($value*100)/$fieldsCount, 0, '.','') . '%'; + } + + /** + * is_citizen_documentation_ok_to_send + * + * serve a stabilire se la documentazione minima necessaria per la sottomissione della pratica cittadino è presente oppure no + * + * @return Bool + */ + public function is_citizen_documentation_ok_to_send (): Bool + { + return + $this->_getCheckRpdi() + && + ( + $this->_getCheckIra() + || + $this->_getCheckIsu() + || + $this->_getCheckIrc56() + || + ( + ( + $this->_getCheckRap() + || + $this->_getCheckIa7() + || + $this->_getCheckIa56() + ) + && + $this->_getCheckThcA() + && + $this->_getCheckThcAa() + && + $this->_getCheckThcAb() + && + $this->_getCheckThcAc() + && + $this->_getCheckThcAd() + && + $this->_getCheckThcAe() + && + $this->_getCheckThcB() + && + $this->_getCheckThcB2() + ) + ); + } + + /** + * is_citizen_water_drawing_paperwork_status_ok_to_send + * + * serve a stabilire se lo stato della pratica cittadino è conforme per la sua sottomissione oppure no + * + * @return Bool + */ + public function is_citizen_water_drawing_paperwork_status_ok_to_send (): Bool + { + return in_array($this->_fields['water_drawing_paperwork_status_id'], [8, 11]); + } + + /** + * is_citizen_water_drawing_paperwork_ok_to_send + * + * serve a stabilire se la pratica cittadino è pronta alla sottomissione oppure no + * + * @return Bool + */ + public function is_citizen_water_drawing_paperwork_ok_to_send (): Bool + { + return $this->is_citizen_documentation_ok_to_send() && $this->is_citizen_water_drawing_paperwork_status_ok_to_send(); + } +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkHistory.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkHistory.php new file mode 100644 index 0000000..42bada6 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkHistory.php @@ -0,0 +1,54 @@ + + */ + protected array $_accessible = [ + 'result' => true, + 'note' => true, + 'created' => true, + 'user_id' => true, + 'water_drawing_paperwork_id' => true, + 'deleted' => true, + 'water_drawing_paperwork_status_id' => true, + 'controllable_object_id' => true, + 'user' => true, + 'water_drawing_paperwork' => true, + 'water_drawing_paperwork_status' => true, + 'attachments' => true, + 'removefiles' => true, + 'controllable_object' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkPec.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkPec.php new file mode 100644 index 0000000..8533c80 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkPec.php @@ -0,0 +1,53 @@ + + */ + protected array $_accessible = [ + 'water_drawing_paperwork_id' => true, + 'user_id' => true, + 'controllable_object_id' => true, + 'document' => true, + 'protocol_number' => true, + 'protocol_date' => true, + 'recipient' => true, + 'sender' => true, + 'water_drawing_paperwork' => true, + 'user' => true, + 'controllable_object' => true, + 'attachments' => true, + 'removefiles' => true, + 'note' => true + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkStatus.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkStatus.php new file mode 100644 index 0000000..7f2af0e --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaperworkStatus.php @@ -0,0 +1,33 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'rgb' => true, + 'water_drawing_paperworks' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPayment.php b/idrocap_wa/src/Model/Entity/WaterDrawingPayment.php new file mode 100644 index 0000000..53d44b6 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPayment.php @@ -0,0 +1,56 @@ + + */ + protected array $_accessible = [ + 'water_drawing_fee_id' => true, + 'water_drawing_payment_type_id' => true, + 'user_id' => true, + 'amount' => true, + 'payment_date' => true, + 'payment_number' => true, + 'notes' => true, + 'created' => true, + 'water_drawing_fee' => true, + 'water_drawing_payment_type' => true, + 'user' => true, + 'receipt_number' => true, + 'receipt_date' => true, + 'receipt_amount' => true, + 'applicant_tax_code' => true + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingPaymentType.php b/idrocap_wa/src/Model/Entity/WaterDrawingPaymentType.php new file mode 100644 index 0000000..014a986 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingPaymentType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_payments' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingReturnPoint.php b/idrocap_wa/src/Model/Entity/WaterDrawingReturnPoint.php new file mode 100644 index 0000000..4a03f2c --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingReturnPoint.php @@ -0,0 +1,43 @@ + + */ + protected array $_accessible = [ + 'latitude' => true, + 'longitude' => true, + 'feature_collection' => true, + 'district' => true, + 'cadastral_sheet' => true, + 'cadastral_parcel' => true, + 'water_drawing_paperwork_id' => true, + 'water_drawing_paperwork' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingToolType.php b/idrocap_wa/src/Model/Entity/WaterDrawingToolType.php new file mode 100644 index 0000000..165ebb6 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingToolType.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_meters' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Entity/WaterDrawingWateringSystem.php b/idrocap_wa/src/Model/Entity/WaterDrawingWateringSystem.php new file mode 100644 index 0000000..4c21c28 --- /dev/null +++ b/idrocap_wa/src/Model/Entity/WaterDrawingWateringSystem.php @@ -0,0 +1,31 @@ + + */ + protected array $_accessible = [ + 'description' => true, + 'water_drawing_intended_uses' => true, + ]; +} diff --git a/idrocap_wa/src/Model/Table/ActorTypesTable.php b/idrocap_wa/src/Model/Table/ActorTypesTable.php new file mode 100644 index 0000000..1601834 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ActorTypesTable.php @@ -0,0 +1,81 @@ +setTable('actor_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Actors', [ + 'foreignKey' => 'actor_type_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('entity') + ->maxLength('entity', 255) + ->requirePresence('entity', 'create') + ->notEmptyString('entity'); + + $validator + ->scalar('table') + ->maxLength('table', 255) + ->requirePresence('table', 'create') + ->notEmptyString('table'); + + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ActorsTable.php b/idrocap_wa/src/Model/Table/ActorsTable.php new file mode 100644 index 0000000..fe71589 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ActorsTable.php @@ -0,0 +1,126 @@ +setTable('actors'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ActorTypes', [ + 'foreignKey' => 'actor_type_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('Deliveries', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Groups', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Organisations', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Users', [ + 'foreignKey' => 'actor_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->integer('actor_type_id') + ->requirePresence('actor_type_id', 'create') + ->notEmptyString('actor_type_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_type_id', 'ActorTypes'), ['errorField' => 'actor_type_id']); + $rules->addDelete(function ($entity, $options) { + // mi assicuro che l'actor è di tipo Groups + if($entity->actor_type_id == 6) { + $group = $this->Groups->find()->where(['actor_id' => $entity->id])->first(); + if(isset($group) && !$group->is_editable) { + return false; + } + } + return true; + }, 'checkGroupIsEditable', ['errorField' => 'is_editable', 'message' => __('Questo profilo non può essere eliminato.')]); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/ApplicantsTable.php b/idrocap_wa/src/Model/Table/ApplicantsTable.php new file mode 100644 index 0000000..ab210f6 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ApplicantsTable.php @@ -0,0 +1,208 @@ +setTable('applicants'); + $this->setDisplayField('name'); + $this->setPrimaryKey('id'); + + $this->hasMany('ApplicantsWaterDrawingPaperworks', [ + 'foreignKey' => 'applicant_id', + ]); + $this->belongsToMany('WaterDrawingPaperworks', [ + 'foreignKey' => 'applicant_id', + 'targetForeignKey' => 'water_drawing_paperwork_id', + 'joinTable' => 'applicants_water_drawing_paperworks', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('name') + ->maxLength('name', 255) + ->allowEmptyString('name'); + + $validator + ->scalar('surname') + ->maxLength('surname', 255) + ->allowEmptyString('surname'); + + $validator + ->scalar('company_name') + ->maxLength('company_name', 255) + ->allowEmptyString('company_name'); + + $validator + ->scalar('tax_code') + ->maxLength('tax_code', 255) + ->allowEmptyString('tax_code') + ->regex('tax_code', '/^[A-Z]{6}[0-9LMNPQRSTUV]{2}[A-EHLMPR-T]{1}[0-9LMNPQRSTUV]{2}[A-Z]{1}[0-9LMNPQRSTUV]{3}[A-Z]{1}$/', 'Il formato del codice fiscale è errato.'); + + $validator + ->scalar('vat_number') + ->maxLength('vat_number', 255) + ->allowEmptyString('vat_number'); + + $validator + ->scalar('address') + ->maxLength('address', 255) + ->allowEmptyString('address'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->allowEmptyString('district'); + + $validator + ->scalar('province') + ->maxLength('province', 255) + ->allowEmptyString('province'); + + $validator + ->scalar('pec_address') + ->email('pec_address', true) + ->maxLength('pec_address', 255) + ->allowEmptyString('pec_address'); + + $validator + ->scalar('email_address') + ->maxLength('email_address', 255) + ->allowEmptyString('email_address'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['tax_code', 'deleted'], __('Un richiedente con lo stesso codice fiscale è già presente!')), ['errorField' => 'tax_code']); + + $rules->add(function ($entity, $options) { + $districtsTable = $this->fetchTable("Districts"); + + if (!empty($entity->district)) { + $exists = $districtsTable->exists(['comune' => $entity->district]); + if (!$exists) { + return false; + } + } + + return true; + }, 'validDistrict', [ + 'errorField' => 'district', + 'message' => 'Il comune selezionato non è valido.' + ]); + + $rules->add(function ($entity, $options) { + $countiesTable = $this->fetchTable("Counties"); + + if (!empty($entity->province)) { + $provinceField = strlen($entity->province) === 2 ? 'sigla' : 'den_uts'; + $exists = $countiesTable->exists([$provinceField => $entity->province]); + if (!$exists) { + return false; + } + } + + return true; + }, 'validProvince', [ + 'errorField' => 'province', + 'message' => 'La provincia selezionata non è valida.' + ]); + + return $rules; + } + + public function beforeMarshal( $event, $data, $options) + { + if (isset($data['tax_code'])) { + $data['tax_code'] = strtoupper($data['tax_code']); + } + if (isset($data['province'])) { + switch (strtolower($data['province'])) { + case 'catania': + $data['province'] = 'CT'; + break; + case 'palermo': + $data['province'] = 'PA'; + break; + case 'caltanissetta': + $data['province'] = 'CL'; + break; + case 'enna': + $data['province'] = 'EN'; + break; + case 'ragusa': + $data['province'] = 'RG'; + break; + case 'siracusa': + $data['province'] = 'SR'; + break; + case 'trapani': + $data['province'] = 'TP'; + break; + case 'messina': + $data['province'] = 'ME'; + break; + case 'agrigento': + $data['province'] = 'AG'; + break; + } + } + } +} diff --git a/idrocap_wa/src/Model/Table/ApplicantsWaterDrawingPaperworksTable.php b/idrocap_wa/src/Model/Table/ApplicantsWaterDrawingPaperworksTable.php new file mode 100644 index 0000000..d467201 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ApplicantsWaterDrawingPaperworksTable.php @@ -0,0 +1,100 @@ +setTable('applicants_water_drawing_paperworks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Applicants', [ + 'foreignKey' => 'applicant_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('applicant_id') + ->notEmptyString('applicant_id'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->allowEmptyString('is_primary_applicant'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('applicant_id', 'Applicants'), ['errorField' => 'applicant_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add(function ($entity){ + $result = $this->find()->where([ + 'ApplicantsWaterDrawingPaperworks.applicant_id' => $entity->applicant_id, + 'ApplicantsWaterDrawingPaperworks.water_drawing_paperwork_id' => $entity->water_drawing_paperwork_id]) + ->count(); + return $result <= 1; + }, ['errorField' => 'applicant_id', 'message' => __('Questo richiedente è già presente all\'interno della pratica.')]); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/AttachmentsTable.php b/idrocap_wa/src/Model/Table/AttachmentsTable.php new file mode 100644 index 0000000..6283be7 --- /dev/null +++ b/idrocap_wa/src/Model/Table/AttachmentsTable.php @@ -0,0 +1,133 @@ +setTable('attachments'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ContainerControllableObjects', [ + 'className' => 'ControllableObjects', + 'foreignKey' => 'container_controllable_object_id', + 'joinType' => 'INNER', + ]); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsToMany('Tags', [ + 'foreignKey' => 'attachment_id', + 'targetForeignKey' => 'tag_id', + 'joinTable' => 'attachments_tags', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('original_file_name') + ->maxLength('original_file_name', 255) + ->requirePresence('original_file_name', 'create') + ->notEmptyFile('original_file_name'); + + $validator + ->integer('original_file_size') + ->requirePresence('original_file_size', 'create') + ->notEmptyFile('original_file_size'); + + $validator + ->scalar('file_name') + ->maxLength('file_name', 255) + ->requirePresence('file_name', 'create') + ->notEmptyFile('file_name'); + + $validator + ->scalar('mimetype') + ->maxLength('mimetype', 255) + ->requirePresence('mimetype', 'create') + ->notEmptyString('mimetype'); + + $validator + ->dateTime('upload_date') + ->requirePresence('upload_date', 'create') + ->notEmptyDateTime('upload_date'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->integer('container_controllable_object_id') + ->allowEmptyString('container_controllable_object_id'); + + $validator + ->boolean('relevant') + ->allowEmptyString('relevant'); + + $validator + ->boolean('private') + ->notEmptyString('private'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/BackgroundTasksTable.php b/idrocap_wa/src/Model/Table/BackgroundTasksTable.php new file mode 100644 index 0000000..f87ea46 --- /dev/null +++ b/idrocap_wa/src/Model/Table/BackgroundTasksTable.php @@ -0,0 +1,103 @@ +setTable('background_tasks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->hasMany('DispatchingTasks', [ + 'foreignKey' => 'background_task_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('command') + ->maxLength('command', 4294967295) + ->requirePresence('command', 'create') + ->notEmptyString('command'); + + $validator + ->scalar('data') + ->maxLength('data', 4294967295) + ->requirePresence('data', 'create') + ->notEmptyString('data'); + + $validator + ->scalar('dgroup') + ->maxLength('dgroup', 255) + ->allowEmptyString('dgroup') + ->add('dgroup', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->integer('status') + ->notEmptyString('status'); + + $validator + ->notEmptyString('was_synced'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['dgroup'], ['allowMultipleNulls' => true]), ['errorField' => 'dgroup']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CadastralCropTypesTable.php b/idrocap_wa/src/Model/Table/CadastralCropTypesTable.php new file mode 100644 index 0000000..cd1d133 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CadastralCropTypesTable.php @@ -0,0 +1,69 @@ +setTable('cadastral_crop_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsToMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'cadastral_crop_type_id', + 'targetForeignKey' => 'water_drawing_intended_use_id', + 'joinTable' => 'cadastral_crop_types_water_drawing_intended_uses', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilitiesMenuItemsTable.php b/idrocap_wa/src/Model/Table/CapabilitiesMenuItemsTable.php new file mode 100644 index 0000000..1b064d3 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilitiesMenuItemsTable.php @@ -0,0 +1,91 @@ +setTable('capabilities_menu_items'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Capabilities', [ + 'foreignKey' => 'capability_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('MenuItems', [ + 'foreignKey' => 'menu_item_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('capability_id') + ->requirePresence('capability_id', 'create') + ->notEmptyString('capability_id'); + + $validator + ->integer('menu_item_id') + ->requirePresence('menu_item_id', 'create') + ->notEmptyString('menu_item_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_id', 'Capabilities'), ['errorField' => 'capability_id']); + $rules->add($rules->existsIn('menu_item_id', 'MenuItems'), ['errorField' => 'menu_item_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilitiesMenuSectionsTable.php b/idrocap_wa/src/Model/Table/CapabilitiesMenuSectionsTable.php new file mode 100644 index 0000000..2b40932 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilitiesMenuSectionsTable.php @@ -0,0 +1,91 @@ +setTable('capabilities_menu_sections'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Capabilities', [ + 'foreignKey' => 'capability_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('MenuSections', [ + 'foreignKey' => 'menu_section_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('capability_id') + ->requirePresence('capability_id', 'create') + ->notEmptyString('capability_id'); + + $validator + ->integer('menu_section_id') + ->requirePresence('menu_section_id', 'create') + ->notEmptyString('menu_section_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_id', 'Capabilities'), ['errorField' => 'capability_id']); + $rules->add($rules->existsIn('menu_section_id', 'MenuSections'), ['errorField' => 'menu_section_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilitiesTable.php b/idrocap_wa/src/Model/Table/CapabilitiesTable.php new file mode 100644 index 0000000..d218875 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilitiesTable.php @@ -0,0 +1,145 @@ +setTable('capabilities'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('CapabilityGroups', [ + 'foreignKey' => 'capability_group_id', + 'joinType' => 'INNER', + ]); + $this->belongsToMany('Groups', [ + 'foreignKey' => 'capability_id', + 'targetForeignKey' => 'group_id', + 'joinTable' => 'permissions', + ]); + $this->belongsToMany('MenuItems', [ + 'foreignKey' => 'capability_id', + 'targetForeignKey' => 'menu_item_id', + 'joinTable' => 'capabilities_menu_items', + ]); + $this->belongsToMany('MenuSections', [ + 'foreignKey' => 'capability_id', + 'targetForeignKey' => 'menu_section_id', + 'joinTable' => 'capabilities_menu_sections', + ]); + $this->hasMany('Permissions', [ + 'foreignKey' => 'capability_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value'); + + $validator + ->integer('priority') + ->notEmptyString('priority'); + + $validator + ->integer('capability_group_id') + ->requirePresence('capability_group_id', 'create') + ->notEmptyString('capability_group_id'); + + $validator + ->integer('priority_group_id') + ->allowEmptyString('priority_group_id'); + + $validator + ->boolean('organisation_required') + ->notEmptyString('organisation_required'); + + $validator + ->scalar('longdescription') + ->maxLength('longdescription', 4294967295) + ->allowEmptyString('longdescription'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->boolean('is_configurable') + ->notEmptyString('is_configurable'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_group_id', 'CapabilityGroups'), ['errorField' => 'capability_group_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/CapabilityGroupsTable.php b/idrocap_wa/src/Model/Table/CapabilityGroupsTable.php new file mode 100644 index 0000000..a517cb5 --- /dev/null +++ b/idrocap_wa/src/Model/Table/CapabilityGroupsTable.php @@ -0,0 +1,79 @@ +setTable('capability_groups'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('Capabilities', [ + 'foreignKey' => 'capability_group_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->boolean('is_configurable') + ->notEmptyString('is_configurable'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectInterfaceTypesTable.php b/idrocap_wa/src/Model/Table/ControllableObjectInterfaceTypesTable.php new file mode 100644 index 0000000..3375fb0 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectInterfaceTypesTable.php @@ -0,0 +1,77 @@ +setTable('controllable_object_interface_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('ControllableObjectInterfaces', [ + 'foreignKey' => 'controllable_object_interface_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('entity') + ->maxLength('entity', 255) + ->requirePresence('entity', 'create') + ->notEmptyString('entity'); + + $validator + ->scalar('table') + ->maxLength('table', 255) + ->requirePresence('table', 'create') + ->notEmptyString('table'); + + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectInterfacesTable.php b/idrocap_wa/src/Model/Table/ControllableObjectInterfacesTable.php new file mode 100644 index 0000000..5b08d1b --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectInterfacesTable.php @@ -0,0 +1,95 @@ +setTable('controllable_object_interfaces'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjectInterfaceTypes', [ + 'foreignKey' => 'controllable_object_interface_type_id', + 'joinType' => 'INNER', + ]); + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = -1; + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->integer('controllable_object_interface_type_id') + ->notEmptyString('controllable_object_interface_type_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('controllable_object_interface_type_id', 'ControllableObjectInterfaceTypes'), ['errorField' => 'controllable_object_interface_type_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectTypesTable.php b/idrocap_wa/src/Model/Table/ControllableObjectTypesTable.php new file mode 100644 index 0000000..2cdcc31 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectTypesTable.php @@ -0,0 +1,74 @@ +setTable('controllable_object_types'); + $this->setDisplayField('label'); + $this->setPrimaryKey('id'); + + $this->hasMany('ControllableObjects', [ + 'foreignKey' => 'controllable_object_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 45) + ->allowEmptyString('description'); + + $validator + ->scalar('controller') + ->maxLength('controller', 45) + ->allowEmptyString('controller'); + + $validator + ->scalar('label') + ->maxLength('label', 255) + ->allowEmptyString('label'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/ControllableObjectsTable.php b/idrocap_wa/src/Model/Table/ControllableObjectsTable.php new file mode 100644 index 0000000..aaf1747 --- /dev/null +++ b/idrocap_wa/src/Model/Table/ControllableObjectsTable.php @@ -0,0 +1,167 @@ +setTable('controllable_objects'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Organisations', [ + 'foreignKey' => 'organisation_id', + ]); + $this->belongsTo('ControllableObjectTypes', [ + 'foreignKey' => 'controllable_object_type_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('ChildAttachments', [ + 'className' => 'Attachments', + 'foreignKey' => 'container_controllable_object_id', + 'joinType' => 'LEFT', + ]); + $this->hasMany('Attachments', [ + 'foreignKey' => 'controllable_object_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('ControllableObjectInterfaces', [ + 'foreignKey' => 'controllable_object_id', + ]); + $this->belongsTo('Creator', [ + 'foreignKey' => 'create_user_id', + 'className' => 'Users', + 'joinType' => 'LEFT' + ]); + $this->belongsTo('Modifier', [ + 'foreignKey' => 'edit_user_id', + 'className' => 'Users', + 'joinType' => 'LEFT' + ]); + $this->hasOne('Locations', [ + 'foreignKey' => 'controllable_object_id', + ]); + + $this->hasOne('WaterDrawingPaperworks', [ + 'foreignKey' => 'controllable_object_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->hasOne('WaterDrawingPaperworkPecs', [ + 'foreignKey' => 'controllable_object_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('organisation_id') + ->allowEmptyString('organisation_id'); + + $validator + ->integer('controllable_object_type_id') + ->requirePresence('controllable_object_type_id', 'create') + ->notEmptyString('controllable_object_type_id'); + + $validator + ->integer('create_user_id') + ->allowEmptyString('create_user_id'); + + $validator + ->integer('edit_user_id') + ->allowEmptyString('edit_user_id'); + + $validator + ->integer('edit_organisation_id') + ->allowEmptyString('edit_organisation_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('organisation_id', 'Organisations'), ['errorField' => 'organisation_id']); + $rules->add($rules->existsIn('controllable_object_type_id', 'ControllableObjectTypes'), ['errorField' => 'controllable_object_type_id']); + $rules->add($rules->existsIn('create_user_id', 'Creator'), ['errorField' => 'create_user_id']); + $rules->add($rules->existsIn('edit_user_id', 'Modifier'), ['errorField' => 'edit_user_id']); + $rules->add($rules->existsIn('edit_organisation_id', 'Organisations'), ['errorField' => 'edit_organisation_id']); + + return $rules; + } + + public function beforeSave(EventInterface $event, ControllableObject $entity, \ArrayObject $options) + { + $user = Router::getRequest()?->getAttribute('identity'); + if (!isset($entity->id)) $entity->organisation_id = $user->organisation_id ?? null; + if (!isset($entity->id)) $entity->create_user_id = $user->id ?? null; + $entity->edit_user_id = $user->id ?? null; + $entity->edit_organisation_id = $user->organisation_id ?? null; + } +} diff --git a/idrocap_wa/src/Model/Table/CountiesTable.php b/idrocap_wa/src/Model/Table/CountiesTable.php new file mode 100644 index 0000000..449369c --- /dev/null +++ b/idrocap_wa/src/Model/Table/CountiesTable.php @@ -0,0 +1,165 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\County get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\County findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\County patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\County> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\County|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\County saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\County>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\County> deleteManyOrFail(iterable $entities, array $options = []) + */ +class CountiesTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('counties'); + $this->setDisplayField('OGR_FID'); + $this->setPrimaryKey('OGR_FID'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->requirePresence('SHAPE', 'create') + ->notEmptyString('SHAPE'); + + $validator + ->decimal('cod_rip') + ->allowEmptyString('cod_rip'); + + $validator + ->decimal('cod_reg') + ->allowEmptyString('cod_reg'); + + $validator + ->decimal('cod_prov') + ->allowEmptyString('cod_prov'); + + $validator + ->decimal('cod_cm') + ->allowEmptyString('cod_cm'); + + $validator + ->decimal('cod_uts') + ->allowEmptyString('cod_uts'); + + $validator + ->scalar('den_prov') + ->maxLength('den_prov', 50) + ->allowEmptyString('den_prov'); + + $validator + ->scalar('den_cm') + ->maxLength('den_cm', 50) + ->allowEmptyString('den_cm'); + + $validator + ->scalar('den_uts') + ->maxLength('den_uts', 50) + ->allowEmptyString('den_uts'); + + $validator + ->scalar('sigla') + ->maxLength('sigla', 2) + ->allowEmptyString('sigla'); + + $validator + ->scalar('tipo_uts') + ->maxLength('tipo_uts', 50) + ->allowEmptyString('tipo_uts'); + + $validator + ->scalar('shape_leng') + ->maxLength('shape_leng', 255) + ->allowEmptyString('shape_leng'); + + $validator + ->scalar('shape_area') + ->maxLength('shape_area', 255) + ->allowEmptyString('shape_area'); + + return $validator; + } + + public function getCountiesByRegion(int $cod_reg, ProvinceCellDto $provinceCellConfig): array + { + $provinceFullNameField = ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::FULL_NAME); + $provinceSiglaField = ProvinceDistrictFieldHelper::raw(ProvinceDistrictFields::ABBREVIATION); + $provinceCodeValueField = $provinceCellConfig->showProvinceFullName ? $provinceFullNameField : $provinceSiglaField; + + $provinceCodeField = ProvinceDistrictFieldHelper::forCounties(ProvinceDistrictFields::PROVINCE_CODE); + $regionCodeField = ProvinceDistrictFieldHelper::forCounties(ProvinceDistrictFields::REGION_CODE); + + $results = $this->find() + ->select([$provinceCodeField, $provinceCodeValueField]) + ->where([$regionCodeField => $cod_reg]) + ->all() + ->toArray(); + + $options = Hash::combine($results, '{n}.' . $provinceCodeValueField, '{n}.' . $provinceCodeValueField); + $map = Hash::combine($results, '{n}.' . $provinceCodeValueField, '{n}.' . ProvinceDistrictFields::PROVINCE_CODE->value); + + return [ + "options" => $options, + "map" => $map, + ]; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['OGR_FID']), ['errorField' => 'OGR_FID']); + + return $rules; + } + + /** + * Returns the database connection name to use by default. + * + * @return string + */ + public static function defaultConnectionName(): string + { + return 'geo'; + } +} diff --git a/idrocap_wa/src/Model/Table/DeliveriesTable.php b/idrocap_wa/src/Model/Table/DeliveriesTable.php new file mode 100644 index 0000000..4929f7f --- /dev/null +++ b/idrocap_wa/src/Model/Table/DeliveriesTable.php @@ -0,0 +1,145 @@ +setTable('deliveries'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('DeliveryTypes', [ + 'foreignKey' => 'delivery_type_id', + 'joinType' => 'INNER', + ]); + $this->hasOne('Emails', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Faxes', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('MobilePhones', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Phones', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('PushNotifications', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('TelegramChats', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('TelegramContacts', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasOne('Pecs', [ + 'foreignKey' => 'delivery_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('actor_id') + ->requirePresence('actor_id', 'create') + ->notEmptyString('actor_id'); + + $validator + ->integer('delivery_type_id') + ->requirePresence('delivery_type_id', 'create') + ->notEmptyString('delivery_type_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + $rules->add($rules->existsIn('delivery_type_id', 'DeliveryTypes'), ['errorField' => 'delivery_type_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/DeliveryTypesTable.php b/idrocap_wa/src/Model/Table/DeliveryTypesTable.php new file mode 100644 index 0000000..730e61d --- /dev/null +++ b/idrocap_wa/src/Model/Table/DeliveryTypesTable.php @@ -0,0 +1,65 @@ +setTable('delivery_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Deliveries', [ + 'foreignKey' => 'delivery_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/DispatchingTaskItemsTable.php b/idrocap_wa/src/Model/Table/DispatchingTaskItemsTable.php new file mode 100644 index 0000000..d26676e --- /dev/null +++ b/idrocap_wa/src/Model/Table/DispatchingTaskItemsTable.php @@ -0,0 +1,111 @@ +setTable('dispatching_task_items'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('DispatchingTasks', [ + 'foreignKey' => 'dispatching_task_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('dispatching_task_id') + ->requirePresence('dispatching_task_id', 'create') + ->notEmptyString('dispatching_task_id'); + + $validator + ->integer('actor_id') + ->requirePresence('actor_id', 'create') + ->notEmptyString('actor_id'); + + $validator + ->boolean('system_dispatched') + ->allowEmptyString('system_dispatched'); + + $validator + ->integer('actor_dispatching_bitmask') + ->notEmptyString('actor_dispatching_bitmask'); + + $validator + ->integer('performed_dispatching_bitmask') + ->notEmptyString('performed_dispatching_bitmask'); + + $validator + ->integer('not_performed_dispatching_bitmask') + ->allowEmptyString('not_performed_dispatching_bitmask'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('dispatching_task_id', 'DispatchingTasks'), ['errorField' => 'dispatching_task_id']); + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/DispatchingTaskStatusesTable.php b/idrocap_wa/src/Model/Table/DispatchingTaskStatusesTable.php new file mode 100644 index 0000000..f911aa3 --- /dev/null +++ b/idrocap_wa/src/Model/Table/DispatchingTaskStatusesTable.php @@ -0,0 +1,65 @@ +setTable('dispatching_task_statuses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('DispatchingTasks', [ + 'foreignKey' => 'dispatching_task_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/DispatchingTasksTable.php b/idrocap_wa/src/Model/Table/DispatchingTasksTable.php new file mode 100644 index 0000000..3f5d008 --- /dev/null +++ b/idrocap_wa/src/Model/Table/DispatchingTasksTable.php @@ -0,0 +1,113 @@ +setTable('dispatching_tasks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('DispatchingTaskStatuses', [ + 'foreignKey' => 'dispatching_task_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('BackgroundTasks', [ + 'foreignKey' => 'background_task_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('DispatchingTaskItems', [ + 'foreignKey' => 'dispatching_task_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('dispatching_task_group') + ->maxLength('dispatching_task_group', 255) + ->requirePresence('dispatching_task_group', 'create') + ->notEmptyString('dispatching_task_group'); + + $validator + ->integer('dispatching_task_status_id') + ->requirePresence('dispatching_task_status_id', 'create') + ->notEmptyString('dispatching_task_status_id'); + + $validator + ->integer('retries') + ->notEmptyString('retries'); + + $validator + ->boolean('failed') + ->notEmptyString('failed'); + + $validator + ->integer('background_task_id') + ->requirePresence('background_task_id', 'create') + ->notEmptyString('background_task_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('dispatching_task_status_id', 'DispatchingTaskStatuses'), ['errorField' => 'dispatching_task_status_id']); + $rules->add($rules->existsIn('background_task_id', 'BackgroundTasks'), ['errorField' => 'background_task_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/DistrictsTable.php b/idrocap_wa/src/Model/Table/DistrictsTable.php new file mode 100644 index 0000000..23dec60 --- /dev/null +++ b/idrocap_wa/src/Model/Table/DistrictsTable.php @@ -0,0 +1,136 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\District get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\District findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\District patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\District> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\District|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\District saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\District>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\District> deleteManyOrFail(iterable $entities, array $options = []) + */ +class DistrictsTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('districts'); + $this->setDisplayField('OGR_FID'); + $this->setPrimaryKey('OGR_FID'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->requirePresence('SHAPE', 'create') + ->notEmptyString('SHAPE'); + + $validator + ->decimal('cod_rip') + ->allowEmptyString('cod_rip'); + + $validator + ->decimal('cod_reg') + ->allowEmptyString('cod_reg'); + + $validator + ->decimal('cod_prov') + ->allowEmptyString('cod_prov'); + + $validator + ->decimal('cod_cm') + ->allowEmptyString('cod_cm'); + + $validator + ->decimal('cod_uts') + ->allowEmptyString('cod_uts'); + + $validator + ->decimal('pro_com') + ->allowEmptyString('pro_com'); + + $validator + ->scalar('pro_com_t') + ->maxLength('pro_com_t', 6) + ->allowEmptyString('pro_com_t'); + + $validator + ->scalar('comune') + ->maxLength('comune', 100) + ->allowEmptyString('comune'); + + $validator + ->scalar('comune_a') + ->maxLength('comune_a', 100) + ->allowEmptyString('comune_a'); + + $validator + ->decimal('cc_uts') + ->allowEmptyString('cc_uts'); + + $validator + ->scalar('shape_leng') + ->maxLength('shape_leng', 255) + ->allowEmptyString('shape_leng'); + + $validator + ->scalar('shape_area') + ->maxLength('shape_area', 255) + ->allowEmptyString('shape_area'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['OGR_FID']), ['errorField' => 'OGR_FID']); + + return $rules; + } + + /** + * Returns the database connection name to use by default. + * + * @return string + */ + public static function defaultConnectionName(): string + { + return 'geo'; + } +} diff --git a/idrocap_wa/src/Model/Table/EmailDescriptionsTable.php b/idrocap_wa/src/Model/Table/EmailDescriptionsTable.php new file mode 100644 index 0000000..30b921a --- /dev/null +++ b/idrocap_wa/src/Model/Table/EmailDescriptionsTable.php @@ -0,0 +1,74 @@ +setTable('email_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Emails', [ + 'foreignKey' => 'email_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/EmailsTable.php b/idrocap_wa/src/Model/Table/EmailsTable.php new file mode 100644 index 0000000..ccff182 --- /dev/null +++ b/idrocap_wa/src/Model/Table/EmailsTable.php @@ -0,0 +1,111 @@ +setTable('emails'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('EmailDescriptions', [ + 'foreignKey' => 'email_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->email('value', true); + + $validator + ->boolean('is_system') + ->notEmptyString('is_system'); + + $validator + ->boolean('enable_notifications') + ->notEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('email_description_id') + ->requirePresence('email_description_id', 'create') + ->allowEmptyString('email_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('email_description_id', 'EmailDescriptions'), ['errorField' => 'email_description_id']); + $rules->add($rules->isUnique(['value'], __('Indirizzo email già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/FaxDescriptionsTable.php b/idrocap_wa/src/Model/Table/FaxDescriptionsTable.php new file mode 100644 index 0000000..9daf8fb --- /dev/null +++ b/idrocap_wa/src/Model/Table/FaxDescriptionsTable.php @@ -0,0 +1,73 @@ +setTable('fax_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Faxes', [ + 'foreignKey' => 'fax_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/FaxesTable.php b/idrocap_wa/src/Model/Table/FaxesTable.php new file mode 100644 index 0000000..63bac03 --- /dev/null +++ b/idrocap_wa/src/Model/Table/FaxesTable.php @@ -0,0 +1,107 @@ +setTable('faxes'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('FaxDescriptions', [ + 'foreignKey' => 'fax_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->regex('value', '/^[0-9]*$/i'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('fax_description_id') + ->requirePresence('fax_description_id', 'create') + ->allowEmptyString('fax_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('fax_description_id', 'FaxDescriptions'), ['errorField' => 'fax_description_id']); + $rules->add($rules->isUnique(['value'], __('Fax già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/FiltersTable.php b/idrocap_wa/src/Model/Table/FiltersTable.php new file mode 100644 index 0000000..37e9521 --- /dev/null +++ b/idrocap_wa/src/Model/Table/FiltersTable.php @@ -0,0 +1,105 @@ +setTable('filters'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('controller_action_category') + ->maxLength('controller_action_category', 255) + ->requirePresence('controller_action_category', 'create') + ->notEmptyString('controller_action_category'); + + $validator + ->scalar('category') + ->maxLength('category', 255) + ->requirePresence('category', 'create') + ->notEmptyString('category'); + + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('filter_type') + ->maxLength('filter_type', 255) + ->requirePresence('filter_type', 'create') + ->notEmptyString('filter_type'); + + $validator + ->scalar('class_name') + ->maxLength('class_name', 255) + ->allowEmptyString('class_name'); + + $validator + ->scalar('search') + ->maxLength('search', 255) + ->allowEmptyString('search'); + + $validator + ->scalar('associations') + ->maxLength('associations', 255) + ->allowEmptyString('associations'); + + $validator + ->integer('order_number') + ->requirePresence('order_number', 'create') + ->notEmptyString('order_number'); + + $validator + ->boolean('sys_admin_only') + ->allowEmptyString('sys_admin_only'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/GroupsGroupsTable.php b/idrocap_wa/src/Model/Table/GroupsGroupsTable.php new file mode 100644 index 0000000..831c287 --- /dev/null +++ b/idrocap_wa/src/Model/Table/GroupsGroupsTable.php @@ -0,0 +1,94 @@ +setTable('groups_groups'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ContainerGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'container_group_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ContainedGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'group_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('container_group_id') + ->requirePresence('container_group_id', 'create') + ->notEmptyString('container_group_id'); + + $validator + ->integer('group_id') + ->requirePresence('group_id', 'create') + ->notEmptyString('group_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('container_group_id', 'Groups'), ['errorField' => 'container_group_id']); + $rules->add($rules->existsIn('group_id', 'Groups'), ['errorField' => 'group_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/GroupsTable.php b/idrocap_wa/src/Model/Table/GroupsTable.php new file mode 100644 index 0000000..c6b0bfa --- /dev/null +++ b/idrocap_wa/src/Model/Table/GroupsTable.php @@ -0,0 +1,157 @@ +setTable('groups'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('Memberships', [ + 'foreignKey' => 'group_id', + ]); + $this->hasMany('Permissions', [ + 'foreignKey' => 'group_id', + ]); + $this->belongsToMany('Users', [ + 'foreignKey' => 'group_id', + 'targetForeignKey' => 'user_id', + 'joinTable' => 'memberships', + ]); + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'group_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'permissions', + ]); + + $this->belongsToMany('ChildGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'container_group_id', + 'targetForeignKey' => 'group_id', + 'joinTable' => 'groups_groups', + 'sort' => 'description ASC' + ]); + + $this->belongsToMany('ParentGroups', [ + 'className' => 'Groups', + 'foreignKey' => 'group_id', + 'targetForeignKey' => 'container_group_id', + 'joinTable' => 'groups_groups', + 'sort' => 'description ASC' + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->boolean('is_default') + ->allowEmptyString('is_default'); + + $validator + ->boolean('super_group') + ->allowEmptyString('super_group'); + + $validator + ->integer('actor_id') + ->notEmptyString('actor_id') + ->add('actor_id', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + return $validator; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['actor']['actor_type_id'] = 6; + $data['actor']['description'] = $data['description']; + + if (isset($options['group_id']) && isset($data['capabilities']['_ids'])) { + $user = Router::getRequest()->getAttribute('identity'); + if (!$user || !$user->sys_admin) { + $not_configurable_capability_ids = TableRegistry::getTableLocator()->get('Capabilities') + ->find() + ->matching('Permissions') + ->select(['Capabilities.id']) + ->where(['Permissions.group_id' => $options['group_id'], 'OR' => ['Capabilities.is_configurable IS NULL', 'Capabilities.is_configurable' => 0]]) + ->all() + ->extract('id') + ->toArray(); + + $data['capabilities']['_ids'] = array_merge($data['capabilities']['_ids'], $not_configurable_capability_ids); + } + } + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/LanguagesTable.php b/idrocap_wa/src/Model/Table/LanguagesTable.php new file mode 100644 index 0000000..dc7edfa --- /dev/null +++ b/idrocap_wa/src/Model/Table/LanguagesTable.php @@ -0,0 +1,71 @@ +setTable('languages'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 45) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('language_code') + ->maxLength('language_code', 45) + ->requirePresence('language_code', 'create') + ->notEmptyString('language_code'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/LocationAttributesTable.php b/idrocap_wa/src/Model/Table/LocationAttributesTable.php new file mode 100644 index 0000000..e77a8b2 --- /dev/null +++ b/idrocap_wa/src/Model/Table/LocationAttributesTable.php @@ -0,0 +1,116 @@ +setTable('location_attributes'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Locations', [ + 'foreignKey' => 'location_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('location_id') + ->requirePresence('location_id', 'create') + ->notEmptyString('location_id'); + + $validator + ->scalar('district_code') + ->maxLength('district_code', 255) + ->requirePresence('district_code', 'create') + ->notEmptyString('district_code'); + + $validator + ->scalar('district_name') + ->maxLength('district_name', 255) + ->requirePresence('district_name', 'create') + ->notEmptyString('district_name'); + + $validator + ->scalar('county_code') + ->maxLength('county_code', 255) + ->requirePresence('county_code', 'create') + ->notEmptyString('county_code'); + + $validator + ->scalar('county_name') + ->maxLength('county_name', 255) + ->requirePresence('county_name', 'create') + ->notEmptyString('county_name'); + + $validator + ->scalar('region') + ->maxLength('region', 255) + ->requirePresence('region', 'create') + ->notEmptyString('region'); + + $validator + ->scalar('area') + ->maxLength('area', 255) + ->requirePresence('area', 'create') + ->notEmptyString('area'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('location_id', 'Locations'), ['errorField' => 'location_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/LocationsTable.php b/idrocap_wa/src/Model/Table/LocationsTable.php new file mode 100644 index 0000000..22bcfa8 --- /dev/null +++ b/idrocap_wa/src/Model/Table/LocationsTable.php @@ -0,0 +1,118 @@ +setTable('locations'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + ]); + $this->hasMany('LocationAttributes', [ + 'foreignKey' => 'location_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('coordinates') + ->maxLength('coordinates', 4294967295) + ->allowEmptyString('coordinates'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('geom') + ->allowEmptyString('geom'); + + $validator + ->integer('controllable_object_id') + ->allowEmptyString('controllable_object_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + return $rules; + } + + public function beforeSave(EventInterface $event, Location $entity, \ArrayObject $options) + { + $locationAttributesTable = TableRegistry::getTableLocator()->get('LocationAttributes'); + $lar = new LocationAttributesRetriever($entity); + if (isset($entity->id)) { + $locationAttributesTable->deleteAll(['LocationAttributes.location_id' => $entity->id]); + } + $lar_result = $lar->retrieve(); + if (isset($lar_result['error']) && $lar_result['error']) { + throw new \Exception($lar_result['message']); + } + $entity->location_attributes = $locationAttributesTable->newEntities($lar_result); + } +} diff --git a/idrocap_wa/src/Model/Table/MapsTable.php b/idrocap_wa/src/Model/Table/MapsTable.php new file mode 100644 index 0000000..69b273c --- /dev/null +++ b/idrocap_wa/src/Model/Table/MapsTable.php @@ -0,0 +1,88 @@ +setTable('maps'); + $this->setDisplayField('name'); + $this->setPrimaryKey(['id', 'language_code']); + + $this->addBehavior('Timestamp'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('code') + ->maxLength('code', 255) + ->requirePresence('code', 'create') + ->notEmptyString('code'); + + $validator + ->scalar('name') + ->maxLength('name', 255) + ->requirePresence('name', 'create') + ->notEmptyString('name'); + + $validator + ->scalar('url_layer') + ->maxLength('url_layer', 255) + ->requirePresence('url_layer', 'create') + ->notEmptyString('url_layer'); + + $validator + ->integer('clusterize') + ->notEmptyString('clusterize'); + + $validator + ->integer('visible') + ->notEmptyString('visible'); + + $validator + ->scalar('style') + ->maxLength('style', 4294967295) + ->allowEmptyString('style'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MenuItemsTable.php b/idrocap_wa/src/Model/Table/MenuItemsTable.php new file mode 100644 index 0000000..b39dff7 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MenuItemsTable.php @@ -0,0 +1,135 @@ +setTable('menu_items'); + $this->setDisplayField('title'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ParentMenuItems', [ + 'className' => 'MenuItems', + 'foreignKey' => 'menu_item_id', + ]); + $this->belongsTo('MenuSections', [ + 'foreignKey' => 'menu_section_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('ChildMenuItems', [ + 'className' => 'MenuItems', + 'foreignKey' => 'menu_item_id', + ]); + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'menu_item_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'capabilities_menu_items', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('title') + ->maxLength('title', 255) + ->requirePresence('title', 'create') + ->notEmptyString('title'); + + $validator + ->scalar('icon') + ->maxLength('icon', 255) + ->allowEmptyString('icon'); + + $validator + ->scalar('link') + ->maxLength('link', 255) + ->allowEmptyString('link'); + + $validator + ->scalar('confirm') + ->maxLength('confirm', 255) + ->allowEmptyString('confirm'); + + $validator + ->scalar('method') + ->maxLength('method', 255) + ->allowEmptyString('method'); + + $validator + ->integer('menu_item_id') + ->allowEmptyString('menu_item_id'); + + $validator + ->integer('menu_section_id') + ->requirePresence('menu_section_id', 'create') + ->notEmptyString('menu_section_id'); + + $validator + ->integer('menu_order') + ->notEmptyString('menu_order'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('menu_item_id', 'MenuItems'), ['errorField' => 'menu_item_id']); + $rules->add($rules->existsIn('menu_section_id', 'MenuSections'), ['errorField' => 'menu_section_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/MenuSectionsTable.php b/idrocap_wa/src/Model/Table/MenuSectionsTable.php new file mode 100644 index 0000000..8959a24 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MenuSectionsTable.php @@ -0,0 +1,80 @@ +setTable('menu_sections'); + $this->setDisplayField('title'); + $this->setPrimaryKey('id'); + + $this->hasMany('MenuItems', [ + 'foreignKey' => 'menu_section_id', + ]); + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'menu_section_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'capabilities_menu_sections', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('title') + ->maxLength('title', 255) + ->requirePresence('title', 'create') + ->notEmptyString('title'); + + $validator + ->scalar('icon') + ->maxLength('icon', 255) + ->allowEmptyString('icon'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MessageStatusesTable.php b/idrocap_wa/src/Model/Table/MessageStatusesTable.php new file mode 100644 index 0000000..a50b78d --- /dev/null +++ b/idrocap_wa/src/Model/Table/MessageStatusesTable.php @@ -0,0 +1,65 @@ +setTable('message_statuses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('Messages', [ + 'foreignKey' => 'message_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MessageTypesTable.php b/idrocap_wa/src/Model/Table/MessageTypesTable.php new file mode 100644 index 0000000..c33469e --- /dev/null +++ b/idrocap_wa/src/Model/Table/MessageTypesTable.php @@ -0,0 +1,69 @@ +setTable('message_types'); + $this->setDisplayField('label'); + $this->setPrimaryKey('id'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 45) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('label') + ->maxLength('label', 45) + ->allowEmptyString('label'); + + $validator + ->integer('dispatching_bitmask_weight') + ->requirePresence('dispatching_bitmask_weight', 'create') + ->notEmptyString('dispatching_bitmask_weight'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MessagesTable.php b/idrocap_wa/src/Model/Table/MessagesTable.php new file mode 100644 index 0000000..f06dda1 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MessagesTable.php @@ -0,0 +1,150 @@ +setTable('messages'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + ]); + $this->belongsTo('MessageTypes', [ + 'foreignKey' => 'message_type_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + ]); + $this->belongsTo('MessageStatuses', [ + 'foreignKey' => 'message_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Organisations', [ + 'foreignKey' => 'organisation_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('controllable_object_id') + ->allowEmptyString('controllable_object_id'); + + $validator + ->integer('message_type_id') + ->requirePresence('message_type_id', 'create') + ->notEmptyString('message_type_id'); + + $validator + ->scalar('content') + ->allowEmptyString('content'); + + $validator + ->integer('user_id') + ->allowEmptyString('user_id'); + + $validator + ->integer('message_status_id') + ->requirePresence('message_status_id', 'create') + ->notEmptyString('message_status_id'); + + $validator + ->scalar('mgroup') + ->maxLength('mgroup', 255) + ->requirePresence('mgroup', 'create') + ->notEmptyString('mgroup'); + + $validator + ->scalar('event_string') + ->maxLength('event_string', 255) + ->requirePresence('event_string', 'create') + ->notEmptyString('event_string') + ->add('event_string', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->dateTime('last_update') + ->allowEmptyDateTime('last_update'); + + $validator + ->integer('organisation_id') + ->allowEmptyString('organisation_id'); + + $validator + ->scalar('contact') + ->maxLength('contact', 255) + ->allowEmptyString('contact'); + + $validator + ->scalar('not_delivered_reason') + ->maxLength('not_delivered_reason', 255) + ->allowEmptyString('not_delivered_reason'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['event_string']), ['errorField' => 'event_string']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('message_type_id', 'MessageTypes'), ['errorField' => 'message_type_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('message_status_id', 'MessageStatuses'), ['errorField' => 'message_status_id']); + $rules->add($rules->existsIn('organisation_id', 'Organisations'), ['errorField' => 'organisation_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/MobileComponentsTable.php b/idrocap_wa/src/Model/Table/MobileComponentsTable.php new file mode 100644 index 0000000..0e45dee --- /dev/null +++ b/idrocap_wa/src/Model/Table/MobileComponentsTable.php @@ -0,0 +1,77 @@ +setTable('mobile_components'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsToMany('Capabilities', [ + 'foreignKey' => 'mobile_component_id', + 'targetForeignKey' => 'capability_id', + 'joinTable' => 'capabilities_mobile_components', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('menu_item') + ->maxLength('menu_item', 255) + ->requirePresence('menu_item', 'create') + ->notEmptyString('menu_item'); + + $validator + ->boolean('is_enabled') + ->notEmptyString('is_enabled'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MobilePhoneDescriptionsTable.php b/idrocap_wa/src/Model/Table/MobilePhoneDescriptionsTable.php new file mode 100644 index 0000000..fe7d4c2 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MobilePhoneDescriptionsTable.php @@ -0,0 +1,74 @@ +setTable('mobile_phone_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('MobilePhones', [ + 'foreignKey' => 'mobile_phone_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('deleted') + ->maxLength('deleted', 45) + ->allowEmptyString('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/MobilePhonesTable.php b/idrocap_wa/src/Model/Table/MobilePhonesTable.php new file mode 100644 index 0000000..3cf9a20 --- /dev/null +++ b/idrocap_wa/src/Model/Table/MobilePhonesTable.php @@ -0,0 +1,111 @@ +setTable('mobile_phones'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('MobilePhoneDescriptions', [ + 'foreignKey' => 'mobile_phone_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->regex('value', '/^[0-9]*$/i'); + + $validator + ->boolean('is_system') + ->allowEmptyString('is_system'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('mobile_phone_description_id') + ->requirePresence('mobile_phone_description_id', 'create') + ->allowEmptyString('mobile_phone_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('mobile_phone_description_id', 'MobilePhoneDescriptions'), ['errorField' => 'mobile_phone_description_id']); + $rules->add($rules->isUnique(['value'], __('Cellulare già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/NotificationTypesTable.php b/idrocap_wa/src/Model/Table/NotificationTypesTable.php new file mode 100644 index 0000000..0ee11bf --- /dev/null +++ b/idrocap_wa/src/Model/Table/NotificationTypesTable.php @@ -0,0 +1,65 @@ +setTable('notification_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('Notifications', [ + 'foreignKey' => 'notification_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/NotificationsTable.php b/idrocap_wa/src/Model/Table/NotificationsTable.php new file mode 100644 index 0000000..122464a --- /dev/null +++ b/idrocap_wa/src/Model/Table/NotificationsTable.php @@ -0,0 +1,122 @@ +setTable('notifications'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('NotificationTypes', [ + 'foreignKey' => 'notification_type_id', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + $validator + ->dateTime('read_by_user') + ->allowEmptyDateTime('read_by_user'); + + $validator + ->integer('notification_type_id') + ->allowEmptyString('notification_type_id'); + + $validator + ->scalar('info') + ->requirePresence('info', 'create') + ->notEmptyString('info'); + + $validator + ->scalar('thread') + ->maxLength('thread', 45) + ->requirePresence('thread', 'create') + ->notEmptyString('thread'); + + $validator + ->scalar('ngroup') + ->maxLength('ngroup', 255) + ->allowEmptyString('ngroup'); + + $validator + ->integer('controllable_object_id') + ->allowEmptyString('controllable_object_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('notification_type_id', 'NotificationTypes'), ['errorField' => 'notification_type_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/OrganisationTypesTable.php b/idrocap_wa/src/Model/Table/OrganisationTypesTable.php new file mode 100644 index 0000000..17db0d4 --- /dev/null +++ b/idrocap_wa/src/Model/Table/OrganisationTypesTable.php @@ -0,0 +1,69 @@ +setTable('organisation_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Organisations', [ + 'foreignKey' => 'organisation_type_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/OrganisationsTable.php b/idrocap_wa/src/Model/Table/OrganisationsTable.php new file mode 100644 index 0000000..ef98dda --- /dev/null +++ b/idrocap_wa/src/Model/Table/OrganisationsTable.php @@ -0,0 +1,286 @@ +setTable('organisations'); + $this->setDisplayField('actor.description'); + $this->setPrimaryKey('id'); + + $this->belongsTo('OrganisationTypes', [ + 'foreignKey' => 'organisation_type_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('OrganisationActors', [ + 'className' => 'Actors', + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('Users', [ + 'foreignKey' => 'organisation_id', + ]); + $this->addBehavior('Muffin/Trash.Trash'); + + // non invertire l'ordine di aggiunta di questi 2 behaviors perchè le callbacks gestite devono essere eseguite in un certo ordine! + $this->addBehavior('ControllableObjectInterface'); + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('acronym') + ->maxLength('acronym', 45) + ->notEmptyString('acronym') + ->requirePresence('acronym'); + + $validator + ->scalar('geoposition') + ->allowEmptyString('geoposition'); + + $validator + ->scalar('address') + ->maxLength('address', 255) + ->notEmptyString('address') + ->requirePresence('address'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->notEmptyString('district') + ->requirePresence('district'); + + $validator + ->scalar('cap') + ->maxLength('cap', 255) + ->notEmptyString('cap') + ->requirePresence('cap'); + + $validator + ->scalar('province') + ->maxLength('province', 255) + ->notEmptyString('province') + ->requirePresence('province'); + + $validator + ->integer('organisation_type_id') + ->requirePresence('organisation_type_id', 'create') + ->notEmptyString('organisation_type_id'); + + $validator + ->integer('actor_id') + ->notEmptyString('actor_id') + ->add('actor_id', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->scalar('pec') + ->email('pec', true) + ->maxLength('pec', 255) + ->allowEmptyString('pec'); + + $validator + ->scalar('coordinates') + ->maxLength('coordinates', 4294967295) + ->notEmptyString('coordinates') + ->requirePresence('coordinates'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->scalar('photo') + ->maxLength('photo', 2555) + ->allowEmptyString('photo'); + + $validator + ->integer('controllable_object_interface_id') + ->allowEmptyString('controllable_object_interface_id'); + + return $validator; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['actor']['actor_type_id'] = 1; + + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare l\'organizzazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geoposition'] = $data['feature_collection']; + } + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + $rules->add($rules->existsIn('organisation_type_id', 'OrganisationTypes'), ['errorField' => 'organisation_type_id']); + + $rules->addCreate(function ($entity, $options) { + // controllo se l'organizzazione è di tipo Cittadini + if ($entity->isNew() && $entity->organisation_type_id === 7) { + $organisations = $this->find()->where(['organisation_type_id' => 7])->count(); + if ($organisations >= 1) { + return false; + } + } + return true; + }, 'validateOrganisationType', [ + 'errorField' => 'organisation_type_id', + "message" => __("L'organizzazione non può essere di tipo Cittadini in quanto ne esiste già una.") + ]); + + $rules->addUpdate(function ($entity, $options) { + if ($entity->getOriginal('organisation_type_id') === 7 && $entity->organisation_type_id !== 7) { + return false; + } + return true; + }, 'validateOrganisationType', [ + 'errorField' => 'organisation_type_id', + "message" => __("L'organizzazione è di tipo Cittadini e non è consentito modificarne il tipo.") + ]); + return $rules; + } + + /** + * can_index + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_index(User $user, Array &$options): Bool + { + if (!$user->hasCapability(['configuration.organisations.read', 'voluntary_organisation'])) + { + $options['error']['capabilities'] = ['configuration.organisations.read', 'voluntary_organisation']; + return false; + } + + $options['finder'] = 'all'; + $type = $options['type']; + if($type == "voluntary" || ($user->hasCapability(['voluntary_organisation']) && !$user->hasCapability(['configuration.organisations.read']))) + { + $options['finder'] = 'onlyType567'; + } + return true; + } + + /** + * findOnlyType567 + * + * @param SelectQuery $query + * @param Array $options + * @return SelectQuery + */ + public function findOnlyType567(SelectQuery $query, Array $params): SelectQuery + { + return $query->where(['Organisations.organisation_type_id IN' => [5, 6, 7]]); + } + + /** + * applySearchParams + * + * @param SelectQuery $query + * @param Array $params + * @return SelectQuery + */ + public function applySearchParams(SelectQuery $query, Array $params): SelectQuery + { + $search_params = [ + 'id' => 'Organisations.id', + 'organisation_description' => 'Actors.description', + 'acronym' => 'Organisations.acronym', + 'organisation_type_id' => 'Organisations.organisation_type_id', + 'district' => 'Organisations.district', + 'province' => 'Organisations.province', + ]; + + $searck_keys = array_keys($search_params); + + $search_conditions = collection($params) + ->filter(function ($paramValue, $paramKey) use ($searck_keys) { + return in_array($paramKey, $searck_keys); + }) + ->map(function ($paramValue, $paramKey) use ($search_params) { + return [$search_params[$paramKey] => $paramValue]; + }) + ->reduce(function ($acc, $search_condition) { + $acc[] = $search_condition; + return $acc; + }, []); + + if (!empty($search_conditions)) { + $query->where($search_conditions); + } + return $query; + } +} diff --git a/idrocap_wa/src/Model/Table/PecDescriptionsTable.php b/idrocap_wa/src/Model/Table/PecDescriptionsTable.php new file mode 100644 index 0000000..8f628b6 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PecDescriptionsTable.php @@ -0,0 +1,74 @@ +setTable('pec_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Pecs', [ + 'foreignKey' => 'pec_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/PecsTable.php b/idrocap_wa/src/Model/Table/PecsTable.php new file mode 100644 index 0000000..578021a --- /dev/null +++ b/idrocap_wa/src/Model/Table/PecsTable.php @@ -0,0 +1,111 @@ +setTable('pecs'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('PecDescriptions', [ + 'foreignKey' => 'pec_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->email('value', true); + + $validator + ->boolean('is_system') + ->notEmptyString('is_system'); + + $validator + ->boolean('enable_notifications') + ->notEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('pec_description_id') + ->requirePresence('pec_description_id', 'create') + ->allowEmptyString('pec_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('pec_description_id', 'PecDescriptions'), ['errorField' => 'pec_description_id']); + $rules->add($rules->isUnique(['value'], __('Indirizzo PEC già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/PermissionsTable.php b/idrocap_wa/src/Model/Table/PermissionsTable.php new file mode 100644 index 0000000..2a174b0 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PermissionsTable.php @@ -0,0 +1,85 @@ +setTable('permissions'); + $this->setDisplayField(['capability_id', 'group_id']); + $this->setPrimaryKey(['capability_id', 'group_id']); + + $this->belongsTo('Capabilities', [ + 'foreignKey' => 'capability_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Groups', [ + 'foreignKey' => 'group_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('capability_id', 'Capabilities'), ['errorField' => 'capability_id']); + $rules->add($rules->existsIn('group_id', 'Groups'), ['errorField' => 'group_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/PhoneDescriptionsTable.php b/idrocap_wa/src/Model/Table/PhoneDescriptionsTable.php new file mode 100644 index 0000000..412021b --- /dev/null +++ b/idrocap_wa/src/Model/Table/PhoneDescriptionsTable.php @@ -0,0 +1,73 @@ +setTable('phone_descriptions'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('Phones', [ + 'foreignKey' => 'phone_description_id', + ]); + + $this->addBehavior('Translate', [ + 'allowEmptyTranslations' => false, + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/PhonesTable.php b/idrocap_wa/src/Model/Table/PhonesTable.php new file mode 100644 index 0000000..6736469 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PhonesTable.php @@ -0,0 +1,103 @@ +setTable('phones'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('PhoneDescriptions', [ + 'foreignKey' => 'phone_description_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->requirePresence('value', 'create') + ->notEmptyString('value') + ->regex('value', '/^[0-9]*$/i'); + + $validator + ->integer('delivery_id') + ->notEmptyString('delivery_id'); + + $validator + ->integer('phone_description_id') + ->requirePresence('phone_description_id', 'create') + ->allowEmptyString('phone_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->existsIn('phone_description_id', 'PhoneDescriptions'), ['errorField' => 'phone_description_id']); + $rules->add($rules->isUnique(['value'], __('Telefono già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/PrivacyTable.php b/idrocap_wa/src/Model/Table/PrivacyTable.php new file mode 100644 index 0000000..1bc5120 --- /dev/null +++ b/idrocap_wa/src/Model/Table/PrivacyTable.php @@ -0,0 +1,90 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\Privacy get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\Privacy findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\Privacy patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\Privacy> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\Privacy|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\Privacy saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\Privacy>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\Privacy> deleteManyOrFail(iterable $entities, array $options = []) + * + * @mixin \Cake\ORM\Behavior\TimestampBehavior + */ +class PrivacyTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('privacy'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->hasMany('PrivacyUsers', [ + 'foreignKey' => 'privacy_id', + ]); + + $this->belongsToMany('Users', [ + 'foreignKey' => 'privacy_id', + 'targetForeignKey' => 'user_id', + 'joinTable' => 'privacy_users', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 4294967295) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } + + /** + * @return Privacy + */ + public function findPrivacy(): Privacy + { + $latestPrivacy = $this->find() + ->orderBy(['created' => 'DESC']) + ->first(); + + return $latestPrivacy ?? $this->newEmptyEntity(); + } +} diff --git a/idrocap_wa/src/Model/Table/PrivacyUsersTable.php b/idrocap_wa/src/Model/Table/PrivacyUsersTable.php new file mode 100644 index 0000000..3f6f5bb --- /dev/null +++ b/idrocap_wa/src/Model/Table/PrivacyUsersTable.php @@ -0,0 +1,123 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\PrivacyUser get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\PrivacyUser findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\PrivacyUser patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\PrivacyUser> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\PrivacyUser|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\PrivacyUser saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\PrivacyUser>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\PrivacyUser> deleteManyOrFail(iterable $entities, array $options = []) + * + * @mixin \Cake\ORM\Behavior\TimestampBehavior + */ +class PrivacyUsersTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('privacy_users'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Privacy', [ + 'foreignKey' => 'privacy_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('privacy_id') + ->notEmptyString('privacy_id'); + + $validator + ->integer('user_id') + ->notEmptyString('user_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn(['privacy_id'], 'Privacy'), ['errorField' => 'privacy_id']); + $rules->add($rules->existsIn(['user_id'], 'Users'), ['errorField' => 'user_id']); + + return $rules; + } + + public function saveConsent(int $userId, int $privacyId): bool + { + $acceptPrivacy = $this->newEmptyEntity(); + $acceptedPrivacy = $this->patchEntity($acceptPrivacy, [ + 'user_id' => $userId, + 'privacy_id' => $privacyId + ]); + + if ($this->save($acceptedPrivacy)) { + return true; + } + + return false; + } + + public function hasConsent(int $userId): bool + { + $userConsent = $this->find() + ->where(['user_id' => $userId]) + ->first(); + + if (isset($userConsent)) { + return true; + } + + return false; + } +} diff --git a/idrocap_wa/src/Model/Table/PushNotificationsTable.php b/idrocap_wa/src/Model/Table/PushNotificationsTable.php new file mode 100644 index 0000000..6c083dd --- /dev/null +++ b/idrocap_wa/src/Model/Table/PushNotificationsTable.php @@ -0,0 +1,101 @@ +setTable('push_notifications'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->allowEmptyString('value'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->allowEmptyString('delivery_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->addCreate(function ($entity, $options) { + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return false; + return $this->find()->matching('Deliveries')->where(['PushNotifications.value' => $entity->value, 'Deliveries.actor_id' => $user->actor_id])->first() === null; + }, 'value', [ + 'errorField' => 'value', + 'message' => __('Non puoi associare nuovamente questo token allo stesso utente') + ]); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/SnapshotsTable.php b/idrocap_wa/src/Model/Table/SnapshotsTable.php new file mode 100644 index 0000000..b77a390 --- /dev/null +++ b/idrocap_wa/src/Model/Table/SnapshotsTable.php @@ -0,0 +1,118 @@ +setTable('snapshots'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjectTypes', [ + 'foreignKey' => 'controllable_object_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('controllable_object_type_id') + ->allowEmptyString('controllable_object_type_id'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->scalar('object_snapshot') + ->maxLength('object_snapshot', 4294967295) + ->requirePresence('object_snapshot', 'create') + ->notEmptyString('object_snapshot'); + + $validator + ->dateTime('date') + ->requirePresence('date', 'create') + ->notEmptyDateTime('date'); + + $validator + ->integer('user_id') + ->allowEmptyString('user_id'); + + $validator + ->scalar('controller_action') + ->requirePresence('controller_action', 'create') + ->notEmptyString('controller_action'); + + $validator + ->integer('unpacked_with_version') + ->allowEmptyString('unpacked_with_version'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('controllable_object_type_id', 'ControllableObjectTypes'), ['errorField' => 'controllable_object_type_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/TagsTable.php b/idrocap_wa/src/Model/Table/TagsTable.php new file mode 100644 index 0000000..1c6e1a3 --- /dev/null +++ b/idrocap_wa/src/Model/Table/TagsTable.php @@ -0,0 +1,94 @@ +setTable('tags'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsToMany('Attachments', [ + 'foreignKey' => 'tag_id', + 'targetForeignKey' => 'attachment_id', + 'joinTable' => 'attachments_tags', + ]); + + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'LEFT', + ]); + + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('code') + ->maxLength('code', 255) + ->allowEmptyString('code'); + + $validator + ->scalar('class') + ->maxLength('class', 255) + ->allowEmptyString('class'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + return $validator; + } + + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 12; + } +} diff --git a/idrocap_wa/src/Model/Table/TelegramChatsTable.php b/idrocap_wa/src/Model/Table/TelegramChatsTable.php new file mode 100644 index 0000000..f6e5d36 --- /dev/null +++ b/idrocap_wa/src/Model/Table/TelegramChatsTable.php @@ -0,0 +1,99 @@ +setTable('telegram_chats'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('value') + ->maxLength('value', 255) + ->allowEmptyString('value'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->allowEmptyString('delivery_id'); + + $validator + ->integer('telegram_chat_description_id') + ->allowEmptyString('telegram_chat_description_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + $rules->add($rules->isUnique(['value'], __('ID Chat Telegram già presente a sistema!'))); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/TelegramContactsTable.php b/idrocap_wa/src/Model/Table/TelegramContactsTable.php new file mode 100644 index 0000000..4827105 --- /dev/null +++ b/idrocap_wa/src/Model/Table/TelegramContactsTable.php @@ -0,0 +1,116 @@ +setTable('telegram_contacts'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Deliveries', [ + 'foreignKey' => 'delivery_id', + 'joinType' => 'INNER', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('phone_number') + ->maxLength('phone_number', 255) + ->requirePresence('phone_number', 'create') + ->notEmptyString('phone_number'); + + $validator + ->scalar('telegram_user_id') + ->maxLength('telegram_user_id', 255) + ->allowEmptyString('telegram_user_id'); + + $validator + ->boolean('enable_notifications') + ->allowEmptyString('enable_notifications'); + + $validator + ->integer('delivery_id') + ->requirePresence('delivery_id', 'create') + ->notEmptyString('delivery_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->integer('telegram_contact_status_id') + ->requirePresence('telegram_contact_status_id', 'create') + ->notEmptyString('telegram_contact_status_id'); + + $validator + ->scalar('error_message') + ->maxLength('error_message', 255) + ->allowEmptyString('error_message'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('delivery_id', 'Deliveries'), ['errorField' => 'delivery_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/UnpackedWaterDrawingPaperworkSnapshotsTable.php b/idrocap_wa/src/Model/Table/UnpackedWaterDrawingPaperworkSnapshotsTable.php new file mode 100644 index 0000000..0f35afd --- /dev/null +++ b/idrocap_wa/src/Model/Table/UnpackedWaterDrawingPaperworkSnapshotsTable.php @@ -0,0 +1,137 @@ +setTable('unpacked_water_drawing_paperwork_snapshots'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Snapshots', [ + 'foreignKey' => 'snapshot_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('snapshot_id') + ->notEmptyString('snapshot_id'); + + $validator + ->integer('unpacking_version') + ->requirePresence('unpacking_version', 'create') + ->notEmptyString('unpacking_version'); + + $validator + ->scalar('who') + ->maxLength('who', 255) + ->allowEmptyString('who'); + + $validator + ->dateTime('when') + ->allowEmptyDateTime('when'); + + $validator + ->scalar('what') + ->maxLength('what', 255) + ->allowEmptyString('what'); + + $validator + ->scalar('creator') + ->maxLength('creator', 255) + ->allowEmptyString('creator'); + + $validator + ->scalar('modifier') + ->maxLength('modifier', 255) + ->allowEmptyString('modifier'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->scalar('water_drawing_paperwork_status') + ->maxLength('water_drawing_paperwork_status', 255) + ->allowEmptyString('water_drawing_paperwork_status'); + + $validator + ->scalar('gc_user') + ->maxLength('gc_user', 255) + ->allowEmptyString('gc_user'); + + $validator + ->scalar('drar_user') + ->maxLength('drar_user', 255) + ->allowEmptyString('drar_user'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('snapshot_id', 'Snapshots'), ['errorField' => 'snapshot_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/UsersTable.php b/idrocap_wa/src/Model/Table/UsersTable.php new file mode 100644 index 0000000..509e662 --- /dev/null +++ b/idrocap_wa/src/Model/Table/UsersTable.php @@ -0,0 +1,476 @@ +setTable('users'); + $this->setDisplayField('actor.description'); + $this->setPrimaryKey('id'); + + $this->belongsTo('Organisations', [ + 'foreignKey' => 'organisation_id', + ]); + $this->belongsTo('Languages', [ + 'foreignKey' => 'language_id', + ]); + $this->belongsTo('Actors', [ + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('UserActors', [ + 'className' => 'Actors', + 'foreignKey' => 'actor_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('PrivacyUsers', [ + 'foreignKey' => 'user_id', + ]); + $this->hasMany('Memberships', [ + 'foreignKey' => 'user_id', + ]); + $this->belongsToMany('Groups', [ + 'foreignKey' => 'user_id', + 'targetForeignKey' => 'group_id', + 'joinTable' => 'memberships', + ]); + $this->hasMany('WaterDrawingPaperworkHistories', [ + 'foreignKey' => 'user_id', + ]); + $this->hasMany('WaterDrawingAntimafiaCertificationRequests', [ + 'foreignKey' => 'user_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('organisation_id') + ->requirePresence('organisation_id', true) + ->notEmptyString('organisation_id'); + + $validator + ->scalar('username') + ->maxLength('username', 255) + ->requirePresence('username', 'create') + ->notEmptyString('username'); + + $validator + ->scalar('password') + ->maxLength('password', 255) + ->requirePresence('password', 'create') + ->notEmptyString('password') + ->minLength('password', Configure::read('App.minPasswordLength'), __('La password deve contenere almeno {0} caratteri', Configure::read('App.minPasswordLength'))) + ->add('password', 'min_capital_letters', [ + 'rule' => function ($value){ + return strlen(preg_replace('![^A-Z]+!', '', $value)) >= Configure::read('App.minPasswordCapitalCharacters'); + }, + 'message' => __('La password deve contenere almeno {0} carattere/i maiuscolo/i', Configure::read('App.minPasswordCapitalCharacters')) + ]) + ->add('password', 'min_numbers', [ + 'rule' => function ($value) { + return strlen(preg_replace('![^0-9]+!', '', $value)) >= Configure::read('App.minPasswordNumberCharacters'); + }, + 'message' => __('La password deve contenere almeno {0} numero/i', Configure::read('App.minPasswordNumberCharacters')) + ]) + ->add('password', 'min_special_characters', [ + 'rule' => function ($value, $context) { + $chars = str_split(Configure::read('App.passwordSpecialCharacters')); + $count = 0; + + foreach($chars as $char) + { + $count+=substr_count($value, $char); + } + + return $count >= Configure::read('App.minPasswordSpecialCharacters'); + }, + 'message' => __('La password deve contenere almeno {1} carattere/i speciale/i tra "{0}"', Configure::read('App.passwordSpecialCharacters'), Configure::read('App.minPasswordSpecialCharacters')) + ]); + + $validator + ->scalar('surname') + ->maxLength('surname', 255) + ->requirePresence('surname', 'create') + ->notEmptyString('surname'); + + $validator + ->scalar('name') + ->maxLength('name', 255) + ->requirePresence('name', 'create') + ->notEmptyString('name'); + + $validator + ->scalar('address') + ->maxLength('address', 255) + ->allowEmptyString('address'); + + $validator + ->scalar('city') + ->maxLength('city', 255) + ->allowEmptyString('city'); + + $validator + ->scalar('cap') + ->maxLength('cap', 255) + ->allowEmptyString('cap'); + + $validator + ->scalar('tax_code') + ->maxLength('tax_code', 255) + ->allowEmptyString('tax_code') + ->regex('tax_code', '/^[A-Z]{6}[0-9LMNPQRSTUV]{2}[A-EHLMPR-T]{1}[0-9LMNPQRSTUV]{2}[A-Z]{1}[0-9LMNPQRSTUV]{3}[A-Z]{1}$/', 'Il formato del codice fiscale è errato.'); + + $validator + ->scalar('photo') + ->maxLength('photo', 255) + ->allowEmptyString('photo'); + + $validator + ->scalar('birthplace') + ->maxLength('birthplace', 255) + ->allowEmptyString('birthplace'); + + $validator + ->dateTime('birthday') + ->allowEmptyDateTime('birthday'); + + $validator + ->scalar('gender') + ->maxLength('gender', 1) + ->allowEmptyString('gender'); + + $validator + ->integer('language_id') + ->allowEmptyString('language_id'); + + $validator + ->scalar('password_recovery_token') + ->maxLength('password_recovery_token', 255) + ->allowEmptyString('password_recovery_token'); + + $validator + ->integer('password_recovery_counter') + ->allowEmptyString('password_recovery_counter'); + + $validator + ->integer('actor_id') + ->notEmptyString('actor_id') + ->add('actor_id', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + return $validator; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + if (!empty($data['birthday'])) { + $data['birthday'] = $data['birthday'] . ' 12:00:00'; + } + $isDefaultCitizen = $options['skipCitizenOrg'] ?? false; + $data['actor']['actor_type_id'] = 5; + if (isset($data['name']) && isset($data['surname'])) { + $data['actor']['description'] = $data['name'] . ' ' . $data['surname']; + } + if (!empty($data['organisation_id']) && !$isDefaultCitizen) { + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) $data['organisation_id'] = null; + if ($user && !$user->hasCapability('configuration.users.add')) $data['organisation_id'] = $user->organisation_id; + } + + if (isset($data['groups']['_ids']) && !empty($data['groups']['_ids']) && is_array($data['groups']['_ids'])) { + $user = Router::getRequest()->getAttribute('identity'); + if ($user && !$user->sys_admin && !$user->hasCapability(['configuration.users.profiles'])) { + $associable_user_groups_ids = array_keys($this->getAssociableUserGroups(as_list: true)->toArray()); + $data['groups']['_ids'] = array_values(array_intersect($data['groups']['_ids'], $associable_user_groups_ids)); + } + } + + if (isset($data['tax_code'])) { + $data['tax_code'] = strtoupper($data['tax_code']); + } + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->isUnique(['username']), ['errorField' => 'username']); + $rules->add($rules->isUnique(['email']), ['errorField' => 'email']); + $rules->add($rules->isUnique(['tax_code']), ['errorField' => 'tax_code']); + $rules->add($rules->existsIn('organisation_id', 'Organisations'), ['errorField' => 'organisation_id']); + $rules->add($rules->existsIn('language_id', 'Languages'), ['errorField' => 'language_id']); + $rules->add($rules->existsIn('actor_id', 'Actors'), ['errorField' => 'actor_id']); + $rules->add(function ($entity, $options) { + $attachment = $entity['user_photo'] ?? null; + if ($attachment) $attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($attachment); + if (empty($attachment['tmp_name']) || !isset($attachment['error']) || $attachment['error'] !== 0) return true; + $attributes = getimagesize($attachment['tmp_name']); + $width = (String)($attributes['0'] ?? 0); + $height = (String)($attributes['1'] ?? 0); + if ($width !== '160' || $height !== '160') return false; + $file_name = (String)($entity->id ?? 0) . '_' . time() . '.jpg'; + try + { + $res = \App\WGS\FileStorage\FileStorageFactory::create()->saveFile(Configure::read('App.userPhotoPath') . "/" . $file_name, $attachment['tmp_name']); + $entity->photo = $file_name; + return true; + } + catch(\Exception $we) + { + return false; + } + }, 'user_photo_check', [ + 'errorField' => 'user_photo', + 'message' => __('Errore durante il salvataggio della foto utente. Assicurarsi che sia nel formato corretto (jpeg 160x160)'), + ]); + return $rules; + } + + /** + * can_index + * + * @param User $user + * @param Array $options + * @return Bool + */ + public function can_index(User $user, Array &$options): Bool + { + if (!$user->hasCapability(['configuration.users.read', 'configuration.users.read_foo'])) { + $options['error']['capabilities'] = ['configuration.users.read', 'configuration.users.read_foo']; + return false; + } + $options['finder'] = 'all'; + if (!$user->hasCapability(['configuration.users.read'])) { + $options['finder'] = 'foo'; + $options['user'] = $user; + } + return true; + } + + /** + * findFoo + * + * @param SelectQuery $query + * @param Array $options + * @return SelectQuery + */ + public function findFoo(SelectQuery $query, Array $params): SelectQuery + { + return $query->where(['Users.organisation_id is not null', 'Users.organisation_id' => $params['user']->organisation_id]); + } + + /** + * applySearchParams + * + * @param SelectQuery $query + * @param Array $params + * @return SelectQuery + */ + public function applySearchParams(SelectQuery $query, Array $params): SelectQuery + { + $search_params = [ + 'id' => 'Users.id', + 'name' => 'Users.name', + 'surname' => 'Users.surname', + 'organisation_description' => 'Actors.description', + ]; + + $searck_keys = array_keys($search_params); + + $search_conditions = collection($params) + ->filter(function ($paramValue, $paramKey) use ($searck_keys) { + return in_array($paramKey, $searck_keys); + }) + ->map(function ($paramValue, $paramKey) use ($search_params) { + return [$search_params[$paramKey] => $paramValue]; + }) + ->reduce(function ($acc, $search_condition) { + $acc[] = $search_condition; + return $acc; + }, []); + + if (!empty($search_conditions)) { + $query->where($search_conditions); + } + return $query; + } + + /** + * getAssociableUserGroups + * + * returns the groups that the user can associate to himself or to others + * + * @param Bool $as_list + * @return SelectQuery + */ + public function getAssociableUserGroups(Bool $as_list = false): SelectQuery + { + $finder = $as_list ? 'list' : 'all'; + $groups = TableRegistry::getTableLocator()->get('Groups')->find($finder)->contain(['Actors']); + + $user = Router::getRequest()->getAttribute('identity'); + if (!$user) return $groups->where(['Groups.id < 0']); + + // se posso associare agli utenti qualunque profilo, restituisco la lista completa dei profili: + if ($user->sys_admin || $user->hasCapability(['configuration.users.profiles'])) return $groups; + + $associable_user_groups_ids = TableRegistry::getTableLocator()->get('Groups')->find() + ->contain(['Actors']) + ->select(['id']) + ->matching('ParentGroups.Users') + ->where(['Users.id' => $user->id]); + + return $groups->where(['Groups.id IN' => $associable_user_groups_ids]); + } + + + /** + * @param array $data + * @return User|false + */ + public function createCitizen(User $user, array $data): User|false + { + $this->getConnection()->begin(); + try { + $default_profile = $this->Groups->find() + ->contain(['Actors']) + // prendiamo il profilo con group_code 1 (valore univoco per il profilo cittadini) + ->where(['Groups.group_code' => 'citizen_group']) + ->first(); + $user['groups'] = [$default_profile]; + // Prendo l'organizzazione di default per i cittadini + $defaultCitizenOrg = $this->Organisations->find()->where(['organisation_type_id' => 7])->first(); + if (!isset($defaultCitizenOrg)) { + throw new InvalidArgumentException('Organizzazione di default per cittadini non trovata'); + } + + $data['is_verified'] = 0; + $data['is_citizen'] = 1; + $data['organisation_id'] = $defaultCitizenOrg->id; + $password = $data['password']; + $confirmPassword = $data['confirmPassword']; + + // inserisco controllo su password e confirmPassword; + if ($password !== $confirmPassword) { + $user->setError('password', __('Le password non corrispondono')); + $user->setError('confirmPassword', __('Le password non corrispondono')); + throw new InvalidArgumentException('Le password non corrispondono'); + } + + $user = $this->patchEntity($user, $data, ['skipCitizenOrg' => true]); + // genro un random_bytes in formato stringa da 32char cosi da garantirne l'univocità. + $user->email_verification_code = bin2hex(random_bytes(16)); + + if (!$this->save($user)) { + throw new RuntimeException('Errore durante il salvataggio di User: ' . json_encode($user->getErrors())); + } + + $emailData = [ + 'value' => $data['email'], + 'email_description_id' => '2', + 'enable_notifications' => '1', + 'delivery' => [ + 'actor_id' => $user->actor_id, + 'delivery_type_id' => 3, + ] + ]; + $email = $this->Actors->Deliveries->Emails->newEntity($emailData); + if (!$this->Actors->Deliveries->Emails->save($email)) { + if ($email->hasErrors() && isset($email->getErrors()['value']['_isUnique'])) { + $user->setError('email', __('Questo indirizzo email è già in uso.')); + } + throw new RuntimeException('Errore durante il salvataggio di Emails: ' . json_encode($email->getErrors())); + } + $this->getConnection()->commit(); + return $user; + } catch (InvalidArgumentException $e) { + $this->getConnection()->rollback(); + Log::error("Argument error: " . $e->getMessage()); + return false; + } catch (RuntimeException $e) { + $this->getConnection()->rollback(); + Log::error("Runtime error: " . $e->getMessage()); + return false; + } + } + + /** + * @param string $emailVerificationCode + * @return User|bool + */ + public function verifyCitizen(string $emailVerificationCode): User|bool + { + $user = $this->find(contain: ['Actors'])->where(['email_verification_code' => $emailVerificationCode, 'is_verified' => 0])->first(); + if (!$user) { + return false; + } + $user = $this->patchEntity($user, ['is_verified' => 1, 'email_verification_code' => null], ['validate' => false, 'skipCitizenOrg' => true]); + return $this->save($user); + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestStatusesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestStatusesTable.php new file mode 100644 index 0000000..48f7c41 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestStatusesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_antimafia_certification_request_statuses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingAntimafiaCertificationRequests', [ + 'foreignKey' => 'water_drawing_antimafia_certification_request_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestsTable.php new file mode 100644 index 0000000..fb5900d --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingAntimafiaCertificationRequestsTable.php @@ -0,0 +1,107 @@ +setTable('water_drawing_antimafia_certification_requests'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingAntimafiaCertificationRequestStatuses', [ + 'foreignKey' => 'water_drawing_antimafia_certification_request_status_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_paperwork_id') + ->requirePresence('water_drawing_paperwork_id', 'create') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + $validator + ->integer('water_drawing_antimafia_certification_request_status_id') + ->requirePresence('water_drawing_antimafia_certification_request_status_id', 'create') + ->notEmptyString('water_drawing_antimafia_certification_request_status_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('water_drawing_antimafia_certification_request_status_id', 'WaterDrawingAntimafiaCertificationRequestStatuses'), ['errorField' => 'water_drawing_antimafia_certification_request_status_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingArticlesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingArticlesTable.php new file mode 100644 index 0000000..e14b579 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingArticlesTable.php @@ -0,0 +1,76 @@ +setTable('water_drawing_articles'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_articles_id', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + $validator + ->scalar('long_description') + ->maxLength('long_description', 255) + ->allowEmptyString('long_description'); + + $validator + ->boolean('disable') + ->allowEmptyString('disable'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingDerivationTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingDerivationTypesTable.php new file mode 100644 index 0000000..fa5d615 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingDerivationTypesTable.php @@ -0,0 +1,66 @@ +setTable('water_drawing_derivation_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingDerivations', [ + 'foreignKey' => 'water_drawing_derivation_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('description') + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingDerivationsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingDerivationsTable.php new file mode 100644 index 0000000..c153d3f --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingDerivationsTable.php @@ -0,0 +1,206 @@ +setTable('water_drawing_derivations'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingDerivationTypes', [ + 'foreignKey' => 'water_drawing_derivation_type_id', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->allowEmptyString('description'); + + $validator + ->scalar('water_body') + ->maxLength('water_body', 255) + ->allowEmptyString('water_body'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->allowEmptyString('district'); + + $validator + ->scalar('cadastral_code') + ->maxLength('cadastral_code', 255) + ->allowEmptyString('cadastral_code'); + + $validator + ->scalar('location') + ->maxLength('location', 255) + ->allowEmptyString('location'); + + $validator + ->integer('cadastral_sheet') + ->allowEmptyString('cadastral_sheet'); + + $validator + ->integer('cadastral_parcel') + ->allowEmptyString('cadastral_parcel'); + + $validator + ->scalar('latitude') + ->maxLength('latitude', 255) + ->allowEmptyString('latitude'); + + $validator + ->scalar('longitude') + ->maxLength('longitude', 255) + ->allowEmptyString('longitude'); + + $validator + ->scalar('istat') + ->maxLength('istat', 255) + ->allowEmptyString('istat'); + + $validator + ->scalar('derivation_status') + ->maxLength('derivation_status', 255) + ->allowEmptyString('derivation_status'); + + $validator + ->integer('withdrawals_amount') + ->allowEmptyString('withdrawals_amount'); + + $validator + ->numeric('annual_volume') + ->allowEmptyString('annual_volume'); + + $validator + ->numeric('average_flow_rate') + ->allowEmptyString('average_flow_rate'); + + $validator + ->integer('water_drawing_derivation_use_id') + ->allowEmptyString('water_drawing_derivation_use_id'); + + $validator + ->integer('water_drawing_derivation_type_id') + ->allowEmptyString('water_drawing_derivation_type_id'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_derivation_type_id', 'WaterDrawingDerivationTypes'), ['errorField' => 'water_drawing_derivation_type_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add(function ($entity, $options){ + if(isset($entity->cadastral_code, $entity->cadastral_sheet, $entity->cadastral_parcel) && !(empty($entity->latitude) && empty($entity->longitude))){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + if(isset($coordinates)){ + return GeoValidation::checkCadastralCoordinates($entity->latitude, $entity->longitude, strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + } + } + return true; + }, ['errorField' => 'latitude', 'message' => __('Le coordinate non ricadono all\'interno della particella selezionata.')]); + $rules->add(function ($entity, $options){ + if(isset($entity->cadastral_code, $entity->cadastral_sheet, $entity->cadastral_parcel) && !(empty($entity->latitude) && empty($entity->longitude))){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + if(isset($coordinates)){ + return GeoValidation::checkCadastralCoordinates($entity->latitude, $entity->longitude, strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + } + } + return true; + }, ['errorField' => 'longitude', 'message' => __('Le coordinate non ricadono all\'interno della particella selezionata.')]); + + return $rules; + } + + public function beforeSave(EventInterface $event, EntityInterface $entity, \ArrayObject $options){ + if(isset($entity->cadastral_code, $entity->cadastral_sheet, $entity->cadastral_parcel) && (empty($entity->latitude) && empty($entity->longitude))){ + $coordinates = CadastralUtils::getParcelCentroidCoordinates(strtolower($entity->cadastral_code), (string) $entity->cadastral_sheet, (string) $entity->cadastral_parcel); + if(isset($coordinates)){ + $entity->latitude = $coordinates->latitude; + $entity->longitude = $coordinates->longitude; + $entity->feature_collection = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":['. $coordinates->longitude .','. $coordinates->latitude .']},"properties":null}]}'; + } + } + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare il punto di prelievo/derivazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geom'] = $data['feature_collection']; + } + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingFeesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingFeesTable.php new file mode 100644 index 0000000..bf7fa0a --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingFeesTable.php @@ -0,0 +1,124 @@ +setTable('water_drawing_fees'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('WaterDrawingPayments', [ + 'foreignKey' => 'water_drawing_fee_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->numeric('amount') + ->allowEmptyString('amount'); + + $validator + ->integer('year') + ->requirePresence('year', 'create') + ->notEmptyString('year'); + + $validator + ->integer('water_drawing_paperwork_id') + ->requirePresence('water_drawing_paperwork_id', 'create') + ->notEmptyString('water_drawing_paperwork_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->isUnique(['year', 'water_drawing_paperwork_id'], 'WaterDrawingPaperworks'), ['errorField' => 'year', 'message' => 'Il canone per l\'anno scelto è già impostato.']); + $rules->add(function($entity, $options) { + $waterDrawingPaperworks = $this->WaterDrawingPaperworks->find()->where(["id" => $entity->water_drawing_paperwork_id])->first(); + $releaseDate = $waterDrawingPaperworks?->release_date?->year; + $expirationDate = $waterDrawingPaperworks?->expiration_date?->year; + + // se non ho entrambe le date skippo i controlli. + if(!isset($releaseDate) && !isset($expirationDate)){ + return true; + } + + // se ho solo la data di scadenza ma non ho la data di rilascio controllo solo la data di scadenza rispetto al canone. + if(!isset($releaseDate) && isset($expirationDate)) { + return $entity->year <= $expirationDate; + } + + // se ho solo la data di rilascio ma non ho la data di scadenza, controllo solo la data di rilascio rispetto al canone. + if(isset($releaseDate) && !isset($expirationDate)) { + return $entity->year >= $releaseDate; + } + + // in questo caso sono sicuro che ho sia la data di rilascio che di scadenza + // in questo caso specifico controllo che le date siano comprese tra la data di rilascio e la data di scadenza. + return ($entity->year >= $releaseDate) && ($entity->year <= $expirationDate); + }, "yearValidation", ['errorField' => 'year', 'message' => 'Il canone annuale deve essere compreso tra la data di rilascio del provvedimento e la data di scadenza del provvedimento.']); + + return $rules; + } + + public function beforeFind($event, $query, $options, $primary){ + $query->order(['WaterDrawingFees.year' => 'DESC']); + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingIntendedUseTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUseTypesTable.php new file mode 100644 index 0000000..f024129 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUseTypesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_intended_use_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_intended_use_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingIntendedUsesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUsesTable.php new file mode 100644 index 0000000..d78d20e --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingIntendedUsesTable.php @@ -0,0 +1,147 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\WaterDrawingIntendedUse findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\WaterDrawingIntendedUse> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\WaterDrawingIntendedUse saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingIntendedUse>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingIntendedUse> deleteManyOrFail(iterable $entities, array $options = []) + */ +class WaterDrawingIntendedUsesTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('water_drawing_intended_uses'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingIntendedUseTypes', [ + 'foreignKey' => 'water_drawing_intended_use_type_id', + ]); + $this->belongsTo('WaterDrawingWateringSystems', [ + 'foreignKey' => 'water_drawing_watering_system_id', + ]); + $this->belongsToMany('CadastralCropTypes', [ + 'foreignKey' => 'water_drawing_intended_use_id', + 'targetForeignKey' => 'cadastral_crop_type_id', + 'joinTable' => 'cadastral_crop_types_water_drawing_intended_uses', + ]); + $this->hasMany('WaterDrawingMeters', [ + 'foreignKey' => 'water_drawing_intended_use_id', + ]); + + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('area') + ->maxLength('area', 255) + ->allowEmptyString('area'); + + $validator + ->scalar('cadastral_code') + ->maxLength('cadastral_code', 255) + ->allowEmptyString('cadastral_code'); + + $validator + ->scalar('cadastral_sheet') + ->maxLength('cadastral_sheet', 255) + ->allowEmptyString('cadastral_sheet'); + + $validator + ->scalar('cadastral_parcel') + ->maxLength('cadastral_parcel', 255) + ->allowEmptyString('cadastral_parcel'); + + $validator + ->scalar('consortium_area') + ->maxLength('consortium_area', 255) + ->allowEmptyString('consortium_area'); + + $validator + ->scalar('rated_power_produced') + ->maxLength('rated_power_produced', 255) + ->allowEmptyString('rated_power_produced'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->integer('water_drawing_intended_use_type_id') + ->allowEmptyString('water_drawing_intended_use_type_id'); + + $validator + ->integer('vegetation_match_status') + ->notEmptyString('vegetation_match_status'); + + $validator + ->integer('water_drawing_watering_system_id') + ->allowEmptyString('water_drawing_watering_system_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn(['water_drawing_paperwork_id'], 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn(['water_drawing_intended_use_type_id'], 'WaterDrawingIntendedUseTypes'), ['errorField' => 'water_drawing_intended_use_type_id']); + $rules->add($rules->existsIn(['water_drawing_watering_system_id'], 'WaterDrawingWateringSystems'), ['errorField' => 'water_drawing_watering_system_id']); + + return $rules; + } + + public function beforeSave(EventInterface $event, EntityInterface $entity, \ArrayObject $options) + { + if (empty($options["skipResetIsMismatch"]) || !$options["skipResetIsMismatch"]) $entity->vegetation_match_status = 0; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingMeasurementsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingMeasurementsTable.php new file mode 100644 index 0000000..5eb5b1a --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingMeasurementsTable.php @@ -0,0 +1,108 @@ +setTable('water_drawing_measurements'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingMeters', [ + 'foreignKey' => 'water_drawing_meter_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->numeric('volume') + ->requirePresence('volume', 'create') + ->notEmptyString('volume'); + + $validator + ->date('date') + ->requirePresence('date', 'create') + ->notEmptyDate('date'); + + $validator + ->integer('water_drawing_meter_id') + ->requirePresence('water_drawing_meter_id', 'create') + ->notEmptyString('water_drawing_meter_id'); + + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_meter_id', 'WaterDrawingMeters'), ['errorField' => 'water_drawing_meter_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + + $rules->add(function($entity, $option) { + $waterDrawingMeeter = $this->WaterDrawingMeters->find()->where(['id' => $entity->water_drawing_meter_id])->first(); + // controlliamo che la data di misurazione sia successiva o uguale alla data di installazione dello strumento di misurazione + return $entity->date->greaterThanOrEquals($waterDrawingMeeter?->installation_date); + }, "checkMeasurementDate", ["errorField" => "date", "message" => "La data di misurazione non può essere antecedente all'installazione dello strumento di misurazione."]); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingMetersTable.php b/idrocap_wa/src/Model/Table/WaterDrawingMetersTable.php new file mode 100644 index 0000000..d6a2252 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingMetersTable.php @@ -0,0 +1,118 @@ +setTable('water_drawing_meters'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingToolTypes', [ + 'foreignKey' => 'water_drawing_tool_type_id', + 'joinType' => 'INNER', + ]); + + $this->belongsTo('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_intended_use_id', + 'joinType' => 'INNER', + ]); + $this->hasMany('WaterDrawingMeasurements', [ + 'foreignKey' => 'water_drawing_meter_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_tool_type_id') + ->requirePresence('water_drawing_tool_type_id', 'create') + ->notEmptyString('water_drawing_tool_type_id'); + + $validator + ->integer('water_drawing_intended_use_id') + ->requirePresence('water_drawing_intended_use_id', 'create') + ->notEmptyString('water_drawing_intended_use_id'); + + $validator + ->scalar('manufacturer') + ->maxLength('manufacturer', 255) + ->requirePresence('manufacturer', 'create') + ->allowEmptyString('manufacturer'); + + $validator + ->scalar('part_number') + ->maxLength('part_number', 255) + ->requirePresence('part_number', 'create') + ->notEmptyString('part_number'); + + $validator + ->date('installation_date') + ->requirePresence('installation_date', 'create') + ->allowEmptyDate('installation_date'); + + $validator + ->date('removal_date') + ->allowEmptyDate('removal_date', null, 'update'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_tool_type_id', 'WaterDrawingToolTypes'), ['errorField' => 'water_drawing_tool_type_id']); + $rules->add($rules->existsIn('water_drawing_intended_use_id', 'WaterDrawingIntendedUses'), ['errorField' => 'water_drawing_intended_use_id']); + + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworkHistoriesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkHistoriesTable.php new file mode 100644 index 0000000..511977a --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkHistoriesTable.php @@ -0,0 +1,170 @@ +setTable('water_drawing_paperwork_histories'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaperworkStatuses', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->boolean('result') + ->requirePresence('result', 'create') + ->notEmptyString('result'); + + $validator + ->scalar('note') + ->maxLength('note', 255) + ->allowEmptyString('note'); + + $validator + ->integer('user_id') + ->notEmptyString('user_id'); + + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->dateTime('deleted') + ->allowEmptyDateTime('deleted'); + + $validator + ->integer('water_drawing_paperwork_status_id') + ->requirePresence('water_drawing_paperwork_status_id', 'create') + ->notEmptyString('water_drawing_paperwork_status_id'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn('water_drawing_paperwork_status_id', 'WaterDrawingPaperworkStatuses'), ['errorField' => 'water_drawing_paperwork_status_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add(function ($entity){ + if($entity->result == 0) return ($entity->note != ""); + return true; + }, ['errorField' => 'note', 'message' => ' In caso di rifiuto bisogna inserire una nota.']); + return $rules; + } + + + public function beforeSave(EventInterface $event, WaterDrawingPaperworkHistory $entity, ArrayObject $options){ + $user = Router::getRequest()->getAttribute('identity'); + $entity->user_id = $user->id; + } + + public function afterSave(EventInterface $event, WaterDrawingPaperworkHistory $entity, ArrayObject $options){ + $waterDrawingPaperwork = $this->WaterDrawingPaperworks->find()->where(['WaterDrawingPaperworks.id' => $entity->water_drawing_paperwork_id])->first(); + if($waterDrawingPaperwork->scanned){ + if($entity->result == 1){ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $entity->water_drawing_paperwork_status_id == 3 ? 4 : 6; + }else{ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $entity->water_drawing_paperwork_status_id == 3 ? 2 : 4; + } + }else{ + if($entity->result == 1){ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $waterDrawingPaperwork->water_drawing_paperwork_status_id == 10 ? -1 : -4; + }else{ + $waterDrawingPaperwork->water_drawing_paperwork_status_id = $waterDrawingPaperwork->water_drawing_paperwork_status_id == 10 ? 11 : -1; + } + } + if(! $this->WaterDrawingPaperworks->save($waterDrawingPaperwork)){ + \Cake\Log\Log::write('debug', 'Errore durante il salvataggio della pratica. ' . json_encode($waterDrawingPaperwork->getErrors())); + } + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 10; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworkPecsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkPecsTable.php new file mode 100644 index 0000000..34eb10b --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkPecsTable.php @@ -0,0 +1,136 @@ +setTable('water_drawing_paperwork_pecs'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_paperwork_id') + ->notEmptyString('water_drawing_paperwork_id'); + + $validator + ->integer('user_id') + ->notEmptyString('user_id'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->scalar('document') + ->maxLength('document', 255) + ->requirePresence('document', 'create') + ->notEmptyString('document'); + + $validator + ->scalar('protocol_number') + ->maxLength('protocol_number', 255) + ->requirePresence('protocol_number', 'create') + ->notEmptyString('protocol_number'); + + $validator + ->date('protocol_date') + ->requirePresence('protocol_date', 'create') + ->notEmptyDate('protocol_date'); + + $validator + ->scalar('recipient') + ->maxLength('recipient', 255) + ->requirePresence('recipient', 'create') + ->notEmptyString('recipient'); + + $validator + ->scalar('sender') + ->maxLength('sender', 255) + ->requirePresence('sender', 'create') + ->notEmptyString('sender'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + + return $rules; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 11; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworkStatusesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkStatusesTable.php new file mode 100644 index 0000000..00c5a0d --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworkStatusesTable.php @@ -0,0 +1,70 @@ +setTable('water_drawing_paperwork_statuses'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + ]); + $this->hasMany('WaterDrawingPaperworkHistories', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaperworksTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaperworksTable.php new file mode 100644 index 0000000..4ae8cb2 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaperworksTable.php @@ -0,0 +1,383 @@ +setTable('water_drawing_paperworks'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworkStatuses', [ + 'foreignKey' => 'water_drawing_paperwork_status_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingArticles', [ + 'foreignKey' => 'water_drawing_article_id', + 'joinType' => 'LEFT', + ]); + $this->belongsTo('ControllableObjects', [ + 'foreignKey' => 'controllable_object_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('DrarUsers', [ + 'className' => 'Users', + 'foreignKey' => 'drar_user_id', + 'joinType' => 'LEFT', + ]); + $this->belongsTo('GcUsers', [ + 'className' => 'Users', + 'foreignKey' => 'gc_user_id', + 'joinType' => 'LEFT', + ]); + $this->hasMany('ApplicantsWaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingAntimafiaCertificationRequests', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingFees', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingPaperworkHistories', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'dependent' => true, + 'cascadeCallbacks' => true, + ]); + $this->hasMany('WaterDrawingDerivations', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingReturnPoints', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->hasMany('WaterDrawingPaperworkPecs', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + $this->belongsToMany('Applicants', [ + 'foreignKey' => 'water_drawing_paperwork_id', + 'targetForeignKey' => 'applicant_id', + 'joinTable' => 'applicants_water_drawing_paperworks', + 'dependent' => true, + 'cascadeCallbacks' => true, + 'sort' => ['is_primary_applicant' => 'DESC'], + ]); + + $this->addBehavior('Muffin/Trash.Trash'); + $this->addBehavior('Attachments', ['attachment' => ['required' => false, 'one_public' => false, 'protected' => false, 'accept_only' => ['.pdf']]]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_paperwork_status_id') + ->requirePresence('water_drawing_paperwork_status_id', 'create') + ->notEmptyString('water_drawing_paperwork_status_id'); + + $validator + ->date('from_date') + ->allowEmptyDate('from_date'); + + $validator + ->date('to_date') + ->allowEmptyDate('to_date'); + + $validator + ->scalar('gurs_reference') + ->maxLength('gurs_reference', 255) + ->allowEmptyString('gurs_reference'); + + $validator + ->scalar('authorisation_type') + ->maxLength('authorisation_type', 255) + ->allowEmptyString('authorisation_type'); + + $validator + ->scalar('concession_decree_number') + ->maxLength('concession_decree_number', 255) + ->allowEmptyString('concession_decree_number'); + + $validator + ->date('release_date') + ->allowEmptyDate('release_date'); + + $validator + ->integer('concession_duration') + ->allowEmptyString('concession_duration'); + + $validator + ->date('expiration_date') + ->allowEmptyDate('expiration_date'); + + $validator + ->scalar('first_istance') + ->maxLength('first_istance', 255) + ->allowEmptyString('first_istance'); + + $validator + ->scalar('takeover') + ->maxLength('takeover', 255) + ->allowEmptyString('takeover'); + + $validator + ->integer('year') + ->allowEmptyString('year'); + + $validator + ->scalar('fee_payment_certificate') + ->maxLength('fee_payment_certificate', 255) + ->allowEmptyString('fee_payment_certificate'); + + $validator + ->integer('initial_static_level_water') + ->allowEmptyString('initial_static_level_water'); + + $validator + ->date('initial_static_level_water_date') + ->allowEmptyDate('initial_static_level_water_date'); + + $validator + ->integer('static_level_water') + ->allowEmptyString('static_level_water'); + + $validator + ->date('static_level_water_date') + ->allowEmptyDate('static_level_water_date'); + + $validator + ->scalar('authority_province') + ->maxLength('authority_province', 255) + ->allowEmptyString('authority_province'); + + $validator + ->scalar('authority_identification_code_civil_engineering_office') + ->maxLength('authority_identification_code_civil_engineering_office', 255) + ->allowEmptyString('authority_identification_code_civil_engineering_office'); + + $validator + ->scalar('authority_identification_code_derivation_department_water_waste') + ->maxLength('authority_identification_code_derivation_department_water_waste', 255) + ->allowEmptyString('authority_identification_code_derivation_department_water_waste'); + + $validator + ->integer('controllable_object_id') + ->notEmptyString('controllable_object_id'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('protocol_number') + ->maxLength('protocol_number', 255) + ->allowEmptyString('protocol_number'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_status_id', 'WaterDrawingPaperworkStatuses'), ['errorField' => 'water_drawing_paperwork_status_id']); + $rules->add($rules->existsIn('controllable_object_id', 'ControllableObjects'), ['errorField' => 'controllable_object_id']); + $rules->add($rules->existsIn('drar_user_id', 'DrarUsers'), ['errorField' => 'drar_user_id']); + $rules->add($rules->existsIn('gc_user_id', 'GcUsers'), ['errorField' => 'gc_user_id']); + $rules->add($rules->isUnique(['authority_identification_code_civil_engineering_office', 'deleted']), ['errorField' => 'authority_identification_code_civil_engineering_office', 'message' => __('Codice identificativo Concessione Ufficio Genio civile esistente.')]); + //controllo sul codice identificativo della pratica GC + /*$rules->add(function ($entity, $options){ + if($entity->authority_identification_code_civil_engineering_office == ''){ + return true; + } + return preg_match("/^[a-zA-Z]{2}[0-9]{4}$/", $entity->authority_identification_code_civil_engineering_office) == 1; + }, + 'authority_identification_code_civil_engineering_office', + [ + 'errorField' => 'authority_identification_code_civil_engineering_office', + 'message' => __('Formato del codice errato. Rispettare il seguente formato AA0000.') + ]);*/ + $rules->add(function ($entity, $options){ + if($entity->authority_identification_code_derivation_department_water_waste == ''){ + return true; + } + return (preg_match("/^[a-zA-Z]{2}[0-9]{4}$/", $entity->authority_identification_code_derivation_department_water_waste) == 1); + }, + 'authority_identification_code_derivation_department_water_waste', + [ + 'errorField' => 'authority_identification_code_derivation_department_water_waste', + 'message' => __('Formato del codice errato. Rispettare il seguente formato AA0000.') + ]); + + $rules->add(function ($entity, $options) { + $countiesTable = $this->fetchTable("Counties"); + if (!empty($entity->authority_province)) { + $provinceField = strlen($entity->authority_province) === 2 ? 'sigla' : 'den_uts'; + $exists = $countiesTable->exists([$provinceField => $entity->authority_province]); + if (!$exists) { + return false; + } + } + + return true; + }, 'validProvince', [ + 'errorField' => 'authority_province', + 'message' => 'La provincia selezionata non è valida.' + ]); + + return $rules; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + $data['controllable_object']['controllable_object_type_id'] = 9; + + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare il punto di prelievo/derivazione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geom'] = $data['feature_collection']; + } + } + + public function afterSave(EventInterface $event, EntityInterface $entity, \ArrayObject $options){ + $data = (object)[]; + $data->water_drawing_paperwork_id = $entity->id; + $logged_user = Router::getRequest()->getAttribute('identity'); + if ($logged_user) $data->notification_user_id = $logged_user->id; + IntendedUseVegetationCheckCommandSender::sendMessage($data); + } + + /** + * checkAttachments + * + * @param Array $attachments_data + * @return Array + */ + public function checkAttachments($data) { + $files = 0; + $error_message = []; + if(!isset($data['authority_identification_code_civil_engineering_office']) || $data['authority_identification_code_civil_engineering_office'] == '') return [ __('Il codice della pratica da parte del genio civile non è impostato.')]; + foreach($data['attachments'] as $key => $attachments){ + foreach($attachments as $attachment_obj){ + $attachment = AttachmentConverter::convertUploadedFileObj2AssociativeArray($attachment_obj); + if($attachment['error'] == 0){ + $files++; + switch($key){ + case 'DV': + $supposedFileName = $data['authority_identification_code_civil_engineering_office'] . '.pdf'; + break; + case 'DUEA': + $supposedFileName = $data['authority_identification_code_civil_engineering_office'] . '_2A.pdf'; + break; + default: + $supposedFileName = $data['authority_identification_code_civil_engineering_office'] . '_' . $key . '.pdf'; + } + + if(strtoupper($supposedFileName) != strtoupper($attachment['name'])) $error_message[] = __('Il file "{0}", nella sezione {1}, non ha il nome del file corretto. Il nome corretto dell\'allegato è "{2}". ', $attachment['name'], $key, $supposedFileName); + } + } + } + if($files == 0) $error_message[] = __('Non hai inserito il numero di file necessari.'); + return $error_message; + } + + public function can_index(User $user, Array &$options): Bool + { + if (!$user->hasCapability(['documentation.water_drawing_paperworks.view', 'documentation.water_drawing_paperworks.view_own_province'])) { + $options['error']['capabilities'] = ['documentation.water_drawing_paperworks.view']; + return false; + } + return true; + } + + public function applySearchParams(Query $query, Array $params): Query + { + $search_params = [ + 'cod' => 'WaterDrawingPaperworks.authority_identification_code_civil_engineering_office', + 'cod_drar' => 'WaterDrawingPaperworks.authority_identification_code_derivation_department_water_waste', + 'province' => 'WaterDrawingPaperworks.authority_province', + 'surname' => 'Applicants.surname' + ]; + + $searck_keys = array_keys($search_params); + + $search_conditions = collection($params) + ->filter(function ($paramValue, $paramKey) use ($searck_keys) { + return in_array($paramKey, $searck_keys); + }) + ->map(function ($paramValue, $paramKey) use ($search_params) { + return [$search_params[$paramKey] => $paramValue]; + }) + ->reduce(function ($acc, $search_condition) { + $acc[] = $search_condition; + return $acc; + }, []); + + if (!empty($search_conditions)) { + $query->where($search_conditions); + } + return $query; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaymentTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaymentTypesTable.php new file mode 100644 index 0000000..2d48ca4 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaymentTypesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_payment_types'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingPayments', [ + 'foreignKey' => 'water_drawing_payment_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingPaymentsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingPaymentsTable.php new file mode 100644 index 0000000..0645ea6 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingPaymentsTable.php @@ -0,0 +1,149 @@ +setTable('water_drawing_payments'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->addBehavior('Timestamp'); + + $this->belongsTo('WaterDrawingFees', [ + 'foreignKey' => 'water_drawing_fee_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('WaterDrawingPaymentTypes', [ + 'foreignKey' => 'water_drawing_payment_type_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Users', [ + 'foreignKey' => 'user_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->integer('water_drawing_fee_id') + ->requirePresence('water_drawing_fee_id', 'create') + ->notEmptyString('water_drawing_fee_id'); + + $validator + ->integer('water_drawing_payment_type_id') + ->requirePresence('water_drawing_payment_type_id', 'create') + ->notEmptyString('water_drawing_payment_type_id'); + + $validator + ->integer('user_id') + ->requirePresence('user_id', 'create') + ->notEmptyString('user_id'); + + $validator + ->numeric('amount') + ->requirePresence('amount', 'create') + ->notEmptyString('amount'); + + $validator + ->date('payment_date') + ->requirePresence('payment_date', 'create') + ->notEmptyString('payment_date'); + + $validator + ->scalar('payment_number') + ->maxLength('payment_number', 255) + ->requirePresence('payment_number', 'create') + ->notEmptyString('payment_number'); + + $validator + ->scalar('notes') + ->maxLength('notes', 4294967295) + ->allowEmptyString('notes'); + + $validator + ->numeric('receipt_amount') + ->allowEmptyString('receipt_amount'); + + $validator + ->date('receipt_date') + ->allowEmptyString('receipt_date'); + + $validator + ->scalar('receipt_number') + ->maxLength('receipt_number', 255) + ->allowEmptyString('receipt_number'); + + $validator + ->scalar('applicant_tax_code') + ->maxLength('applicant_tax_code', 4294967295) + ->allowEmptyString('applicant_tax_code'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_fee_id', 'WaterDrawingFees'), ['errorField' => 'water_drawing_fee_id']); + $rules->add($rules->existsIn('water_drawing_payment_type_id', 'WaterDrawingPaymentTypes'), ['errorField' => 'water_drawing_payment_type_id']); + $rules->add($rules->existsIn('user_id', 'Users'), ['errorField' => 'user_id']); + $rules->add(function ($entity, $options){ + if(!isset($entity->receipt_date)) return true; + return ($entity->payment_date <= $entity->receipt_date); + }, ['errorField' => 'receipt_date', 'message' => __('La data di quietanza non può essere antecedente alla data di pagamento.')]); + return $rules; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingReturnPointsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingReturnPointsTable.php new file mode 100644 index 0000000..680bdd7 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingReturnPointsTable.php @@ -0,0 +1,120 @@ +setTable('water_drawing_return_points'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('WaterDrawingPaperworks', [ + 'foreignKey' => 'water_drawing_paperwork_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('latitude') + ->maxLength('latitude', 255) + ->allowEmptyString('latitude'); + + $validator + ->scalar('longitude') + ->maxLength('longitude', 255) + ->allowEmptyString('longitude'); + + $validator + ->scalar('feature_collection') + ->maxLength('feature_collection', 4294967295) + ->allowEmptyString('feature_collection'); + + $validator + ->scalar('district') + ->maxLength('district', 255) + ->allowEmptyString('district'); + + $validator + ->integer('cadastral_sheet') + ->allowEmptyString('cadastral_sheet'); + + $validator + ->integer('cadastral_parcel') + ->allowEmptyString('cadastral_parcel'); + + $validator + ->integer('water_drawing_paperwork_id') + ->allowEmptyString('water_drawing_paperwork_id'); + + return $validator; + } + + /** + * Returns a rules checker object that will be used for validating + * application integrity. + * + * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. + * @return \Cake\ORM\RulesChecker + */ + public function buildRules(RulesChecker $rules): RulesChecker + { + $rules->add($rules->existsIn('water_drawing_paperwork_id', 'WaterDrawingPaperworks'), ['errorField' => 'water_drawing_paperwork_id']); + + return $rules; + } + + public function beforeMarshal(EventInterface $event, \ArrayObject $data, \ArrayObject $options) + { + if (isset($data['feature_collection']) && json_decode($data['feature_collection']) !== null) { + if (!GeoValidation::isValidGeometry(json_decode($data['feature_collection']))) { + throw new BadRequestException(__('Le geometrie inserite per georeferenziare il punto di restituzione, non risultano valide. Controllare che siano espresse nel corretto formato (WGS84) e che rientrano nell\'area di competenza della piattaforma.')); + } + $data['geom'] = $data['feature_collection']; + } + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingToolTypesTable.php b/idrocap_wa/src/Model/Table/WaterDrawingToolTypesTable.php new file mode 100644 index 0000000..0a11497 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingToolTypesTable.php @@ -0,0 +1,67 @@ +setTable('water_drawing_tool_types'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingMeters', [ + 'foreignKey' => 'water_drawing_tool_type_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/Model/Table/WaterDrawingWateringSystemsTable.php b/idrocap_wa/src/Model/Table/WaterDrawingWateringSystemsTable.php new file mode 100644 index 0000000..b51d036 --- /dev/null +++ b/idrocap_wa/src/Model/Table/WaterDrawingWateringSystemsTable.php @@ -0,0 +1,67 @@ + newEntities(array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem get(mixed $primaryKey, array|string $finder = 'all', \Psr\SimpleCache\CacheInterface|string|null $cache = null, \Closure|string|null $cacheKey = null, mixed ...$args) + * @method \App\Model\Entity\WaterDrawingWateringSystem findOrCreate($search, ?callable $callback = null, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = []) + * @method array<\App\Model\Entity\WaterDrawingWateringSystem> patchEntities(iterable $entities, array $data, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem|false save(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method \App\Model\Entity\WaterDrawingWateringSystem saveOrFail(\Cake\Datasource\EntityInterface $entity, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem>|false saveMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem> saveManyOrFail(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem>|false deleteMany(iterable $entities, array $options = []) + * @method iterable<\App\Model\Entity\WaterDrawingWateringSystem>|\Cake\Datasource\ResultSetInterface<\App\Model\Entity\WaterDrawingWateringSystem> deleteManyOrFail(iterable $entities, array $options = []) + */ +class WaterDrawingWateringSystemsTable extends Table +{ + /** + * Initialize method + * + * @param array $config The configuration for the Table. + * @return void + */ + public function initialize(array $config): void + { + parent::initialize($config); + + $this->setTable('water_drawing_watering_systems'); + $this->setDisplayField('description'); + $this->setPrimaryKey('id'); + + $this->hasMany('WaterDrawingIntendedUses', [ + 'foreignKey' => 'water_drawing_watering_system_id', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator): Validator + { + $validator + ->scalar('description') + ->maxLength('description', 255) + ->requirePresence('description', 'create') + ->notEmptyString('description'); + + return $validator; + } +} diff --git a/idrocap_wa/src/View/AjaxView.php b/idrocap_wa/src/View/AjaxView.php new file mode 100644 index 0000000..dd9d7d9 --- /dev/null +++ b/idrocap_wa/src/View/AjaxView.php @@ -0,0 +1,46 @@ +response = $this->response->withType('ajax'); + } +} diff --git a/idrocap_wa/src/View/AppView.php b/idrocap_wa/src/View/AppView.php new file mode 100644 index 0000000..a4e335a --- /dev/null +++ b/idrocap_wa/src/View/AppView.php @@ -0,0 +1,52 @@ +addHelper('Html');` + * + * @return void + */ + public function initialize(): void + { + parent::initialize(); + $this->initializeCakeLte(); + $this->addHelper('Sections'); + $this->addHelper('Menu'); + $this->addHelper('Breadcrumb'); + $this->addHelper('Notifications'); + } +} diff --git a/idrocap_wa/src/View/Cell/.gitkeep b/idrocap_wa/src/View/Cell/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/src/View/Cell/DistrictProvinceCell.php b/idrocap_wa/src/View/Cell/DistrictProvinceCell.php new file mode 100644 index 0000000..9061ec6 --- /dev/null +++ b/idrocap_wa/src/View/Cell/DistrictProvinceCell.php @@ -0,0 +1,68 @@ +autoFillTargetEnabled) && $provinceCellConfig->autoFillTargetEnabled && empty($provinceCellConfig?->autoFillTargetId); + if ($autoFillIsMisconfigured) { + throw new Exception("autoFillTargetId must be set when autoFillTargetEnabled is true"); + } + + $viewVars = []; + + /** + * Controllo che in mapConfig abbiamo un array di codeReg e che la specifica region + * sia effettivamente presente. + */ + $codeReg = ProvinceDistrictFieldHelper::getCodeRegByRegion(Regions::SICILY); + $viewVars["codReg"] = $codeReg; + + if ($provinceCellConfig) { + $viewVars["provinces"] = $this->fetchTable('Counties')->getCountiesByRegion($codeReg, $provinceCellConfig); + $viewVars["provinceCellConfig"] = $provinceCellConfig; + } + + if ($districtCellConfig) { + $viewVars["codReg"] = $codeReg; + $viewVars["districtCellConfig"] = $districtCellConfig; + } + + $this->set($viewVars); + } +} diff --git a/idrocap_wa/src/View/Cell/FilterInputCell.php b/idrocap_wa/src/View/Cell/FilterInputCell.php new file mode 100644 index 0000000..d662de2 --- /dev/null +++ b/idrocap_wa/src/View/Cell/FilterInputCell.php @@ -0,0 +1,51 @@ +Cell('FilterInput', [ + * filter_id, // Int -> id fel filtro da recuperare in table filters + * value, // ?Any -> il valore impostato dall'utente per il tipo di filtro + * ]); + */ +class FilterInputCell extends Cell +{ + protected array $_validCellOptions = []; + + /** + * display + * + * @param Int $filter_id + * @param ?String $value + * @return void + */ + public function display(Int $filter_id, ?String $value = null) + { + $filter = $this->fetchTable('Filters')->get($filter_id); + + if ($filter->filter_type == 'class') { + $table_name = $this->fetchTable($filter->class_name)->getAlias(); + $display_field = $this->fetchTable($filter->class_name)->getDisplayField(); + $order_clause = json_decode($filter->order_clause ?? '', true) ?? ["$table_name.$display_field" => 'ASC']; + $options = $this->fetchTable($filter->class_name)->find('list')->order($order_clause); + } + + if ($filter->filter_type == 'bool') { + $options = [0 => __('NO'), 1 => __('SI')]; + } + + $this->set('label', $filter->description); + $this->set('name', 'filter_id_' . $filter->id); + $this->set('type', in_array($filter->filter_type, ['class', 'bool']) ? 'select' : 'text'); + $this->set('additional_classes', $filter->filter_type == 'date' ? ' jixeldaterangepicker' : ''); + $this->set('options', $options ?? null); + $this->set('value', $value ?? null); + } +} diff --git a/idrocap_wa/src/View/Cell/FiltersCell.php b/idrocap_wa/src/View/Cell/FiltersCell.php new file mode 100755 index 0000000..d225eb9 --- /dev/null +++ b/idrocap_wa/src/View/Cell/FiltersCell.php @@ -0,0 +1,50 @@ +Cell('Filters', [ + * header_title, // String -> titolo da visualizzare nell'header del collapsable + * ]); + * + */ +class FiltersCell extends Cell +{ + protected array $_validCellOptions = []; + + /** + * display + * + * @param String $header_title + * @return void + */ + public function display(String $header_title) + { + $logged_user = Router::getRequest()->getAttribute('identity'); + $logged_user_id = $logged_user->id ?? 0; + $controller = Router::getRequest()->getParam('controller'); + $action = Router::getRequest()->getParam('action'); + $controller_action_category = "$controller-$action"; + $filter_session_key = "filters-$logged_user_id-$controller-$action"; + $filters = Router::getRequest()->getSession()->read($filter_session_key); + + $available_filters = $this->fetchTable('Filters')->find('list') + ->where(['Filters.controller_action_category' => $controller_action_category]) + ->order(['Filters.order_number' => 'ASC']); + + if (!$logged_user->sys_admin) { + $available_filters = $available_filters->where(['Filters.sys_admin_only' => false]); + } + + $this->set('filters', $filters ?? []); + $this->set('available_filters', $available_filters); + $this->set('header_title', $header_title); + } +} diff --git a/idrocap_wa/src/View/Cell/IntendedUsesCell.php b/idrocap_wa/src/View/Cell/IntendedUsesCell.php new file mode 100644 index 0000000..5569264 --- /dev/null +++ b/idrocap_wa/src/View/Cell/IntendedUsesCell.php @@ -0,0 +1,33 @@ +getTableLocator()->get('WaterDrawingIntendedUseTypes')->find()->all()->combine('id', 'description')->toArray(); + $cadastralCropTypes = $this->getTableLocator()->get('CadastralCropTypes')->find()->all()->combine('id', 'description')->toArray(); + $wateringSystems = $this->getTableLocator()->get('WaterDrawingWateringSystems')->find()->all()->combine('id', 'description')->toArray(); + $this->set(compact('intended_use_item_block', 'intendedUseTypes', 'cadastralCropTypes', 'wateringSystems')); + } +} diff --git a/idrocap_wa/src/View/Cell/MapCell.php b/idrocap_wa/src/View/Cell/MapCell.php new file mode 100755 index 0000000..aa629ee --- /dev/null +++ b/idrocap_wa/src/View/Cell/MapCell.php @@ -0,0 +1,234 @@ +Cell('Map', [ + [-1], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Evento'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => true, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'feature_collection' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'feature-collection-custom1', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'feature_collection_custom1', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Collezione di geometrie'), + ], + 'longitude' => [ // Array = null -> null/[] = il campo longitude non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude-custom2', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude_custom2', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Longitudine'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo latitude non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude-custom3', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude_custom3', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Latitudine'), + ], + 'coordinates' => [ // Array = null -> null/[] = il campo coordinates non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'coordinates-custom4', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'coordinates_custom4', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinate (Longitudine Latitudine)'), + ], + 'cap' => [ // Array = null -> null/[] = il campo cap non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'cap', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'cap', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Cap'), + ], + 'province' => [ // Array = null -> null/[] = il campo province non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'province', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'province', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Provincia'), + ], + 'district_code' => [ // Array = null -> null/[] = il campo district_code non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district-code', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district_code', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Codice ISTAT'), + ], + 'district' => [ // Array = null -> null/[] = il campo district non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo address non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'address', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'address', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Indirizzo'), + ], + 'description' => [ // Array = null -> null/[] = il campo description non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'description', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'description', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Descrizione luogo'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'table_name' => 'geo.rw_watersheds', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'id' => 'ws-id', + 'swbcode' => 'swbcode' + ], + ], + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'COD_COMUNE' => 'cadastral-code', + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + */ + + /** + * display + * + * @param ?Array $layer_ids + * @param Bool $get_current_position + * @param ?Array $tools + * @param ?Int $zoom_to_layer_with_id + * @return void + */ + public function display(?Array $layer_ids = null, Bool $get_current_position = false, ?Array $tools = null, ?Int $zoom_to_layer_with_id = null) + { + $layers = []; + + if (is_array($layer_ids)) { + $layers = $this->fetchTable('Maps')->find(); + + if (isset($layer_ids) && is_array($layer_ids) && count($layer_ids) > 0) { + $layers->where(['Maps.id IN' => $layer_ids]); + } + + $layers = $layers->all(); + + $layers = $layers->map(function ($value, $key) use ($zoom_to_layer_with_id) { + $value->style = json_decode($value->style ?? ''); + $value->zoom_to_layer = isset($zoom_to_layer_with_id) && $value->id == $zoom_to_layer_with_id; + return $value; + }); + + $found_layers = $layers->reduce(function ($acc, $layer) { + $acc[$layer->id][$layer->language_code] = $layer; + return $acc; + }, []); + + $locale = I18n::getLocale(); + + $layers = collection($found_layers) + ->reduce(function ($acc, $found_layer) use ($locale) { + $acc[] = isset($found_layer[$locale]) ? $found_layer[$locale] : $found_layer['it']; + return $acc; + }, []); + } + + $this->set('layers', $layers); + $this->set('get_current_position', (isset($get_current_position) && $get_current_position)); + $this->set('tools', is_array($tools) && !empty($tools)); + $this->set('drawing_layer_name', !empty($tools['drawing_layer_name']) ? $tools['drawing_layer_name'] : __('Geometrie disegnate')); + $this->set('geocoding', isset($tools['geocoding']) && $tools['geocoding']); + $this->set('point', isset($tools['point']) && $tools['point']); + $this->set('multiple_points', !(isset($tools['geocoding']) && $tools['geocoding']) && isset($tools['multiple_points']) && $tools['multiple_points']); + $this->set('polygon', isset($tools['polygon']) && $tools['polygon']); + $this->set('circle', isset($tools['circle']) && $tools['circle']); + $this->set('delete_geometry', isset($tools['delete_geometry']) && $tools['delete_geometry']); + $this->set('feature_collection', $tools['fields']['feature_collection'] ?? false); + $this->set('longitude', $tools['fields']['longitude'] ?? false); + $this->set('latitude', $tools['fields']['latitude'] ?? false); + $this->set('coordinates', $tools['fields']['coordinates'] ?? false); + $this->set('cap', $tools['fields']['cap'] ?? false); + $this->set('province', $tools['fields']['province'] ?? false); + $this->set('district_code', $tools['fields']['district_code'] ?? false); + $this->set('district', $tools['fields']['district'] ?? false); + $this->set('address', $tools['fields']['address'] ?? false); + $this->set('description', $tools['fields']['description'] ?? false); + $this->set('geo_resources', $tools['geo_resources'] ?? false); + } +} diff --git a/idrocap_wa/src/View/CustomCsvView.php b/idrocap_wa/src/View/CustomCsvView.php new file mode 100644 index 0000000..fd65f46 --- /dev/null +++ b/idrocap_wa/src/View/CustomCsvView.php @@ -0,0 +1,100 @@ +getConfig('setSeparator'); + if ($setSeparator) { + fwrite($fp, 'sep=' . $setSeparator . "\n"); + } + } else { + ftruncate($fp, 0); + } + + $null = $this->getConfig('null'); + if ($null) { + foreach ($row as &$field) { + if ($field === null) { + $field = $null; + } + } + } + + $delimiter = $this->getConfig('delimiter'); + $enclosure = $this->getConfig('enclosure'); + $newline = $this->getConfig('newline'); + + $row = str_replace(["\r\n", "\n", "\r"], $newline, $row); + if ($enclosure === '') { + // fputcsv does not supports empty enclosure + if (fputs($fp, implode($delimiter, $row) . "\n") === false) { + return false; + } + } else { + if (fputcsv($fp, $row, $delimiter, $enclosure, "\\") === false) { + return false; + } + } + + rewind($fp); + + $csv = ''; + while (($buffer = fgets($fp, 4096)) !== false) { + $csv .= $buffer; + } + + $eol = $this->getConfig('eol'); + if ($eol !== "\n") { + $csv = str_replace("\n", $eol, $csv); + } + + $dataEncoding = $this->getConfig('dataEncoding'); + $csvEncoding = $this->getConfig('csvEncoding'); + if ($dataEncoding !== $csvEncoding) { + $extension = $this->getConfig('transcodingExtension'); + if ($extension === static::EXTENSION_ICONV) { + $csv = iconv($dataEncoding, $csvEncoding, $csv); + } elseif ($extension === static::EXTENSION_MBSTRING) { + $csv = mb_convert_encoding($csv, $csvEncoding, $dataEncoding); + } + } + + // BOM must be added after encoding + $bom = $this->getConfig('bom'); + if ($bom && $this->isFirstBom) { + $csv = $this->getBom($csvEncoding) . $csv; + $this->isFirstBom = false; + } + + return $csv; + } +} diff --git a/idrocap_wa/src/View/Helper/BreadcrumbHelper.php b/idrocap_wa/src/View/Helper/BreadcrumbHelper.php new file mode 100644 index 0000000..a0124ea --- /dev/null +++ b/idrocap_wa/src/View/Helper/BreadcrumbHelper.php @@ -0,0 +1,67 @@ + + */ + protected array $_defaultConfig = []; + + public array $helpers = ['Breadcrumbs']; + + /** + * output + * + * @param String $breadcrumb + * @return String + */ + private function output(String $breadcrumb) + { + return << +
+ $breadcrumb +
+ + EOD; + } + + /** + * render + * + * @param Array $items + * @return String + */ + public function render(Array $items): String + { + $this->Breadcrumbs->setTemplates([ + 'wrapper' => '{{content}}', + 'item' => ' {{title}}{{separator}}', + 'itemWithoutLink' => ' {{title}}{{separator}}', + 'separator' => '{{separator}}', + ]); + + $items = collection($items) + ->map(function ($item) { + return ['title' => $item['title'], 'url' => $item['url'] ?? null, 'options' => ['innerAttrs' => ['class' => $item['icon'] ?? '']]]; + }) + ->toArray(); + + $this->Breadcrumbs->add($items); + + $breadcrumb = $this->Breadcrumbs->render(['class' => 'float-sm-right']); + + return $this->output($breadcrumb); + } +} diff --git a/idrocap_wa/src/View/Helper/MenuHelper.php b/idrocap_wa/src/View/Helper/MenuHelper.php new file mode 100644 index 0000000..87fb82d --- /dev/null +++ b/idrocap_wa/src/View/Helper/MenuHelper.php @@ -0,0 +1,108 @@ + + */ + protected array $_defaultConfig = []; + + public array $helpers = ['Form', 'Html']; + + /** + * makeSingleItem + * + * @param String $title + * @param ?String $icon + * @param String $link + * @param ?String $confirm + * @param String $method + * @return String + */ + private function makeSingleItem(String $title, String|Null $icon, String $link, ?String $confirm = null, String $method = 'GET'): String + { + $fa_icon = !empty($icon) ? " fa fa-$icon" : ""; + + if (!empty($confirm) || $method == 'POST') { + $form_title = << +

$title

+ EOD; + + $form_link = $method == 'POST' ? $this->Form->postLink($form_title, $link, ['confirm' => $confirm, 'escape' => false, 'class' => 'nav-link']) : $this->Html->link($form_title, $link, ['confirm' => $confirm, 'escape' => false, 'class' => 'nav-link']); + } else { + $form_link = << + +

$title

+ + EOD; + } + + return << + $form_link + + EOD; + } + + /** + * makeItemWithSubItems + * + * @param String $title + * @param ?String $icon + * @param Array $items + * @return String + */ + private function makeItemWithSubItems(String $title, String|Null $icon, Array $items): String + { + $menu_items = implode("", collection($items)->map(function ($item) { return isset($item['link']) ? $this->makeSingleItem($item['title'], $item['icon'], $item['link'], $item['confirm'] ?? null, $item['method'] ?? 'GET') : $this->makeItemWithSubItems($item['title'], $item['icon'], $item['menu_items']); })->toArray()); + + $fa_icon = !empty($icon) ? " fa fa-$icon" : ""; + + return << + + +

+ $title + +

+
+ + + EOD; + } + + /** + * create + * + * @param Array $menu_items + * @return String + */ + public function create(Array $menu_items): String + { + $output = ''; + + foreach ($menu_items as $menu_item) { + if (isset($menu_item['link'])) { + $output.= $this->makeSingleItem($menu_item['title'], $menu_item['icon'], $menu_item['link'], $menu_item['confirm'] ?? null, $menu_item['method'] ?? 'GET'); + } else { + $output.= $this->makeItemWithSubItems($menu_item['title'], $menu_item['icon'], $menu_item['menu_items']); + } + } + return $output; + } +} diff --git a/idrocap_wa/src/View/Helper/NotificationsHelper.php b/idrocap_wa/src/View/Helper/NotificationsHelper.php new file mode 100644 index 0000000..a457c2d --- /dev/null +++ b/idrocap_wa/src/View/Helper/NotificationsHelper.php @@ -0,0 +1,87 @@ + + */ + protected array $_defaultConfig = []; + + /** + * makeNotification + * + * @param String $id + * @param String $icon + * @param String $title + * @param String $time_ago + * @param String $body + * @return String + */ + private function makeNotification(String $id, String $icon, String $title, String $time_ago, String $body): String + { + $title = strlen($title) > 35 ? substr($title, 0, 32) . '...' : $title; + return << + + $title + $time_ago +

$body

+
+ EOD; + } + + /** + * makeNotificationList + * + * @param String $user_notifications_count + * @param String $notification_items + * @return String + */ + private function makeNotificationList(String $user_notifications_count, String $notification_items): String + { + $user_notifications_count_badge = $user_notifications_count > 0 ? '' . $user_notifications_count . '' : ''; + $notifications_header = '' . __('Nuove notifiche: {0}', $user_notifications_count) . ''; + $notifications_footer = $user_notifications_count > 0 ? '' . __('Segna tutte le notifiche come lette') . '' : ''; + + return << + + + $user_notifications_count_badge + + + + EOD; + } + + /** + * create + * + * @param Array $menu_sections + * @return String + */ + public function create(Array $notifications): String + { + $notification_items = ''; + foreach ($notifications as $notification) { + $notification_items.= $this->makeNotification((String)$notification['id'], $notification['icon'], $notification['title'], $notification['time_ago'], $notification['body']); + } + return $this->makeNotificationList((String)count($notifications), $notification_items); + } +} diff --git a/idrocap_wa/src/View/Helper/SectionsHelper.php b/idrocap_wa/src/View/Helper/SectionsHelper.php new file mode 100644 index 0000000..d99a80d --- /dev/null +++ b/idrocap_wa/src/View/Helper/SectionsHelper.php @@ -0,0 +1,55 @@ + + */ + protected array $_defaultConfig = []; + + /** + * makeSection + * + * @param String $title + * @param ?String $icon + * @param Int $id + * @return String + */ + private function makeSection(String $title, String|Null $icon, Int $id): String + { + $url = Router::getRequest()->getPath(); + return << + + + + + EOD; + } + + /** + * create + * + * @param Array $menu_sections + * @return String + */ + public function create(Array $menu_sections): String + { + $output = ''; + foreach ($menu_sections as $menu_section) { + $output.= $this->makeSection($menu_section['title'], $menu_section['icon'], $menu_section['id']); + } + return $output; + } +} diff --git a/idrocap_wa/src/WGS/Auth/OpenIdConnectClient.php b/idrocap_wa/src/WGS/Auth/OpenIdConnectClient.php new file mode 100644 index 0000000..10ac5af --- /dev/null +++ b/idrocap_wa/src/WGS/Auth/OpenIdConnectClient.php @@ -0,0 +1,163 @@ +getSession()->write("oidc.oidc_state", $state); + + // Construct the authorization URL + $params = [ + 'state' => $state, + 'response_type' => 'code', + 'client_id' => $clientId, + 'scope' => $scopes, + 'redirect_uri' => $redirectUri, + ]; + + $authRequestUrl = $authUrl . '?' . http_build_query($params); + // Redirect the user to the OpenID Provider's authorization page + header("Location: $authRequestUrl"); + exit(); + } + + /** + * get_access_token + * + * This method performs a POST request to the IdP tokenUrl endpoint in order to obtain both id and access tokens + * + * @param String $tokenUrl + * @param String $issuer + * @param String $clientId + * @param Null|String $clientSecret + * @param String $redirectUri + * @throws Exception + * @return String + */ + public static function get_access_token(String $tokenUrl, String $issuer, String $clientId, Null|String $clientSecret, String $redirectUri): String + { + // Check if the state parameter matches the stored one to prevent CSRF + if (Router::getRequest()->getSession()->read("oidc.oidc_state") !== Router::getRequest()->getQuery('state')) { + throw new \Exception("oidc_state mismatch!"); + } + + // Retrieve the authorization code from the callback + $code = Router::getRequest()->getQuery('code'); + Router::getRequest()->getSession()->write('oidc.auth_code', $code); + + // Exchange the authorization code for tokens + $data = [ + 'grant_type' => 'authorization_code', + 'code' => $code, + 'client_id' => $clientId, + 'redirect_uri' => $redirectUri, + ]; + + if (!empty($clientSecret)) $data['client_secret'] = $clientSecret; + + // Use cURL to send the POST request to the token endpoint + $ch = curl_init($tokenUrl); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); + curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/x-www-form-urlencoded']); + $response = curl_exec($ch); + $errno = curl_errno($ch); + if($errno) { + $error_message = curl_strerror($errno); + throw new \Exception("Error retrieving access token from $tokenUrl: $errno - $error_message"); + } + curl_close($ch); + + // Decode the response, which contains the ID token and Access Token + $responseData = is_string($response) && strlen($response) > 0 ? json_decode($response, true) : ''; + if (empty($responseData)) throw new \Exception("Unexpected or malformed Issuer response"); + Router::getRequest()->getSession()->write("oidc.id_token", $responseData['id_token'] ?? ''); + Router::getRequest()->getSession()->write("oidc.access_token", $responseData['access_token'] ?? ''); + + $id_token_array = explode('.', $responseData['id_token'] ?? ''); + $decodedPayload = !empty($id_token_array[1]) && is_string($id_token_array[1]) && strlen($id_token_array[1]) > 0 ? json_decode(base64_decode($id_token_array[1]), true) : ''; + if (empty($decodedPayload)) throw new \Exception("Error decoding ID Token"); + if (empty($decodedPayload['iss'])) throw new \Exception("Issuer data is missing"); + if ($decodedPayload['iss'] !== $issuer) throw new \Exception("Invalid Issuer"); + if (empty($decodedPayload['aud'])) throw new \Exception("Audience data is missing"); + $audience_array = is_array($decodedPayload['aud']) ? $decodedPayload['aud'] : [$decodedPayload['aud']]; + if (!in_array($clientId, $audience_array)) throw new \Exception("Invalid Audience"); + if (empty($decodedPayload['exp'])) throw new \Exception("ID Token expiration information is missing"); + if ($decodedPayload['exp'] < time()) throw new \Exception("ID token has expired"); + return $responseData['access_token'] ?? ''; + } + + /** + * get_user_info + * + * This method performs a GET request to the IdP userInfoUrl endpoint using previously retrieved access token + * + * @param String $userInfoUrl + * @param String $access_token + * @throws Exception + * @return String + */ + public static function get_user_info(String $userInfoUrl, String $userinfo_claim_key, String $access_token): array + { + $ch = curl_init($userInfoUrl); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Bearer ' . $access_token, + ]); + $userInfoResponse = curl_exec($ch); + $errno = curl_errno($ch); + if($errno) { + $error_message = curl_strerror($errno); + throw new \Exception("Error retrieving user info from $userInfoUrl: $errno - $error_message"); + } + curl_close($ch); + + // Decode the response, which contains all user info + $decodedUserInfoResponse = is_string($userInfoResponse) && strlen($userInfoResponse) > 0 ? json_decode($userInfoResponse, true) : ''; + if (empty($decodedUserInfoResponse)) throw new \Exception("Unexpected or malformed User info response"); + if (empty($decodedUserInfoResponse[$userinfo_claim_key])) throw new \Exception("User info '$userinfo_claim_key' attribute is missing"); + return $decodedUserInfoResponse; + } + + /** + * logout + * + * @param String $endSessionUrl + * @param String $clientId + * @param String $postLogoutRedirectUri + * @return void + */ + public static function logout(String $endSessionUrl, String $clientId, String $postLogoutRedirectUri) + { + $params = [ + 'client_id' => $clientId, + 'state' => Router::getRequest()->getSession()->read("oidc.oidc_state"), + 'post_logout_redirect_uri' => $postLogoutRedirectUri, // Where to redirect after logout + ]; + + // Construct the logout URL with query parameters + $logoutUrl = $endSessionUrl . '?' . http_build_query($params); + + Router::getRequest()->getSession()->destroy(); + // Redirect to the OpenID Provider's logout page + header('Location: ' . $logoutUrl); + exit(); + } +} diff --git a/idrocap_wa/src/WGS/FileStorage/FileStorage.php b/idrocap_wa/src/WGS/FileStorage/FileStorage.php new file mode 100755 index 0000000..e002896 --- /dev/null +++ b/idrocap_wa/src/WGS/FileStorage/FileStorage.php @@ -0,0 +1,14 @@ +namenodeHost = $namenodeHost; + $this->namenodePort = $namenodePort; + $this->namenodeUser = $namenodeUser; + $this->namenodeRpcHost = $namenodeRpcHost; + $this->namenodeRpcPort = $namenodeRpcPort; + $this->hdfs = new \org\apache\hadoop\WebHDFS($this->namenodeHost, $this->namenodePort, $this->namenodeUser, $this->namenodeRpcHost, $this->namenodeRpcPort, true); + } + + /** + * getFile + * + * @param String $path + * @return mixed + */ + public function getFile(String $path) + { + return $this->hdfs->open($path); + } + + /** + * deleteFile + * + * @param String $path + * @return mixed + */ + public function deleteFile(String $path) + { + $this->hdfs->delete($path); + } + + /** + * saveFile + * + * @param String $path + * @param String $tmpPath + * @throws \Exception + * @return mixed + */ + public function saveFile(String $path, String $tmpPath) + { + try + { + $result = $this->hdfs->create($path, $tmpPath); + return $result; + } + catch(\org\apache\hadoop\WebHDFS_Exception $we) + { + throw new \Exception('Unable to save file on HadoopFileStorage: ' . $we->getMessage()); + } + } + + /** + * savePassedFile + * + * @param String $path + * @param String $file + * @return mixed + */ + public function savePassedFile(String $path, String $file) + { + return $this->hdfs->createWithData($path, $file); + } + + /** + * copyFile + * + * @param String $path1 + * @param String $path2 + * @return mixed + */ + public function copyFile(String $path1, String $path2) + { + $file = $this->getFile($path1); + $this->savePassedFile($path2, $file); + } + + /** + * checkIfExists + * + * @param String $path + * @return mixed + */ + public function checkIfExists(String $path) + { + $response = $this->hdfs->getFileStatus($path); + $jsonResponse = json_decode($response); + return !isset($jsonResponse->RemoteException->exception); + } +} diff --git a/idrocap_wa/src/WGS/FileStorage/S3MinioFileStorage.php b/idrocap_wa/src/WGS/FileStorage/S3MinioFileStorage.php new file mode 100755 index 0000000..1d41137 --- /dev/null +++ b/idrocap_wa/src/WGS/FileStorage/S3MinioFileStorage.php @@ -0,0 +1,180 @@ +config = [ + 'version' => 'latest', + 'region' => $region, + 'use_path_style_endpoint' => true, + 'credentials' => [ + 'key' => $accessKey, + 'secret' => $secretKey, + ], + ]; + + if($endpoint != null) + { + $this->config['endpoint'] = $endpoint; + } + + $this->bucket = $bucket; + $this->client = new S3Client($this->config); + + if(!$this->client->doesBucketExist($bucket)) $this->client->createBucket(['Bucket' => $bucket]); + } + + /** + * adaptPath + * + * @param String $path + * @return String + */ + protected function adaptPath($path) + { + return substr(str_replace('/', '_', $path),1); + } + + /** + * getFile + * + * @param String $path + * @return mixed + */ + public function getFile(String $path) + { + $path = $this->adaptPath($path); + $retrive = $this->client->getObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + ]); + + return $retrive['Body']->__toString(); + } + + /** + * deleteFile + * + * @param String $path + * @return mixed + */ + public function deleteFile(String $path) + { + $path = $this->adaptPath($path); + $this->client->deleteObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + ]); + } + + /** + * saveFile + * + * @param String $path + * @param String $tmpPath + * @throws \Exception + * @return mixed + */ + public function saveFile(String $path, String $tmpPath) + { + $path = $this->adaptPath($path); + try + { + $insert = $this->client->putObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + 'SourceFile' => $tmpPath + ]); + + return $insert; + } + catch(\Exception $we) + { + throw new \Exception('Unable to save file on S3MinioFileStorage: ' . $we->getMessage()); + } + } + + /** + * savePassedFile + * + * @param String $path + * @param String $file + * @throws \Exception + * @return mixed + */ + public function savePassedFile(String $path, String $file) + { + $path = $this->adaptPath($path); + try + { + $insert = $this->client->putObject([ + 'Bucket' => $this->bucket, + 'Key' => $path, + 'Body' => $file, + ]); + + return $insert; + } + catch(\Exception $we) + { + throw new \Exception('Unable to save file on S3MinioFileStorage: ' . $we->getMessage()); + } + } + + /** + * copyFile + * + * @param String $path1 + * @param String $path2 + * @return mixed + */ + public function copyFile(String $path1, String $path2) + { + $path1 = $this->adaptPath($path1); + $path2 = $this->adaptPath($path2); + $sourceBucket = $this->bucket; + $sourceKeyname = $path1; + + $copy = $this->client->copyObject([ + 'Bucket' => $this->bucket, + 'Key' => $path2, + 'CopySource' => "{$sourceBucket}/{$sourceKeyname}", + ]); + + return $copy; + } + + /** + * checkIfExists + * + * @param String $path + * @return Bool + */ + public function checkIfExists(String $path) + { + $path = $this->adaptPath($path); + return $this->client->doesObjectExist($this->bucket, $path); + } +} + +?> \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Geo/CadastralUtils.php b/idrocap_wa/src/WGS/Geo/CadastralUtils.php new file mode 100644 index 0000000..736a7d6 --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/CadastralUtils.php @@ -0,0 +1,61 @@ +execute($sql_statement)->fetchAll('assoc'); + if (!isset($result[0]['result']) || json_decode($result[0]['result'], true) === null || !isset(json_decode($result[0]['result'], true)['coordinates'])) return null; + $result_object = json_decode($result[0]['result'], true)['coordinates']; + $coordinates = (object)[]; + $coordinates->latitude = $result_object[0]; + $coordinates->longitude = $result_object[1]; + return $coordinates; + } + catch(\Exception $e) { + return null; + } + } + + /** + * isParcelWithinVegetationArea + * + * controlla se la particella specificata, del foglio specificato del comune specificato si interseca o meno con un'area di vegetazione + * + * @param String $cadastral_code + * @param String $sheet + * @param String $parcel + * @return Bool + */ + public static function isParcelWithinVegetationArea(String $cadastral_code, String $sheet, String $parcel): Bool + { + $sql_statement = "select count(*) as result from full_vegetations where st_intersects(SHAPE, (select SHAPE from cadastral_{$cadastral_code}_parcels where nationalcadastralreference = concat((select nationalcadastralzoningreference from cadastral_{$cadastral_code}_sheets where label = '{$sheet}'), '.', '{$parcel}')));"; + + $connection = ConnectionManager::get('geo'); + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return isset($result[0]['result']) && $result[0]['result'] > 0; + } + catch(\Exception $e) { + return false; + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Geo/ExtGeoResourceAttributesRetriever.php b/idrocap_wa/src/WGS/Geo/ExtGeoResourceAttributesRetriever.php new file mode 100644 index 0000000..865521e --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/ExtGeoResourceAttributesRetriever.php @@ -0,0 +1,40 @@ +url = $url; + $this->lon_parameter_name = $lon_parameter_name; + $this->lat_parameter_name = $lat_parameter_name; + } + + /** + * retrieve + * + * @param String $lat + * @param String $lon + * @return Array + */ + public function retrieve(String $lon, String $lat) + { + $http = new Client(); + $response = $http->get($this->url, [$this->lon_parameter_name => $lon, $this->lat_parameter_name => $lat]); + return json_decode($response->getStringBody(), true); + } +} diff --git a/idrocap_wa/src/WGS/Geo/GeoValidation.php b/idrocap_wa/src/WGS/Geo/GeoValidation.php new file mode 100644 index 0000000..698a79b --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/GeoValidation.php @@ -0,0 +1,61 @@ +execute('SELECT st_intersects(st_geomFromGeojson(\''.$testGeometry.'\'),st_geomFromGeojson(\''.json_encode($geometry).'\')) as result') + ->fetchAll('assoc'); + return isset($result[0]['result']) && $result[0]['result']; + } + catch(\Exception $e) { + return false; + } + } + + /** + * checkCadastralCoordinates + * + * chiede a mysql GEO se le coordinate passate costituiscono un punto all'interno del comune, foglio e particella passate + * + * @param String $latitude + * @param String $longitude + * @param String $cadastral_code + * @param String $sheet + * @param String $parcel + * @return Bool + */ + public static function checkCadastralCoordinates(String $latitude, String $longitude, String $cadastral_code, String $sheet, String $parcel): Bool + { + $sql_statement = "select count(*) as result from cadastral_{$cadastral_code}_parcels where nationalcadastralreference = concat((select nationalcadastralzoningreference from cadastral_{$cadastral_code}_sheets where label = '{$sheet}'),'.', '{$parcel}') and st_intersects(SHAPE, st_geomfromtext('POINT({$latitude} {$longitude})',4326));"; + $connection = ConnectionManager::get('geo'); + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return isset($result[0]['result']) && $result[0]['result'] === 1; + } + catch(\Exception $e) { + return false; + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Geo/Geocoding.php b/idrocap_wa/src/WGS/Geo/Geocoding.php new file mode 100644 index 0000000..c9a60e5 --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/Geocoding.php @@ -0,0 +1,84 @@ +get( + $url, + ['type' => 'json'], ['ssl_verify_peer' => false, 'ssl_verify_peer_name' => false] + ); + $http_code = $result->getStatusCode(); + if ($http_code == 200 && $result->getJson() !== null) { + $result = $result->getJson(); + } else { + $result = []; + } + return ['http_code' => $http_code, 'result' => $result]; + } + + /** + * performGeocoding + * + * @param ?String $parameters + * @param ?Array $queryParameters + * @return Array + */ + public static function performGeocoding(?String $parameters = null, ?Array $queryParameters = null) + { + $language_code = substr(I18n::getLocale(), 0, 2); + $status = 'online'; + + $map_config = Configure::read('App.mapConfig'); + $upperLeftBoundLon = $map_config['upperLeftBoundLon']; + $upperLeftBoundLat = $map_config['upperLeftBoundLat']; + $lowerRightBoundLon = $map_config['lowerRightBoundLon']; + $lowerRightBoundLat = $map_config['lowerRightBoundLat']; + + $url = Configure::read('App.urlGeocodingOnline') . "$parameters?accept-language=$language_code&viewbox=$upperLeftBoundLon,$upperLeftBoundLat,$lowerRightBoundLon,$lowerRightBoundLat&bounded=1"; + + foreach ($queryParameters as $key => $value) + { + $url .= "&$key=" . urlencode($value); + } + + if(!Configure::read('App.enableGeocodingOffline') || !Cache::read('geocoding_offline') || (time() - Cache::read('geocoding_offline') > Configure::read('App.offlineTimeout'))) + { + Cache::delete('geocoding_offline'); + $json_result = Geocoding::getJson($url); + } + + if (Configure::read('App.enableGeocodingOffline') && (!isset($json_result) || $json_result['http_code'] != 200 || is_string($json_result['result']))) + { + if(!Cache::read('geocoding_offline')) + { + Cache::write('geocoding_offline', time()); + } + $url = Configure::read('App.urlGeocodingOffline') . "$parameters?accept-language=$language_code&viewbox=$upperLeftBoundLon,$upperLeftBoundLat,$lowerRightBoundLon,$lowerRightBoundLat&bounded=1"; + + foreach($queryParameters as $key => $value) + { + $url .= "&$key=" . urlencode($value); + } + $status = 'offline'; + $json_result = Geocoding::getJson($url); + } + + $result = ['url' => $url, 'status' => $status, 'contents' => $json_result['result'], 'status_code' => ['http_code' => $json_result['http_code']]]; + return $result; + } +} diff --git a/idrocap_wa/src/WGS/Geo/IntGeoResourceAttributesRetriever.php b/idrocap_wa/src/WGS/Geo/IntGeoResourceAttributesRetriever.php new file mode 100644 index 0000000..702cb5a --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/IntGeoResourceAttributesRetriever.php @@ -0,0 +1,57 @@ +connection_name = count($geo_resource_path_array ) > 1 ? $geo_resource_path_array[0] : 'default'; + $this->db_name = count($geo_resource_path_array ) > 1 ? $geo_resource_path_array[0] : 'jixel'; + $this->table_name = $geo_resource_path_array[count($geo_resource_path_array) - 1]; + $this->geometry_name = $geometry_name; + $field_prefix = $this->db_name . '.' . $this->table_name; + $this->select_fields = implode(",", collection($attributes)->map(function ($attribute) use ($field_prefix) { return "$field_prefix.$attribute"; })->toArray()); + } + + /** + * retrieve + * + * @return Array + */ + public function retrieve($feature_collection) + { + $select_fields = $this->select_fields; + $connection_name = $this->connection_name; + $db_name = $this->db_name; + $table_name = $this->table_name; + $geometry_name = $this->geometry_name; + $connection = ConnectionManager::get("$connection_name"); + $sql_statement = "select $select_fields from $db_name.$table_name where st_intersects($db_name.$table_name.$geometry_name, st_geomfromgeojson('$feature_collection'))"; + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return $result; + } + catch(\Exception $e) { + return ['error' => true, 'code' => $e->getCode(), 'message' => $e->getMessage()]; + } + } +} diff --git a/idrocap_wa/src/WGS/Geo/LocationAttributesRetriever.php b/idrocap_wa/src/WGS/Geo/LocationAttributesRetriever.php new file mode 100644 index 0000000..24eda59 --- /dev/null +++ b/idrocap_wa/src/WGS/Geo/LocationAttributesRetriever.php @@ -0,0 +1,65 @@ +setLocation($location); + } + + /** + * setLocation + * + * @param ?Location $location + * @return LocationAttributesRetriever + */ + public function setLocation(?Location $location = null): LocationAttributesRetriever + { + if (empty($location) || get_class($location) != 'App\Model\Entity\Location') { + throw new \Exception('LocationAttributesRetriever/setLocation: Invalid location entity passed!'); + } + + $geometry_collection = json_decode('{"type": "FeatureCollection","features": []}'); + if (isset($location->feature_collection) && json_decode($location->feature_collection) != null) { + $geometry_collection = json_decode($location->feature_collection); + } + if (isset($location->coordinates) && $location->coordinates != '' && json_decode($location->coordinates) == null) { + $geometry_collection->features[] = json_decode('{"type": "Feature", "properties": {}, "geometry": {"type": "Point", "coordinates": ['.str_replace(" ", ",", $location->coordinates).']}}'); + } + $this->geometry_collection = json_encode($geometry_collection); + + return $this; + } + + /** + * retrieve + * + * @return Array + */ + public function retrieve() + { + $sql_statement = "select pro_com_t as district_code, comune as district_name, sigla as county_code, den_uts as county_name, den_reg as region, den_rip as area from geo.districts join geo.counties on geo.counties.cod_prov = geo.districts.cod_prov join geo.regions on geo.regions.cod_reg = geo.counties.cod_reg join geo.areas on geo.areas.cod_rip = geo.regions.cod_rip where st_intersects(geo.areas.SHAPE, st_geomfromgeojson('$this->geometry_collection')) and st_intersects(geo.regions.SHAPE, st_geomfromgeojson('$this->geometry_collection')) and st_intersects(geo.counties.SHAPE, st_geomfromgeojson('$this->geometry_collection')) and st_intersects(geo.districts.SHAPE, st_geomfromgeojson('$this->geometry_collection'))"; + $connection = ConnectionManager::get('geo'); + try { + $result = $connection->execute($sql_statement)->fetchAll('assoc'); + return $result; + } + catch(\Exception $e) { + return ['error' => true, 'code' => $e->getCode(), 'message' => $e->getMessage()]; + } + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/MessagingHandler.php b/idrocap_wa/src/WGS/NotificationsHandler/MessagingHandler.php new file mode 100644 index 0000000..d6b8de7 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/MessagingHandler.php @@ -0,0 +1,631 @@ +<è+òàù,.-'; + } + + $charactersLength = strlen($characters); + $randomString = ''; + for ($i = 0; $i < $length; $i++) { + $randomString .= $characters[rand(0, $charactersLength - 1)]; + } + return $randomString; + } + + /** + * generateOneTimePassword + * + * @return String + */ + private static function generateOneTimePassword(): String + { + return time().md5(MessagingHandler::generateRandomString(50)); + } + + /** + * getEventID + * + * @param ?String $co_id + * @param ?String $user_id + * @return String + */ + private static function getEventID(?String $co_id = null, ?String $user_id = null): String + { + $datetime = new \DateTime(); + + if($co_id && $user_id) + { + return $datetime->format('ymdhi') . 'UID' . $user_id . 'COID' . $co_id . 'TS' . substr((string)microtime(), 2, 8); + } + return $datetime->format('ymdhi') . 'LID' . MessagingHandler::generateRandomString(5, true) . 'RID' . MessagingHandler::generateRandomString(5, true) . 'TS' . substr((string)microtime(), 2, 8); + } + + /** + * trimMessage + * + * @param String $header + * @param String $link + * @param String $body + * @param Int $length + * @return String + */ + private static function trimMessage(String $header, String $link, String $body, Int $length): String + { + if(strlen($header . $link) > $length) + { + return substr($header . $link, 0, $length); + } + $trimmed_body = substr($body, 0, $length - strlen($header . $link) - 4) . "... "; + return $header . $trimmed_body . $link; + } + + /** + * createPushNotificationFromNotification + * + * @param Int $recipientId + * @param Array $notification + * @param String $token + * @return Array + */ + private static function createPushNotificationFromNotification(Int $recipientId, Array $notification, String $token): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $webURL = Configure::read('App.weburl'); + $link = $webURL . $notification['link']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "PUSHNOTIFICATION" . $eventID; + $notificationEntity = TableRegistry::getTableLocator()->get('Notifications')->find()->where(['Notifications.user_id' => $recipientId])->order(['Notifications.created' => 'DESC'])->first(); + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => [ + 'token' => $token, + 'notification' => [ + 'title' => $notification['title'], + 'body' => $notification['body'], + ], + 'data' => [ + 'id' => !empty($notificationEntity->id) ? (string)$notificationEntity->id : '', + 'delay' => '', + 'start' => !empty($notification['start']) ? $notification['start'] : '', + 'datetime' => !empty($notification['datetime']) ? $notification['datetime'] : '', + 'before_link' => !empty($notification['before_link']) ? $notification['before_link'] : '', + 'link' => !empty($link) ? $link : '', + 'end' => !empty($notification['end']) ? $notification['end'] : '', + ], + ], + "RECIPIENTS" => [$token], + ]; + return $message; + } + + /** + * createSmsFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $number + * @return Array + */ + private static function createSmsFromNotification(String $recipientId, Array $notification, String $number): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "SMS" . $eventID . $number; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $notification_title = $notification['sms_skip_title'] ? '' : $notification['title'] . ': '; + $body = MessagingHandler::trimMessage($notification['start'] . $notification['datetime'] . ' ' . $notification_title, $notification['before_link'] . $link.$notification['end'], $notification['body'], 640); + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => substr($body, 0, 640), + "RECIPIENTS" => [$number], + "TYPE" => "INFOTIM", + "OSDC" => "DRPCSORIS", + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * createFaxFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $number + * @return Array + */ + private static function createFaxFromNotification(String $recipientId, Array $notification, String $number): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $subject = $notification['title']; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . ': ' . $notification['body'] . ' ' . $notification['before_link'] . $link . $notification['end']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "FAX" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => substr($body, 0, 640), + "SUBJECT" => $subject, + "RECIPIENTS" => [$number], + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * createEmailFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $email + * @return Array + */ + private static function createEmailFromNotification(String $recipientId, Array $notification, String $email): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $subject = $notification['datetime'] . ' ' . $notification['title']; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . ': ' . $notification['body'] . '.' . chr(0x0D) . $notification['before_link'] . $link.$notification['end'] . chr(0x0D) . chr(0x0D) . chr(0x0D) . '---' . chr(0x0D) . $notification['disclaimer']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "EMAIL" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => $body, + "SUBJECT" => $subject, + "RECIPIENTS" => [$email], + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * createTelegramChatMessageFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $telegram_chat_id + * @return Array + */ + private static function createTelegramChatMessageFromNotification(String $recipientId, Array $notification, String $telegram_chat_id): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = '🔔' . $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . '\n\n' . $notification['body'] . '. ' . $notification['before_link'] . '\n\n' . $link . "" . $notification['end']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "TELEGRAM" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => $body, + "RECIPIENTS" => [$telegram_chat_id], + ]; + return $message; + } + + /** + * createPecFromNotification + * + * @param String $recipientId + * @param Array $notification + * @param String $pec + * @return Array + */ + private static function createPecFromNotification(String $recipientId, Array $notification, String $pec): Array + { + $eventID = MessagingHandler::getEventID((String)$notification['co_id'], (String)$recipientId); + $subject = $notification['datetime'] . ' ' . $notification['title']; + $webURL = Configure::read('App.weburl'); + $link = $notification['use_otp'] ? $webURL . "/users/oneTimePassword/" . $notification['otp'] : $webURL . $notification['link']; + $body = $notification['start'] . $notification['datetime'] . ' ' . $notification['title'] . ': ' . $notification['body'] . '.' . chr(0x0D) . $notification['before_link'] . $link.$notification['end'] . chr(0x0D) . chr(0x0D) . chr(0x0D) . '---' . chr(0x0D) . $notification['disclaimer']; + $event_string = (Configure::read('App.messaging_config.event_id_prefix') != '' ? Configure::read('App.messaging_config.event_id_prefix') . '_' : '') . "PEC" . $eventID; + $message = [ + "EVENT_ID" => $event_string, + "MESSAGE" => $body, + "SUBJECT" => $subject, + "RECIPIENTS" => [$pec], + "TOKEN" => "", + "CALLBACK" => Configure::read('App.messageCallbackUrl') . '/' . 'messages/post_report.json', + ]; + return $message; + } + + /** + * sendMessageToQueue + * + * @param Array $m + * @param String $queue + * @return void + */ + private static function sendMessageToQueue(Array $m, String $queue) + { + Log::write('debug', 'MessagingHandler::sendMessageToQueue publishing queue: ' . $queue); + Log::write('debug', 'MessagingHandler::sendMessageToQueue publishing message: ' . json_encode($m)); + $connection = new AMQPStreamConnection(Configure::read('App.rabbitMQhost'), Configure::read('App.rabbitMQport'), Configure::read('App.rabbitMQusername'), Configure::read('App.rabbitMQpassword')); + $channel = $connection->channel(); + $channel->queue_declare($queue, false, true, false, false); + $msg = new AMQPMessage(json_encode($m), ['delivery_mode' => 2]); + $channel->basic_publish($msg, '', $queue); + $channel->close(); + $connection->close(); + } + + /** + * sendMessageOfTypeToConfiguredProvider + * + * @param Array $message + * @param String $type + * @throws \Exception + * @return void + */ + private static function sendMessageOfTypeToConfiguredProvider(Array $message, String $type) + { + $dispatching_provider = Configure::read('App.messaging_config.' . $type); + Log::write('debug', "MessagingHandler::sendMessageToConfiguredProvider: $dispatching_provider"); + $queue = ''; + $m = []; + + switch ($dispatching_provider) { + case 'tim': + if ($type != 'sms') throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + $queue = Configure::read('App.messaging_broker_config.tim.sms.queue'); + $m["infotim"] = Configure::read('App.messaging_broker_config.tim.sms.infotim'); + $m["dispatching_method"] = 'tim'; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'firebase': + if ($type != 'push_notification') throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + $queue = Configure::read('App.messaging_broker_config.firebase.push_notification.queue'); + $m["dispatching_method"] = 'firebase'; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'amazon': + switch ($type) + { + case 'email': + $awsCredentials = [ + 'ses_aws_access_key_id' => Configure::read('App.messaging_broker_config.amazon.email.ses_aws_access_key_id'), + 'ses_aws_secret_access_key' => Configure::read('App.messaging_broker_config.amazon.email.ses_aws_secret_access_key'), + ]; + $queue = Configure::read('App.messaging_broker_config.amazon.email.queue'); + break; + + case 'sms': + $awsCredentials = [ + 'sns_aws_access_key_id' => Configure::read('App.messaging_broker_config.amazon.sms.sns_aws_access_key_id'), + 'sns_aws_secret_access_key' => Configure::read('App.messaging_broker_config.amazon.sms.sns_aws_secret_access_key'), + ]; + $queue = Configure::read('App.messaging_broker_config.amazon.sms.queue'); + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + } + $m["awsCredentials"] = $awsCredentials; + $m["dispatching_method"] = 'amazon'; + $m["messageChannel"] = ''; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'ies': + switch ($type) + { + case 'email': + $queue = Configure::read('App.messaging_broker_config.ies.email.queue'); + $m["smtp_username"] = Configure::read('App.messaging_broker_config.ies.email.smtp_username'); + $m["smtp_password"] = Configure::read('App.messaging_broker_config.ies.email.smtp_password'); + $m["default_sender"] = Configure::read('App.messaging_broker_config.ies.email.default_sender'); + $m["reply-to"] = Configure::read('App.messaging_broker_config.ies.email.reply-to'); + $m["list-unsubscribe"] = Configure::read('App.messaging_broker_config.ies.email.list-unsubscribe'); + $m["domain"] = Configure::read('App.messaging_broker_config.ies.email.domain'); + $m["messageChannel"] = Configure::read('App.messaging_broker_config.ies.email.messageChannel'); + break; + + case 'telegram': + $queue = Configure::read('App.messaging_broker_config.ies.telegram.queue'); + $m["telegram_bot_token"] = Configure::read('App.messaging_broker_config.ies.telegram.bot_token'); + break; + + case 'pec': + $queue = Configure::read('App.messaging_broker_config.ies.pec.queue'); + $m["smtp_username"] = Configure::read('App.messaging_broker_config.ies.pec.smtp_username'); + $m["smtp_password"] = Configure::read('App.messaging_broker_config.ies.pec.smtp_password'); + $m["default_sender"] = Configure::read('App.messaging_broker_config.ies.pec.default_sender'); + $m["reply-to"] = Configure::read('App.messaging_broker_config.ies.pec.reply-to'); + $m["list-unsubscribe"] = Configure::read('App.messaging_broker_config.ies.pec.list-unsubscribe'); + $m["domain"] = Configure::read('App.messaging_broker_config.ies.pec.domain'); + $m["messageChannel"] = Configure::read('App.messaging_broker_config.ies.pec.messageChannel'); + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + } + $m["dispatching_method"] = 'ies'; + $m["message"] = $message; + $m["type"] = $type; + break; + + case 'log': + switch ($type) + { + case 'fax': + $queue = Configure::read('App.messaging_broker_config.log.fax.queue'); + break; + + case 'email': + $queue = Configure::read('App.messaging_broker_config.log.email.queue'); + break; + + case 'sms': + $queue = Configure::read('App.messaging_broker_config.log.sms.queue'); + break; + + case 'telegram': + $queue = Configure::read('App.messaging_broker_config.log.telegram.queue'); + break; + + case 'push_notification': + $queue = Configure::read('App.messaging_broker_config.log.push_notification.queue'); + break; + + case 'pec': + $queue = Configure::read('App.messaging_broker_config.log.pec.queue'); + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' doesn't support '$type'!"); + } + $m["dispatching_method"] = 'log'; + $m["messageChannel"] = 'log'; + $m["message"] = $message; + $m["type"] = $type; + break; + + default: + throw new \Exception("messaging: dispatching_provider '$dispatching_provider' not handled!"); + } + MessagingHandler::sendMessageToQueue($m, $queue); + } + + /** + * saveMessage + * + * @param Array $orig_message + * @param ?Int $user_id + * @param String $group + * @param Int $type_id + * @param ?Int $co_id + * @param ?Int $org_id + * @param String $contact + * @return void + */ + private static function saveMessage(Array $orig_message, ?Int $user_id, String $group, Int $type_id, ?Int $co_id, ?Int $org_id, String $contact) + { + $message = TableRegistry::getTableLocator()->get('Messages')->newEntity([ + 'controllable_object_id' => $co_id, + 'user_id' => $user_id, + 'organisation_id' => $org_id, + 'mgroup' => $group, + 'message_status_id' => 0, + 'content' => $orig_message['MESSAGE'], + 'event_string' => $orig_message['EVENT_ID'], + 'message_type_id' => $type_id, + 'last_update' => new DateTime(), + 'contact' => $contact, + ]); + + Log::write('debug', 'MessagingHandler::saveMessage saving messaage: ' . json_encode($message)); + if (!TableRegistry::getTableLocator()->get('Messages')->save($message)) { + Log::write('debug', 'MessagingHandler::saveMessage error:'); + Log::write('debug', json_encode($message->getErrors())); + } + } + + /** + * dispatch + * + * @param Array $recipients + * @param Array $notification + * @param String $group + * @param ?Int $co_id + * @param Int $dispatching_task_id + * @throws \Exception + * @return void + */ + public static function dispatch(Array $recipients, Array $notification, String $group, ?Int $co_id, Int $dispatching_task_id) + { + Log::write('debug', 'MessagingHandler::dispatch START'); + foreach($recipients as $recipient) + { + // inserisco nella notifica il datetime in base al timezone dello user. Se lo user non ha timezone + // o se si tratta di una organizzazione, usiamo il defaultUserTimezone: + $notification['datetime'] = (new DateTime())->i18nFormat(Configure::read('App.notification_datetime_format'), $recipient->timezone ?? Configure::read('App.defaultUserTimezone')); + + // recupero l'actor del recipient (che sia user o organisation): + $recipient_actor = $recipient->getActor(); + + // se l'actor non è ne USER ne ORGANISATION -> skip: + if (!in_array($recipient_actor->actor_type_id, [1, 5])) continue; + + // se il recipient è uno user e va usato otp per il tipo di notifica, + // genero otp, lo ingetto nella notifica, lo salvo nello user insieme a redirect url ed expires: + if ($recipient_actor->actor_type_id == 5 && $notification['use_otp']) { + $notification['otp'] = MessagingHandler::generateOneTimePassword(); + $recipient->otp = $notification['otp']; + $recipient->otp_redirect_url = empty($notification['link']) ? '/' : $notification['link']; + $hours = Configure::read('App.oneTimePasswordExpirationHours', 1); + $recipient->otp_expires = new DateTime("+$hours hours"); + TableRegistry::getTableLocator()->get('Users')->save($recipient); + } + + // stabilisco il prefix da inviare a createSmsFromNotification e createEmailFromNotification: + $recipientIdPrefix = $recipient_actor->actor_type_id == 1 ? 'O' : 'U'; + + // recupero il dispatching_task_item per l'actor specifico: + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->contain(['DispatchingTasks'])->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task_id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item) continue; + + if ($recipient_actor->actor_type_id == 5) { + // SOLO PER UTENTE - gestione invio PUSH NOTIFICATION: + $push_notification_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(0)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $push_notification_bit)) + { + foreach($recipient->getPushNotificationsWithNotifications() as $pushNotificationObj) + { + $pushNotification = $pushNotificationObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating PUSH NOTIFICATION for ' . $recipient->name . " " . $recipient->surname . " with token " . $pushNotification); + $message = MessagingHandler::createPushNotificationFromNotification($recipient->id, $notification, $pushNotification); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'push_notification'); + $message['MESSAGE'] = $message['MESSAGE']['notification']['title'] . ' - ' . $message['MESSAGE']['notification']['body']; + MessagingHandler::saveMessage($message, $recipient->id, $group, 0, $co_id, null, $pushNotification); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $push_notification_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + + // gestione invio SMS: + $sms_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(1)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $sms_bit)) + { + foreach($recipient->getMobilePhonesWithNotifications() as $mobileObj) + { + $mobile = $mobileObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating SMS for ' . $recipient_actor->description . " with number " . $mobile); + $message = MessagingHandler::createSmsFromNotification($recipientIdPrefix . $recipient->id . 'D' . $mobileObj->delivery_id, $notification, $mobile); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'sms'); + MessagingHandler::saveMessage($message, $recipient_actor->actor_type_id == 1 ? null : $recipient->id, $group, 1, $co_id, $recipient_actor->actor_type_id == 1 ? $recipient->id : null, $mobile); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $sms_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + + if ($recipient_actor->actor_type_id == 5) { + // SOLO PER UTENTE - gestione invio FAX: + $fax_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(2)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $fax_bit)) + { + foreach($recipient->getFaxesWithNotifications() as $faxObj) + { + $fax = $faxObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating FAX for ' . $recipient->name . " " . $recipient->surname . " with number " . $fax); + $message = MessagingHandler::createFaxFromNotification('U' . $recipient->id . 'D' . $faxObj->delivery_id, $notification, $fax); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'fax'); + MessagingHandler::saveMessage($message, $recipient->id, $group, 2, $co_id, null, $fax); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $fax_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + + // gestione invio EMAIL: + $email_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(3)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $email_bit)) + { + foreach($recipient->getEmailsWithNotifications() as $emailObj) + { + $email = $emailObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating EMAIL for ' . $recipient_actor->description . " with email " . $email); + $message = MessagingHandler::createEmailFromNotification($recipientIdPrefix . $recipient->id . 'D' . $emailObj->delivery_id, $notification, $email); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'email'); + MessagingHandler::saveMessage($message, $recipient_actor->actor_type_id == 1 ? null : $recipient->id, $group, 3, $co_id, $recipient_actor->actor_type_id == 1 ? $recipient->id : null, $email); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $email_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + + if ($recipient_actor->actor_type_id == 5) { + // SOLO PER UTENTE - gestione invio TELEGRAM CHAT (BOT): + $telegram_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(4)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $telegram_bit)) + { + foreach($recipient->getTelegramChatsWithNotifications() as $telegramChatObj) + { + $telegramChat = $telegramChatObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating TELEGRAM CHAT for ' . $recipient->name . " " . $recipient->surname . " with telegram_chat_id " . $telegramChat); + $message = MessagingHandler::createTelegramChatMessageFromNotification('U' . $recipient->id . 'D' . $telegramChatObj->delivery_id, $notification, $telegramChat); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'telegram'); + MessagingHandler::saveMessage($message, $recipient->id, $group, 4, $co_id, null, $telegramChat); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $telegram_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + + // gestione invio PEC: + $pec_bit = TableRegistry::getTableLocator()->get('MessageTypes')->get(5)->dispatching_bitmask_weight; + if (($dispatching_task_item->not_performed_dispatching_bitmask & $pec_bit)) + { + foreach($recipient->getPecsWithNotifications() as $pecObj) + { + $pec = $pecObj->value; + Log::write('debug', 'MessagingHandler::dispatch Creating PEC for ' . $recipient_actor->description . " with PEC " . $pec); + $message = MessagingHandler::createPecFromNotification($recipientIdPrefix . $recipient->id . 'D' . $pecObj->delivery_id, $notification, $pec); + MessagingHandler::sendMessageOfTypeToConfiguredProvider($message, 'pec'); + MessagingHandler::saveMessage($message, $recipient_actor->actor_type_id == 1 ? null : $recipient->id, $group, 5, $co_id, $recipient_actor->actor_type_id == 1 ? $recipient->id : null, $pec); + } + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->performed_dispatching_bitmask += $pec_bit; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + Log::write('debug', 'MessagingHandler::dispatch END'); + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/NotificationsHandler/NotificationGenerator.php b/idrocap_wa/src/WGS/NotificationsHandler/NotificationGenerator.php new file mode 100644 index 0000000..fb49144 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/NotificationGenerator.php @@ -0,0 +1,169 @@ +get('NotificationTypes')->find()->where(['NotificationTypes.description' => $notification['type']])->first(); + $notification['type_id'] = $notificationType->id ?? ''; + } + + return $notification; + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/NotificationsHandler.php b/idrocap_wa/src/WGS/NotificationsHandler/NotificationsHandler.php new file mode 100644 index 0000000..90f6ac0 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/NotificationsHandler.php @@ -0,0 +1,243 @@ +channel(); + $channel->queue_declare(Configure::read('App.background_tasks.notifications.channel'), false, true, false, false); + $msg = new AMQPMessage(json_encode($m), ['delivery_mode' => 2]); + $channel->basic_publish($msg, '', Configure::read('App.background_tasks.notifications.channel')); + $channel->close(); + $connection->close(); + } + + /** + * dispatch + * + * @param Int|Null $co_id + * @param String $notification_code + * @param Array $options + * @param Int|String $group + * @param Int|Null $user_logged + * @return void + */ + public static function dispatch(Int|Null $co_id, String $notification_code, Array $options, String|Null $group = null, Int|Null $user_logged = null) + { + $group = !empty($group) ? $group : (new \DateTime())->format('ymdhi').substr((string)microtime(), 2, 8); + + $bt = TableRegistry::getTableLocator()->get('BackgroundTasks')->newEntity([ + 'command' => 'notifications_handler', + 'data' => json_encode(['co_id' => $co_id, 'notification_code' => $notification_code, 'options' => $options, 'group' => $group, 'user_logged' => $user_logged]), + 'dgroup' => $group, + ]); + if (TableRegistry::getTableLocator()->get('BackgroundTasks')->save($bt)) NotificationsHandler::sendDispatchingBackgroundTask(['command' => 'notifications_handler', 'data' => json_encode(['background_task_id' => $bt->id])]); + } + + /** + * executeDispatch + * + * @param Int|Null $co_id + * @param String $notification_code + * @param Array $options + * @param String $group + * @param Int|Null $user_logged + * @throws \Exception + * @return void + */ + public static function executeDispatch(Int|Null $co_id, String $notification_code, Array $options, String $group, Int|Null $user_logged) + { + Log::write('debug', 'NotificationsHandler::executeDispatch - DISPATCH FOR CODE: "' . $notification_code . '" AND GROUP: "' . $group . '" START!!!'); + + $dispatch_step = 0; + + // Fase 0 (eseguita sempre) - creazione/aggiornamento task: + $background_task = TableRegistry::getTableLocator()->get('BackgroundTasks')->find()->where(['BackgroundTasks.dgroup' => $group])->first(); + if ($background_task) { + Log::write('debug', 'NotificationsHandler::executeDispatch - linked background_task id: ' . $background_task->id); + $dispatching_task = TableRegistry::getTableLocator()->get('DispatchingTasks')->find()->where(['DispatchingTasks.background_task_id' => $background_task->id])->first(); + if (!$dispatching_task) { + Log::write('debug', 'NotificationsHandler::executeDispatch - Creating new dispatching_task'); + $dispatching_task = TableRegistry::getTableLocator()->get('DispatchingTasks')->newEntity([ + 'dispatching_task_group' => $group, + 'dispatching_task_status_id' => 1, + 'retries' => 0, + 'failed' => false, + 'background_task_id' => $background_task->id, + ]); + } else { + if ($dispatching_task->dispatching_task_status_id != 5 && !$dispatching_task->failed) $dispatching_task->retries++; + } + if ($dispatching_task->dispatching_task_status_id != 5 && !$dispatching_task->failed) { + if ($dispatching_task->retries >= Configure::read('App.dispatching_task_max_retries')) $dispatching_task->failed = true; + Log::write('debug', 'NotificationsHandler::executeDispatch - Saving dispatching_task:' . json_encode($dispatching_task)); + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->failed ? 0 : $dispatching_task->dispatching_task_status_id; + } + } + + // Fase 1 - Retrieving - se lo stato è "recipients_detection": + if ($dispatch_step == 1) { + Log::write('debug', 'NotificationsHandler::executeDispatch - RECIPIENTS_DETECTION START!!!'); + $recipients = RecipientsDetector::getRecipients($notification_code, $options); + + // in questo foreach prendo un utente e verifico se ha almeno un recapito valido: + // si: rimuovo l'organizzazione da recipients, almeno c'è un destinatario in grado di ricevere, quindi l'org va rimossa. + // no: vado avanti (l'organizzazione rimane dentro recipients e quindi verrà lasciata, se poi dopo si trova un utente che ha recapiti in caso viene rimossa) + if (count($recipients['users']) > 0) Log::write('debug', 'NotificationsHandler::executeDispatch - checking users to be notified (if they have notification enabled push notifications, mobile phones, faxes, emails, telegram chats or PECs):'); + foreach ($recipients['users'] as $recipient) { + // creo (se non esiste il task item per l'utente specifico): + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item) { + Log::write('debug', 'NotificationsHandler::executeDispatch - creating dispatching_task_item for user recipient with id: ' . $recipient->id); + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->newEntity([ + 'dispatching_task_id' => $dispatching_task->id, + 'actor_id' => $recipient->actor_id, + 'system_dispatched' => false, + 'actor_dispatching_bitmask' => $recipient->getDispatchingBitmask($notification_code), + 'performed_dispatching_bitmask' => 0, + ]); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + if($notification_code != 'test_all' && isset($recipient->organisation_id) && $recipient->getDispatchingBitmask($notification_code) > 0) + { + if (($key = array_search($recipient->organisation_id, $recipients['organisations'])) !== false) { + Log::write('debug', 'NotificationsHandler::executeDispatch - Removing organisation with ID: ' . $recipients['organisations'][$key] . ' from notifiable organisations because there is at least 1 belonging user that will be notified!'); + unset($recipients['organisations'][$key]); + } + } + } + + if (count($recipients['organisations']) > 0) Log::write('debug', 'NotificationsHandler::executeDispatch - checking organisations to be notified (if they have notification enabled mobile phones, emails or PECs):'); + foreach($recipients['organisations'] as $organisation_id) + { + $recipient = TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.id' => $organisation_id])->first(); + if (!$recipient) continue; + + // creo (se non esiste il task item per l'org specifica): + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item && $recipient->getDispatchingBitmask()) { + Log::write('debug', 'NotificationsHandler::executeDispatch - creating dispatching_task_item for organisation recipient with id: ' . $recipient->id); + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->newEntity([ + 'dispatching_task_id' => $dispatching_task->id, + 'actor_id' => $recipient->actor_id, + 'system_dispatched' => null, + 'actor_dispatching_bitmask' => $recipient->getDispatchingBitmask(), + 'performed_dispatching_bitmask' => 0, + ]); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + } + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - RECIPIENTS_DETECTION END!!!'); + } + + $notification = null; + if (in_array($dispatch_step, [2,3,4])) { + $notification = NotificationGenerator::getNotification($co_id, $notification_code, $options); + $notification['user_logged'] = $user_logged; + Log::write('debug', 'NotificationsHandler::executeDispatch - GENERATED NOTIFICATION: ' . json_encode($notification)); + } + + // Fase 2 - se lo stato è "system_dispatching": + if ($dispatch_step == 2) { + Log::write('debug', 'NotificationsHandler::executeDispatch - SYSTEM_DISPATCHING START!!!'); + + $actor_ids_query = TableRegistry::getTableLocator()->get('DispatchingTaskItems') + ->find() + ->select(['DispatchingTaskItems.actor_id']) + ->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.system_dispatched' => false]); + + $users = TableRegistry::getTableLocator()->get('Users') + ->find() + ->where(['Users.actor_id IN' => $actor_ids_query]) + ->toArray(); + + if($notification_code != "password_recovery" && $notification_code != "verify-citizen-registration") + { + SystemNotificationsDispatcher::dispatch($users, $notification, $group, $co_id, $dispatching_task->id); + } + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - SYSTEM_DISPATCHING END!!!'); + } + + // Fase 3 - se lo stato è "users_message_dispatching": + if ($dispatch_step == 3) { + Log::write('debug', 'NotificationsHandler::executeDispatch - USERS_MESSAGE_DISPATCHING START!!!'); + + $actor_ids_query = TableRegistry::getTableLocator()->get('DispatchingTaskItems') + ->find() + ->select(['DispatchingTaskItems.actor_id']) + ->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.system_dispatched IS NOT NULL', 'DispatchingTaskItems.not_performed_dispatching_bitmask > 0']); + + $users = TableRegistry::getTableLocator()->get('Users') + ->find() + ->where(['Users.actor_id IN' => $actor_ids_query]) + ->toArray(); + + MessagingHandler::dispatch($users, $notification, $group, $co_id, $dispatching_task->id); + + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - USERS_MESSAGE_DISPATCHING END!!!'); + } + + // Fase 4 - se lo stato è "organisations_message_dispatching": + if ($dispatch_step == 4) { + Log::write('debug', 'NotificationsHandler::executeDispatch - ORGANISATIONS_MESSAGE_DISPATCHING START!!!'); + + $actor_ids_query = TableRegistry::getTableLocator()->get('DispatchingTaskItems') + ->find() + ->select(['DispatchingTaskItems.actor_id']) + ->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task->id, 'DispatchingTaskItems.system_dispatched IS NULL', 'DispatchingTaskItems.not_performed_dispatching_bitmask > 0']); + + $organisations = TableRegistry::getTableLocator()->get('Organisations') + ->find() + ->where(['Organisations.actor_id IN' => $actor_ids_query]) + ->toArray(); + + MessagingHandler::dispatch($organisations, $notification, $group, $co_id, $dispatching_task->id); + + $dispatching_task->dispatching_task_status_id++; + if (!TableRegistry::getTableLocator()->get('DispatchingTasks')->save($dispatching_task)) { + throw new \Exception(json_encode($dispatching_task->getErrors())); + } + $dispatch_step = $dispatching_task->dispatching_task_status_id; + Log::write('debug', 'NotificationsHandler::executeDispatch - ORGANISATIONS_MESSAGE_DISPATCHING END!!!'); + } + Log::write('debug', 'NotificationsHandler::executeDispatch - DISPATCH FOR CODE: "' . $notification_code . '" AND GROUP: "' . $group . '" END!!!'); + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/RecipientsDetector.php b/idrocap_wa/src/WGS/NotificationsHandler/RecipientsDetector.php new file mode 100644 index 0000000..94ed81f --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/RecipientsDetector.php @@ -0,0 +1,119 @@ + [], 'organisations' => []]; + + switch($notification_code) + { + case "test_all": + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->toArray(); + $recipients['organisations'] = TableRegistry::getTableLocator()->get('Organisations')->find()->all()->extract('id')->toArray(); + break; + case "verify-citizen-registration": + case "password_recovery": + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['user_id']); + break; + + case "send_to_drar_admin": + // recupero gli utenti appartenenti all'organizzazione di tipo DRAR (id 6) + // che hanno la capability "documentation.water_drawing_paperworks.assign": + $user_ids_query = TableRegistry::getTableLocator()->get('Users') + ->find() + ->matching('Groups.Capabilities') + ->matching('Organisations') + ->select(['Users.id']) + ->where(['Organisations.organisation_type_id' => 6, 'Capabilities.value' => 'documentation.water_drawing_paperworks.assign']); + + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id IN' => $user_ids_query])->toArray(); + break; + case "send_to_drar_anac_user": + // recupero gli utenti appartenenti all'organizzazione di tipo DRAR (id 6) + // che hanno la capability "documentation.water_drawing_paperworks.antimafia_request": + $user_ids_query = TableRegistry::getTableLocator()->get('Users') + ->find() + ->matching('Groups.Capabilities') + ->matching('Organisations') + ->select(['Users.id']) + ->where(['Organisations.organisation_type_id' => 6, 'Capabilities.value' => 'documentation.water_drawing_paperworks.antimafia_request']); + + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id IN' => $user_ids_query])->toArray(); + break; + case "send_to_drar_user_antimafia_uploaded": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['drar_user_id']); + break; + case "send_to_drar_user_antimafia_request_expired": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['drar_user_id']); + break; + case "send_to_drar_user": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['drar_user_id']); + break; + case "send_to_gc_user": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_user_paperwork_verified": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_user_request_self_certification": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_user_paperwork_completed": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_gc_assign_paperwork": + // recupero gli utenti appartenenti all'organizzazione di tipo GC (id 0) + // che hanno la capability "documentation.water_drawing_paperworks.assign": + $user_ids_query = TableRegistry::getTableLocator()->get('Users') + ->find() + ->matching('Groups.Capabilities') + ->matching('Organisations') + ->select(['Users.id']) + ->where(['Organisations.province' => $options['water_drawing_paperwork_province'], 'Organisations.organisation_type_id' => 0, 'Capabilities.value' => 'documentation.water_drawing_paperworks.assign']); + + $recipients['users'] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id IN' => $user_ids_query])->toArray(); + + // recupero l'organizzazione di tipo GC (id 0) per la provincia di competenza: + $recipients['organisations'] = TableRegistry::getTableLocator()->get('Organisations')->find()->where(['Organisations.organisation_type_id' => 0, 'Organisations.province' => $options['water_drawing_paperwork_province']])->all()->extract('id')->toArray(); + break; + case "send_to_gc_validate_paperwork": + // recupero l'utente GC a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['gc_user_id']); + break; + case "send_to_citizen_paperwork_verified": + // recupero l'utente Cittadino a cui la pratica risulta intestata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.tax_code' => $options['citizen_user_tax_code']])->first(); + break; + case "send_result_of_validation_to_operator": + // recupero l'utente Cittadino a cui la pratica risulta intestata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->find()->where(['Users.id' => $options['user_id']])->first(); + break; + case "send_to_last_edit_user_intended_use_check_completed": + // recupero l'utente DRAR a cui la pratica risulta già assegnata: + $recipients['users'][] = TableRegistry::getTableLocator()->get('Users')->get($options['last_edit_user_id']); + break; + default: + break; + } + return $recipients; + } +} diff --git a/idrocap_wa/src/WGS/NotificationsHandler/SystemNotificationsDispatcher.php b/idrocap_wa/src/WGS/NotificationsHandler/SystemNotificationsDispatcher.php new file mode 100644 index 0000000..ab1c948 --- /dev/null +++ b/idrocap_wa/src/WGS/NotificationsHandler/SystemNotificationsDispatcher.php @@ -0,0 +1,122 @@ +get('Notifications')->newEntity([ + 'user_id' => $user_id, + 'notification_type_id' => $orig_notification['type_id'], + 'thread' => substr($type_string, 0, 45 - strlen($co_id_string) - 1) . '-' . $co_id_string, + 'info' => json_encode($orig_notification), + 'ngroup' => $group, + 'controllable_object_id' => $co_id, + ]); + + Log::write('debug', 'SystemNotificationsDispatcher::saveNotification saving notification: ' . json_encode($notification)); + if (!TableRegistry::getTableLocator()->get('Notifications')->save($notification)) { + Log::write('debug', 'SystemNotificationsDispatcher::saveNotification error:'); + Log::write('debug', json_encode($notification->getErrors())); + return null; + } + return $notification->id; + } + + /** + * createSystemNotificationFromNotification + * + * @param Int $user_id + * @param Array $orig_notification + * @param Int $saved_notification_id + * @return Object + */ + private static function createSystemNotificationFromNotification(Int $user_id, Array $orig_notification, Int $saved_notification_id): Object + { + $system_notification = (object)[]; + $system_notification->type = "notification"; + $system_notification->user_ids = [$user_id]; + $system_notification->notification_ids = [$user_id => $saved_notification_id]; + $system_notification->msg = (object)[]; + $system_notification->msg->title = $orig_notification['title']; + $system_notification->msg->body = $orig_notification['body']; + $system_notification->msg->type = TableRegistry::getTableLocator()->get('NotificationTypes')->find()->where(['NotificationTypes.id' => $orig_notification['type_id'] ?? 0])->first()->description ?? 'unknown'; + $system_notification->msg->sound = 'notification'; + return $system_notification; + } + + /** + * sendNotification + * + * @param Object $system_notification + * @return void + */ + private static function sendNotification(Object $system_notification) + { + Log::write('debug', 'SystemNotificationsDispatcher::sendNotificationRequests publishing exchange: ' . Configure::read('App.notificatorExchange')); + Log::write('debug', 'SystemNotificationsDispatcher::sendNotificationRequests publishing system_notification: ' . json_encode($system_notification)); + $connection = new AMQPStreamConnection(Configure::read('App.rabbitMQhost'), Configure::read('App.rabbitMQport'), Configure::read('App.rabbitMQusername'), Configure::read('App.rabbitMQpassword')); + $channel = $connection->channel(); + $exchange = Configure::read('App.notificatorExchange'); + $channel->exchange_declare($exchange, 'fanout', false, true, false); + $msg = new AMQPMessage(json_encode($system_notification), ['expiration' => '600000']); + $channel->basic_publish($msg, $exchange); + $channel->close(); + $connection->close(); + } + + /** + * dispatch + * + * @param Array $recipients + * @param Array $orig_notification + * @param String $group + * @param ?Int $co_id + * @param Int $dispatching_task_id + * @throws \Exception + * @return void + */ + public static function dispatch(Array $recipients, Array $orig_notification, String $group, ?Int $co_id, Int $dispatching_task_id) + { + Log::write('debug', 'SystemNotificationsDispatcher::dispatch START'); + foreach($recipients as $recipient) + { + // recupero il dispatching_task_item per l'actor specifico: + $dispatching_task_item = TableRegistry::getTableLocator()->get('DispatchingTaskItems')->find()->contain(['DispatchingTasks'])->where(['DispatchingTaskItems.dispatching_task_id' => $dispatching_task_id, 'DispatchingTaskItems.actor_id' => $recipient->actor_id])->first(); + if (!$dispatching_task_item) continue; + + $saved_notification_id = SystemNotificationsDispatcher::saveNotification($orig_notification, $recipient->id, $group, $co_id); + if (!is_int($saved_notification_id)) continue; + $system_notification = SystemNotificationsDispatcher::createSystemNotificationFromNotification($recipient->id, $orig_notification, $saved_notification_id); + SystemNotificationsDispatcher::sendNotification($system_notification); + + // aggiorno il task item per l'utente specifico): + $dispatching_task_item->system_dispatched = true; + $dispatching_task_item->dispatching_task->dispatching_task_group = $dispatching_task_item->dispatching_task->dispatching_task_group; + $dispatching_task_item->setDirty('dispatching_task'); + if (!TableRegistry::getTableLocator()->get('DispatchingTaskItems')->save($dispatching_task_item)) { + throw new \Exception(json_encode($dispatching_task_item->getErrors())); + } + } + Log::write('debug', 'SystemNotificationsDispatcher::dispatch END'); + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/SnapshotsHandler/SnapshotsHandler.php b/idrocap_wa/src/WGS/SnapshotsHandler/SnapshotsHandler.php new file mode 100644 index 0000000..c12ae88 --- /dev/null +++ b/idrocap_wa/src/WGS/SnapshotsHandler/SnapshotsHandler.php @@ -0,0 +1,304 @@ +get('ControllableObjects')->find()->contain(['ControllableObjectTypes'])->where(['ControllableObjects.id' => $controllable_object_id])->first(); + if (!isset($controllable_object->controllable_object_type->description)) return false; + + switch($controllable_object->controllable_object_type->description) + { + case "water_drawing_paperwork": + $snapshot = SnapshotsHandler::createSnapshotForWaterDrawingPaperworks($controllable_object_id); + break; + } + + if (!isset($snapshot)) return false; + + $user_id = Router::getRequest()?->getAttribute('identity')?->id; + $controller = Router::getRequest()?->getParam('controller'); + $action = Router::getRequest()?->getParam('action'); + + if (!isset($user_id) || !isset($controller) || !isset($action)) return false; + + $snapshotsTable = TableRegistry::getTableLocator()->get('Snapshots'); + $snapshotEntity = $snapshotsTable->newEntity([ + 'controllable_object_type_id' => $controllable_object->controllable_object_type_id, + 'controllable_object_id' => $controllable_object_id, + 'object_snapshot' => $snapshot, + 'date' => new DateTime(), + 'user_id' => $user_id, + 'controller_action' => "$controller-$action", + ]); + if (!$snapshotsTable->save($snapshotEntity)) return false; + + // all good! + return true; + } + + /** + * createSnapshotForWaterDrawingPaperworks + * + * @param Int $controllable_object_id + * @return String + */ + private static function createSnapshotForWaterDrawingPaperworks(Int $controllable_object_id): String + { + $controllableObjectsTable = TableRegistry::getTableLocator()->get('ControllableObjects'); + $contain = [ + 'Organisations' => [ + 'Actors', + ], + 'Locations', + 'ChildAttachments' => [ + 'Tags', + 'ControllableObjects' => [ + 'Locations', + 'Creator' => [ + 'Organisations' => [ + 'Actors' + ] + ] + ] + ], + 'Creator' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'Modifier' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'WaterDrawingPaperworks' => [ + 'WaterDrawingPaperworkPecs' => [ + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + 'WaterDrawingPaperworkStatuses', + 'WaterDrawingArticles', + 'DrarUsers' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'GcUsers' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + 'Applicants', + 'WaterDrawingAntimafiaCertificationRequests' => [ + 'WaterDrawingAntimafiaCertificationRequestStatuses', + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + 'WaterDrawingFees' => [ + 'WaterDrawingPayments' => [ + 'WaterDrawingPaymentTypes', + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + ], + 'WaterDrawingPaperworkHistories' => [ + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + 'WaterDrawingDerivations' => [ + 'WaterDrawingDerivationTypes', + ], + 'WaterDrawingReturnPoints', + 'WaterDrawingIntendedUses' => [ + 'WaterDrawingIntendedUseTypes', + 'CadastralCropTypes', + 'WaterDrawingMeters' => [ + 'WaterDrawingToolTypes', + 'WaterDrawingMeasurements' => [ + 'Users' => [ + 'Actors', + 'Organisations' => [ + 'Actors' + ] + ], + ], + ], + ], + ], + ]; + + $logged_user = Router::getRequest()?->getAttribute('identity'); + + // disabilitiamo temporaneamente lo UserTimezoneDatetimeEntityTrait altrimenti la serializzazione + // verrà eseguita con tutte le date nel timezone dello user loggato e non in UTC!!!!!> + if ($logged_user) $logged_user->disableUserTimezoneDatetimeEntityTrait = true; + + $waterDrawingPaperwork = $controllableObjectsTable->find()->contain($contain)->where(['ControllableObjects.id' => $controllable_object_id])->first(); + + // riabilitiamo lo UserTimezoneDatetimeEntityTrait post serializzazione + if ($logged_user) $logged_user->disableUserTimezoneDatetimeEntityTrait = false; + + return base64_encode(serialize($waterDrawingPaperwork)); + } + + /** + * getControllableObjectFromSnapshotWithId + * + * @param Int $snapshot_id + * @return ControllableObject|Null + */ + public static function getControllableObjectFromSnapshotWithId(Int $snapshot_id): ?ControllableObject + { + $snapshotsTable = TableRegistry::getTableLocator()->get('Snapshots'); + $snapshot = $snapshotsTable->find()->where(['Snapshots.id' => $snapshot_id])->first(); + if (!$snapshot) return null; + return unserialize(base64_decode($snapshot->object_snapshot)); + } + + /** + * getLastWaterDrawingPaperworkUnpackingVersion + * + * @return Int + */ + public static function getLastWaterDrawingPaperworkUnpackingVersion(): Int + { + // ogni volta che si modifica il codice del metodo seguente getUnpackedWaterDrawingPaperworkSnapshot(), + // incrementare il numero int da restituire. Questo permetterà al cron job di rieseguire l'unpacking + // secondo la nuova versione. + return 1; + } + + /** + * getSnapshotControllerActionDescription + * + * @param String $controller_action + * @return String + */ + public static function getSnapshotControllerActionDescription($controller_action): String + { + $controller_action_descriptions = [ + 'WaterDrawingPaperworks-add' => __('ha creato una nuova Pratica di Attingimento'), + 'WaterDrawingPaperworks-add_scan' => __('ha inserito una nuova Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-edit' => __('ha modificato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-edit_scan' => __('ha modificato la Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-delete' => __('ha eliminato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-validate_scan' => __('ha verificato la Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-upload_attachment' => __('ha inserito un allegato sulla Pratica di Attingimento'), + 'WaterDrawingPaperworks-upload_attachment_scan' => __('ha inserito un allegato sulla Pratica di Attingimento scansionata'), + 'WaterDrawingPaperworks-send_to_validation' => __('ha inviato in validazione la Pratica di Attingimento'), + 'WaterDrawingPaperworks-assign' => __('ha assegnato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-validate' => __('ha verificato la Pratica di Attingimento'), + 'WaterDrawingPaperworks-send_to_drar' => __('ha inviato la Pratica di Attingimento al DRAR'), + 'WaterDrawingPaperworks-send_to_gc' => __('ha inviato la Pratica di Attingimento al Genio Civile'), + 'WaterDrawingPaperworks-submit_antimafia_request' => __('ha creato la richiesta Antimafia'), + 'WaterDrawingPaperworks-antimafia_request_to_anac' => __('ha inviato la richiesta Antimafia all\'ANAC'), + 'WaterDrawingPaperworks-request_self_certification' => __('ha richiesto l\'autocertificazione Antimafia'), + 'WaterDrawingPaperworks-upload_antimafia_attachment' => __('ha inserito l\'allegato Antimafia'), + 'WaterDrawingPayments-add' => __('ha inserito un pagamento sulla Pratica di Attingimento'), + 'WaterDrawingPayments-edit' => __('ha aggiornato un pagamento sulla Pratica di Attingimento'), + 'WaterDrawingPayments-delete' => __('ha cancellato un pagamento sulla Pratica di Attingimento'), + 'WaterDrawingPaperworkPecs-add' => __('ha inserito un documento PEC sulla Pratica di Attingimento'), + 'WaterDrawingPaperworkPecs-edit' => __('ha aggiornato un documento PEC sulla Pratica di Attingimento'), + 'WaterDrawingPaperworkPecs-delete' => __('ha cancellato un documento PEC sulla Pratica di Attingimento'), + 'WaterDrawingDerivations-add' => __('ha inserito un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-edit' => __('ha aggiornato un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-delete' => __('ha cancellato un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-update_location' => __('ha aggiornato la località di un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingDerivations-update_data' => __('ha aggiornato la portata e il volume di un punto di prelievo alla Pratica di Attingimento'), + 'WaterDrawingFees-add' => __('ha inserito un canone alla Pratica di Attingimento'), + 'WaterDrawingFees-edit' => __('ha aggiornato un canone alla Pratica di Attingimento'), + 'WaterDrawingFees-delete' => __('ha cancellato un canone alla Pratica di Attingimento'), + 'WaterDrawingMeters-add' => __('ha inserito uno strumento di misura alla Pratica di Attingimento'), + 'WaterDrawingMeters-edit' => __('ha aggiornato un strumento di misura alla Pratica di Attingimento'), + 'WaterDrawingMeters-delete' => __('ha cancellato un strumento di misura alla Pratica di Attingimento'), + 'WaterDrawingMeasurements-add' => __('ha inserito una misurazione alla Pratica di Attingimento'), + 'WaterDrawingMeasurements-delete' => __('ha cancellato una misurazione alla Pratica di Attingimento'), + 'WaterDrawingReturnPoints-add' => __('ha inserito un punto di restituzione alla Pratica di Attingimento'), + 'WaterDrawingReturnPoints-edit' => __('ha aggiornato un punto di restituzione alla Pratica di Attingimento'), + 'WaterDrawingReturnPoints-delete' => __('ha cancellato un punto di restituzione alla Pratica di Attingimento'), + ]; + return $controller_action_descriptions[$controller_action] ?? ''; + } + + /** + * getUnpackedWaterDrawingPaperworkSnapshot + * + * @param Int $snapshot_id + * @return UnpackedWaterDrawingPaperworkSnapshot!Null + */ + public static function getUnpackedWaterDrawingPaperworkSnapshot(Int $snapshot_id): ?UnpackedWaterDrawingPaperworkSnapshot + { + $co = SnapshotsHandler::getControllableObjectFromSnapshotWithId($snapshot_id); + if (!$co) return null; + + $snapshot = TableRegistry::getTableLocator()->get('Snapshots') + ->find() + ->contain(['Users' => ['Actors', 'Organisations' => ['Actors']]]) + ->where(['Snapshots.id' => $snapshot_id]) + ->first(); + + if (!$snapshot) return null; + + $unpacked_water_drawing_paperwork_snapshot = []; + + // Inizializzazione valori di base: + $unpacked_water_drawing_paperwork_snapshot['snapshot_id'] = $snapshot_id; + $unpacked_water_drawing_paperwork_snapshot['unpacking_version'] = SnapshotsHandler::getLastWaterDrawingPaperworkUnpackingVersion(); + $unpacked_water_drawing_paperwork_snapshot['who'] = $snapshot->user?->name. ' ' . $snapshot->user?->surname; + $unpacked_water_drawing_paperwork_snapshot['when'] = isset($snapshot->date) ? new DateTime($snapshot->date->format("Y-m-d H:i:s")) : null; + $unpacked_water_drawing_paperwork_snapshot['what'] = SnapshotsHandler::getSnapshotControllerActionDescription($snapshot->controller_action); + + // Inizializzazione valori presi da oggetto 'root' (controllable_object): + $creator_organisation = isset($co->creator->organisation->actor->description) ? " (" . $co->creator->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['creator'] = $co->creator->name . ' ' . $co->creator->surname . $creator_organisation; + $unpacked_water_drawing_paperwork_snapshot['created'] = isset($co->created) ? new DateTime($co->created->format("Y-m-d H:i:s")) : null; + $modifier_organisation = isset($co->modifier->organisation->actor->description) ? " (" . $co->modifier->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['modifier'] = $co->modifier->name . ' ' . $co->modifier->surname . $modifier_organisation; + $unpacked_water_drawing_paperwork_snapshot['modified'] = isset($co->modified) ? new DateTime($co->modified->format("Y-m-d H:i:s")) : null; + + // Inizializzazione valori presi da specializzazione oggetto (water_drawing_paperwork): + $unpacked_water_drawing_paperwork_snapshot['water_drawing_paperwork_id'] = $co->water_drawing_paperwork->id; + $unpacked_water_drawing_paperwork_snapshot['water_drawing_paperwork_status'] = $co->water_drawing_paperwork->water_drawing_paperwork_status->description; + $gc_user_organisation = isset($co->water_drawing_paperwork->gc_user->organisation->actor->description) ? " (" . $co->water_drawing_paperwork->gc_user->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['gc_user'] = $co->water_drawing_paperwork->gc_user?->name . ' ' . $co->water_drawing_paperwork->gc_user?->surname . $gc_user_organisation; + $drar_user_organisation = isset($co->water_drawing_paperwork->drar_user->organisation->actor->description) ? " (" . $co->water_drawing_paperwork->drar_user->organisation->actor->description . ")" : ""; + $unpacked_water_drawing_paperwork_snapshot['drar_user'] = $co->water_drawing_paperwork->drar_user?->name . ' ' . $co->water_drawing_paperwork->drar_user?->surname . $drar_user_organisation; + + return TableRegistry::getTableLocator()->get('UnpackedWaterDrawingPaperworkSnapshots')->newEntity($unpacked_water_drawing_paperwork_snapshot); + } +} diff --git a/idrocap_wa/src/WGS/Utils/Attachments/AttachmentChecker.php b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentChecker.php new file mode 100644 index 0000000..6efd1d8 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentChecker.php @@ -0,0 +1,27 @@ + 1 ? strtolower($file_name_parts[count($file_name_parts) - 1]) : ''; + // if (!in_array($file_name_extension, ["txt", "pdf", "jpg", "png"])) throw new \Exception(__('Allegato "{0}" non valido! Estensione file "{1}" non ammessa!', $attachment['name'], $file_name_extension)); + // if (!in_array(mime_content_type($attachment['tmp_name']), ["text/plain", "application/pdf", "image/jpeg", "image/png"])) throw new \Exception(__('Allegato "{0}" non ammesso! Tipo dichiarato: "{1}", tipo realmente riscontrato: "{2}". Dimensioni: "{3} bytes"', $attachment['name'], $attachment['type'], mime_content_type($attachment['tmp_name']), $attachment['size'])); + } else { + if (!$skip_form_check) throw new \Exception(__('L\'allegato "{0}" non risulta caricato correttamente tramite apposita funzione nel form!', $attachment['name'])); + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Utils/Attachments/AttachmentConverter.php b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentConverter.php new file mode 100644 index 0000000..5553c13 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Attachments/AttachmentConverter.php @@ -0,0 +1,39 @@ +getError() === 0) { + return [ + 'name' => $attachment->getClientFilename(), + 'size' => $attachment->getSize(), + 'tmp_name' => $attachment->getStream()->getMetadata('uri'), + 'type' => $attachment->getClientMediaType(), + 'error' => $attachment->getError(), + ]; + } else { + return [ + 'name' => '', + 'size' => '', + 'tmp_name' => '', + 'type' => '', + 'error' => $attachment->getError(), + ]; + } + } +} \ No newline at end of file diff --git a/idrocap_wa/src/WGS/Utils/Attachments/SignedAttachmentChecker.php b/idrocap_wa/src/WGS/Utils/Attachments/SignedAttachmentChecker.php new file mode 100644 index 0000000..4d03d42 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Attachments/SignedAttachmentChecker.php @@ -0,0 +1,133 @@ + il path del file firmato da controllare + * $signer_fiscal_code -----------------------------------> il CF che dovrebbe essere presente nella firma (dentro il certificato) + * $signer_description -----------------------------------> descrizione del firmatario in base al contesto + * $certificate_expired_if_expires_within_seconds -> il lasso di tempo espresso in secondi entro il quale + * il certificato DEVE essere ancora valido per non considerarlo SCADUTO + * valore di default 1 ora (86400 seconds) + * + * @param String $signed_attachment + * @param String $signer_fiscal_code + * @param String $signer_description + * @param String $certificate_expired_if_expires_within_seconds + * @return Bool|String + */ + public static function check_cades(String $signed_attachment, String $signer_fiscal_code, String $signer_description, String $certificate_expired_if_expires_within_seconds = '86400'): Bool|String + { + $command = null; + $output = null; + $result_code = null; + + // Verifica formale firma: + $tmpfname = tempnam(sys_get_temp_dir(), 'signed_file_content_'); + $command = "openssl cms -verify -noverify -in $signed_attachment -inform DER -out $tmpfname"; + exec($command, $output, $result_code); + unlink($tmpfname); + unset($output); + if ($result_code) return __('Verifica formale della firma fallita!'); + + // Estrazione del certificato PEM allegato al file firmato: + $signed_file_certificate = tempnam(sys_get_temp_dir(), 'signed_file_certificate_'); + $command = "openssl pkcs7 -inform DER -in $signed_attachment -print_certs -out $signed_file_certificate"; + exec($command, $output, $result_code); + unset($output); + if ($result_code) { + unlink($signed_file_certificate); + return __('Impossibile estrarre il certificato dal file firmato!'); + } + + // Verifica formale del certificato PEM estratto: + $command = "openssl x509 -in $signed_file_certificate -noout"; + exec($command, $output, $result_code); + unset($output); + if ($result_code) { + unlink($signed_file_certificate); + return __('Certificato formalmente non valido!'); + } + + // Verifica se il certificato PEM estratto scadrà entro i prossimi "$certificate_expired_if_expires_within_seconds" secondi: + $command = "openssl x509 -in $signed_file_certificate -noout -checkend $certificate_expired_if_expires_within_seconds"; + exec($command, $output, $result_code); + unset($output); + if ($result_code) { + unlink($signed_file_certificate); + $hours = $certificate_expired_if_expires_within_seconds / 3600; + return __("Certificato scaduto o in scadenza nelle prossime $hours ore!"); + } + + // Verifica formale del certificato PEM estratto ed estrazione attributi del firmatario (ultimo subject nella chain!): + $command = "awk 'BEGIN {c=0; out=\"\"} /BEGIN CERTIFICATE/ {c++; out=\"\";} {out = out \$0 ORS} /END CERTIFICATE/ {last=out;} END {print last}' $signed_file_certificate | openssl x509 -noout -subject"; + exec($command, $output, $result_code); + if ($result_code) { + unlink($signed_file_certificate); + return __('Errore durante l\'estrazione delle informazioni del soggetto firmatario dal certificato!'); + } + + // Estrazione del CODICE FISCALE dal certificato PEM estratto: + $certificate_fiscal_code = self::extract_fiscal_code_from_certificate_subject_row($output[0]); + if (!$certificate_fiscal_code) { + unlink($signed_file_certificate); + return __('Errore durante l\'estrazione del Codice Fiscale dal certificato!'); + } + + // Controlliamo se il CODICE FISCALE preso dal certificato PEM estratto coincide con quello passato: + if ($certificate_fiscal_code != $signer_fiscal_code) { + unlink($signed_file_certificate); + return __("Il Codice Fiscale del firmatario del documento non corrisponde a quello del $signer_description!"); + } + + // Tutto OK! + unlink($signed_file_certificate); + return true; + } + + /** + * extract_certificate_subject_fiscal_code + * + * @param String $certificate_attributes + * @return ?String + */ + private static function extract_fiscal_code_from_certificate_subject_row(String $certificate_subject_row): ?String { + // estrazione CF con subject preceduto da "TINIT-": + $serial_number_start_index = strpos($certificate_subject_row, "TINIT-"); + if ($serial_number_start_index !== false) return substr($certificate_subject_row, $serial_number_start_index + 6, 16); + // estrazione CF con subject preceduto da "CN=": + $serial_number_start_index = strpos($certificate_subject_row, "CN="); + if ($serial_number_start_index !== false) return substr($certificate_subject_row, $serial_number_start_index + 3, 16); + return null; + } + + /** + * check_pades + * + * controlla la firma di un file in formato PAdES + * + * $signed_attachment -----------------------------> il path del file firmato da controllare + * $signer_fiscal_code -----------------------------------> il CF che dovrebbe essere presente nella firma (dentro il certificato) + * $signer_description -----------------------------------> descrizione del firmatario in base al contesto + * $certificate_expired_if_expires_within_seconds -> il lasso di tempo espresso in secondi entro il quale + * il certificato DEVE essere ancora valido per non considerarlo SCADUTO + * valore di default 1 ora (86400 seconds) + * + * @param mixed $signed_attachment + * @param mixed $signer_fiscal_code + * @param String $signer_description + * @param mixed $certificate_expired_if_expires_within_seconds + * @return Bool|String + */ + public static function check_pades(String $signed_attachment, String $signer_fiscal_code, String $signer_description, String $certificate_expired_if_expires_within_seconds = '86400'): Bool|String + { + return true; + } +} diff --git a/idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/DistrictCellDto.php b/idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/DistrictCellDto.php new file mode 100644 index 0000000..7c6c5f5 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Dto/ProvinceDistrictCellDto/DistrictCellDto.php @@ -0,0 +1,25 @@ +showAlert; + } + + public function setShowAlert(bool $showAlert): CitizenRegistrationDTO + { + $this->showAlert = $showAlert; + return $this; + } + + public function getFiscalCode(): string + { + return $this->fiscalCode; + } + + public function setFiscalCode(string $fiscalCode): CitizenRegistrationDTO + { + $this->fiscalCode = $fiscalCode; + return $this; + } + + public function getName(): string + { + return $this->name; + } + + public function setName(string $name): CitizenRegistrationDTO + { + $this->name = $name; + return $this; + } + + public function getSurname(): string + { + return $this->surname; + } + + public function setSurname(string $surname): CitizenRegistrationDTO + { + $this->surname = $surname; + return $this; + } + + public function getGender(): string + { + return $this->gender; + } + + public function setGender(string $gender): CitizenRegistrationDTO + { + $this->gender = $gender; + return $this; + } + + public function getBirthdate(): string + { + return !empty($this->birthdate) ? new DateTime($this->birthdate)->format('Y-m-d') : ''; + } + + public function setBirthdate(string $birthdate): CitizenRegistrationDTO + { + $this->birthdate = $birthdate; + return $this; + } +} diff --git a/idrocap_wa/src/WGS/Utils/Enum/InputFieldType.php b/idrocap_wa/src/WGS/Utils/Enum/InputFieldType.php new file mode 100644 index 0000000..865db54 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Enum/InputFieldType.php @@ -0,0 +1,8 @@ +name, $fullName) === 0) { + return "GC " . $case->value; + } + } + + return null; + } +} diff --git a/idrocap_wa/src/WGS/Utils/Helper/ProvinceDistrictFieldHelper.php b/idrocap_wa/src/WGS/Utils/Helper/ProvinceDistrictFieldHelper.php new file mode 100644 index 0000000..4239838 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/Helper/ProvinceDistrictFieldHelper.php @@ -0,0 +1,44 @@ +value; + } + + public static function withAlias(string $alias, ProvinceDistrictFields $field): string + { + return "{$alias}.{$field->value}"; + } + + public static function forDistricts(ProvinceDistrictFields $field): string + { + return self::withAlias('Districts', $field); + } + + public static function forCounties(ProvinceDistrictFields $field): string + { + return self::withAlias('Counties', $field); + } + + public static function getCodeRegByRegion(Regions $region): int + { + $regionKey = $region->value; + $configMap = Configure::read("App.mapConfig.cod_reg", []); + + if (!isset($configMap[$regionKey])) { + throw new Exception("Region '{$regionKey}' not found in AppConfig."); + } + + return $configMap[$regionKey]; + } +} diff --git a/idrocap_wa/src/WGS/Utils/RabbitMQSenders/IntendedUseVegetationCheckCommandSender.php b/idrocap_wa/src/WGS/Utils/RabbitMQSenders/IntendedUseVegetationCheckCommandSender.php new file mode 100644 index 0000000..c1a8a31 --- /dev/null +++ b/idrocap_wa/src/WGS/Utils/RabbitMQSenders/IntendedUseVegetationCheckCommandSender.php @@ -0,0 +1,28 @@ +channel(); + $channel->queue_declare($queue, false, true, false, false); + $msg = new AMQPMessage(json_encode($m), ['delivery_mode' => 2]); + $channel->basic_publish($msg, '', $queue); + $channel->close(); + $connection->close(); + } +} \ No newline at end of file diff --git a/idrocap_wa/templates/Applicants/citizen_add.php b/idrocap_wa/templates/Applicants/citizen_add.php new file mode 100644 index 0000000..ab25410 --- /dev/null +++ b/idrocap_wa/templates/Applicants/citizen_add.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Creazione Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'disabled' => true, 'value' => $user->name]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'disabled' => true, 'value' => $user->surname]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'disabled' => true, 'value' => $user->tax_code]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true, 'value' => $user->address]); + echo $this->Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'required' => true, 'value' => $user->city]); + echo $this->Form->control('province', ['label' => __('Provincia'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Applicants/citizen_edit.php b/idrocap_wa/templates/Applicants/citizen_edit.php new file mode 100644 index 0000000..f63b258 --- /dev/null +++ b/idrocap_wa/templates/Applicants/citizen_edit.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Creazione Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'disabled' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'disabled' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'disabled' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('province', ['label' => __('Provincia'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Applicants/citizen_view.php b/idrocap_wa/templates/Applicants/citizen_view.php new file mode 100644 index 0000000..6376615 --- /dev/null +++ b/idrocap_wa/templates/Applicants/citizen_view.php @@ -0,0 +1,63 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Dettagli Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('province', ['label' => __('Provincia'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ Form->end(); + ?> + +
+ diff --git a/idrocap_wa/templates/Applicants/edit.php b/idrocap_wa/templates/Applicants/edit.php new file mode 100644 index 0000000..b10c9b5 --- /dev/null +++ b/idrocap_wa/templates/Applicants/edit.php @@ -0,0 +1,71 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: 'province', + fieldName: 'province', + formContext: $applicant ?? null, + fieldRequired: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->province ?? null, + ), + new DistrictCellDto( + fieldId: 'district', + fieldName: 'district', + provinceFieldId: "province", + fieldRequired: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->district ?? null, + entity: $applicant ?? null, + ) + ] + ); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Applicants/view.php b/idrocap_wa/templates/Applicants/view.php new file mode 100644 index 0000000..60a8863 --- /dev/null +++ b/idrocap_wa/templates/Applicants/view.php @@ -0,0 +1,72 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Concessionario'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('name', ['label' => __('Nome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('surname', ['label' => __('Cognome'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('tax_code', ['label' => __('Codice fiscale'), 'type' => 'text', 'required' => true]); + echo $this->Form->control('company_name', ['label' => __('Ragione sociale'), 'type' => 'text']); + echo $this->Form->control('vat_number', ['label' => __('Partita IVA'), 'type' => 'text']); + echo $this->Form->control('address', ['label' => __('Indirizzo'), 'type' => 'text', 'required' => true]); + echo $this->Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: 'province', + fieldName: 'province', + formContext: $applicant ?? null, + fieldRequired: true, + disabled: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->province ?? null, + ), + new DistrictCellDto( + fieldId: 'district', + fieldName: 'district', + fieldRequired: true, + disabled: true, + fieldContainerClass: "mb-3", + fieldValue: $applicant->district ?? null, + ) + ] + ); + echo $this->Form->control('pec_address', ['label' => __('Indirizzo PEC'), 'type' => 'text']); + echo $this->Form->control('email_address', ['label' => __('Indirizzo email'), 'type' => 'text']); + ?> +
+ Form->end(); + ?> +
+ diff --git a/idrocap_wa/templates/Capabilities/index.php b/idrocap_wa/templates/Capabilities/index.php new file mode 100644 index 0000000..def20e9 --- /dev/null +++ b/idrocap_wa/templates/Capabilities/index.php @@ -0,0 +1,85 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Gestione competenze'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ +

+
+
+
+
+ +
+ +
+
+
+
+
+ + + + + + + + + + + + + is_configurable ? $style .= 'background-color:#bfbddc;' : ''; + isset($capability->deleted) ? $style .= 'color:red; text-decoration:line-through;' : ''; + $style .= '"'; + + $title = 'title="'; + !$capability->is_configurable ? $title .= __('Competenza non visibile e non configurabile dai non SYSADMIN') . ' ' : ''; + isset($capability->deleted) ? $title .= __('Competenza eliminata dal sistema') : ''; + $title .= '"'; + ?> + > + + + + + + + + +
Paginator->sort('description',__('Descrizione')) ?>Paginator->sort('value', __('Codice')) ?>Paginator->sort('priority', __('Priorità')) ?>Paginator->sort('CapabilityGroups.description', __('Gruppo')) ?>
description) ?>value) ?>priority) ?>capability_group->description) ?> + Form->postLink($capability->is_configurable ? __('Nascondi') : __('Mostra'), ['action' => $capability->is_configurable ? 'hide' : 'show', $capability->id, '?' => $this->request->getQueryParams()], ['class'=>'btn btn-warning btn-xs']) ?> + Form->postLink(isset($capability->deleted) ? __('Ripristina') : __('Cancella'), ['action' => isset($capability->deleted) ? 'restore' : 'delete', $capability->id, '?' => $this->request->getQueryParams()], ['class'=>'btn btn-danger btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/ControllableObjects/get_attachments.php b/idrocap_wa/templates/ControllableObjects/get_attachments.php new file mode 100755 index 0000000..6eb1eb3 --- /dev/null +++ b/idrocap_wa/templates/ControllableObjects/get_attachments.php @@ -0,0 +1,119 @@ + + + + +
+
+

+ 0) ? __('Allegati presenti: {0}', $numberOfAttachments) : __('Nessun Allegato presente') ?> +

+
+
+ + + + + + + + + + + + + + + + + controllable_object->modified))->wasWithinLast('5 minutes') ? "font-weight: bold;background-color:#f8d716" : ""; + ?> + + '; + if($attachment->private) + { + $htmlCode = ''; + } + ?> + + + + + + + + + + + + +
Paginator->sort('Attachments.private', '', ['escape' => false]) ?>';?>Paginator->sort('Attachments.original_file_name', __('Nome')) ?>Paginator->sort('Attachments.relevant', '', ['escape' => false]) ?>Paginator->sort('Attachments.original_file_size', __('Dimensione')) ?>Paginator->sort('Attachments.mimetype', __('Tipo')) ?>Paginator->sort('Attachments.upload_date', __('Caricato il')) ?>Paginator->sort('Creator.surname', __('Da')) ?>
original_file_name) ?>relevant ? '' : '' ?>human_original_file_size) ?>mimetype) ?>upload_date) ?>controllable_object->creator) ?> + Html->link(__('Visualizza'), ['controller' => 'attachments', 'action' => 'view', $attachment->file_name], ['target' => '_blank', 'class' => 'btn btn-info btn-xs', 'style' => 'margin-right: 5px;', 'data-mimetype' => $attachment->mimetype]); + if (isset($removecurrentfiles) && $removecurrentfiles == "true") { + echo $this->Html->link(__('Segna da eliminare'), ['controller' => 'attachments', 'action' => 'markAsDeleted', $attachment->controllable_object_id], ['target' => '_blank', 'class' => 'btn btn-danger btn-xs', 'style' => 'margin-right: 5px;']); + } else { + echo $this->Html->link($attachment->relevant ? __('Segna come non rilevante') : __('Segna come rilevante'), ['controller' => 'attachments', 'action' => 'markAsRelevant', $attachment->file_name], ['id' => $attachment->controllable_object_id, 'target' => '_blank', 'class' => 'btn btn-warning btn-xs', 'style' => 'margin-right: 5px;']); + } + ?> +
+
+ +
diff --git a/idrocap_wa/templates/Dashboard/index.php b/idrocap_wa/templates/Dashboard/index.php new file mode 100644 index 0000000..6b392db --- /dev/null +++ b/idrocap_wa/templates/Dashboard/index.php @@ -0,0 +1,32 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + ], + ]); +?> +
+
+

+ +

+
+
+ Cell('Map', [ + [-1, -5], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + null, // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+ +
+ \ No newline at end of file diff --git a/idrocap_wa/templates/Deliveries/index.php b/idrocap_wa/templates/Deliveries/index.php new file mode 100644 index 0000000..7a45ddb --- /dev/null +++ b/idrocap_wa/templates/Deliveries/index.php @@ -0,0 +1,284 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description); ?> +

+
+
+ + + + + +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
mobile_phone_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'MobilePhones', 'action' => 'edit', $mobile_phone->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $mobile_phone->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare il Cellulare "{0}" ?', $mobile_phone->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
fax_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'Faxes', 'action' => 'edit', $fax->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $fax->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare il Fax "{0}" ?', $fax->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
email_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'Emails', 'action' => 'edit', $email->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $email->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'Email "{0}" ?', $email->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + +
phone_description->description) ?>value) ?> + Html->link(__('Modifica'), ['controller' => 'Phones', 'action' => 'edit', $phone->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $phone->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare il Telefono "{0}" ?', $phone->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + +
value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'TelegramChats', 'action' => 'edit', $telegram_chat->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $telegram_chat->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare la Chat Telegram con ID "{0}" ?', $telegram_chat->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ + +
+
+

+ count()); ?> +

+
+
+ + + + + + + + + + + + + + + + + + + +
pec_description->description) ?>value) ?>enable_notifications ? __('SI') : __('NO') ?> + Html->link(__('Modifica'), ['controller' => 'Pecs', 'action' => 'edit', $pec->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + Form->postLink(__('Cancella'), ['action' => 'delete', $pec->delivery_id], ['confirm' => __('Sei sicuro che vuoi cancellare la PEC "{0}" ?', $pec->value), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Emails/add.php b/idrocap_wa/templates/Emails/add.php new file mode 100644 index 0000000..a0c6040 --- /dev/null +++ b/idrocap_wa/templates/Emails/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Email'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($email, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Email')]); + echo $this->Form->control('email_description_id', ['label' => __('Descrizione'), 'options' => $emailDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Emails/edit.php b/idrocap_wa/templates/Emails/edit.php new file mode 100644 index 0000000..a3cc434 --- /dev/null +++ b/idrocap_wa/templates/Emails/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Email'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $email->delivery->actor->description) ?> +

+
+ Form->create($email, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Email')]); + echo $this->Form->control('email_description_id', ['label' => __('Descrizione'), 'options' => $emailDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Error/error400.php b/idrocap_wa/templates/Error/error400.php new file mode 100644 index 0000000..eeaa6f9 --- /dev/null +++ b/idrocap_wa/templates/Error/error400.php @@ -0,0 +1,49 @@ +layout = 'default'; + +if (Configure::read('debug')) : + $this->layout = 'dev_error'; + + $this->assign('title', $message); + $this->assign('templateName', 'error400.php'); + + $this->start('file'); +?> +queryString)) : ?> +

+ SQL Query: + queryString) ?> +

+ +params)) : ?> + SQL Query Params: + params) ?> + +element('auto_table_warning') ?> +end(); +endif; +?> +
+
+
+
+
+
+
+
+

+

'{$url}'") ?>

+

+
+

Html->link(__('Torna indietro'), 'javascript:history.back()') ?>

diff --git a/idrocap_wa/templates/Error/error500.php b/idrocap_wa/templates/Error/error500.php new file mode 100644 index 0000000..8f52f47 --- /dev/null +++ b/idrocap_wa/templates/Error/error500.php @@ -0,0 +1,53 @@ +layout = 'default'; + +if (Configure::read('debug')) : + $this->layout = 'dev_error'; + + $this->assign('title', $message); + $this->assign('templateName', 'error500.php'); + + $this->start('file'); +?> +queryString)) : ?> +

+ SQL Query: + queryString) ?> +

+ +params)) : ?> + SQL Query Params: + params) ?> + + + Error in: + getFile()), $error->getLine()) ?> + +element('auto_table_warning'); + + $this->end(); +endif; +?> +
+
+
+
+
+
+
+
+

+

'{$url}'") ?>

+

+
+

Html->link(__('Torna indietro'), 'javascript:history.back()') ?>

diff --git a/idrocap_wa/templates/Faxes/add.php b/idrocap_wa/templates/Faxes/add.php new file mode 100644 index 0000000..cb3250e --- /dev/null +++ b/idrocap_wa/templates/Faxes/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Fax'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($fax, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Fax')]); + echo $this->Form->control('fax_description_id', ['label' => __('Descrizione'), 'options' => $faxDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Faxes/edit.php b/idrocap_wa/templates/Faxes/edit.php new file mode 100644 index 0000000..8a37561 --- /dev/null +++ b/idrocap_wa/templates/Faxes/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Fax'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $fax->delivery->actor->description) ?> +

+
+ Form->create($fax, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Fax')]); + echo $this->Form->control('fax_description_id', ['label' => __('Descrizione'), 'options' => $faxDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Filters/get_filter_input.php b/idrocap_wa/templates/Filters/get_filter_input.php new file mode 100644 index 0000000..b159ed8 --- /dev/null +++ b/idrocap_wa/templates/Filters/get_filter_input.php @@ -0,0 +1 @@ +Cell('FilterInput', [$filter_id]) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Groups/add.php b/idrocap_wa/templates/Groups/add.php new file mode 100644 index 0000000..c385218 --- /dev/null +++ b/idrocap_wa/templates/Groups/add.php @@ -0,0 +1,61 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Nuovo Profilo Utente'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($group, ['role' => 'form']); ?> +
+ Form->control('description', ['label' => __('Descrizione')]); + echo $this->Form->control('is_default', ['label' => __('Profilo Default')]); + echo $this->Form->control('child_groups._ids', ['label' => __('Profili associati'), 'options' => $child_groups, 'multiple' => true, 'style="width: 100%']); + ?> +
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/Groups/edit.php b/idrocap_wa/templates/Groups/edit.php new file mode 100644 index 0000000..a3fe706 --- /dev/null +++ b/idrocap_wa/templates/Groups/edit.php @@ -0,0 +1,66 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Profilo Utente'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'groups', 'action' => 'view', $group->id], + ], + [ + 'title' => __('Modifica Profilo Utente'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+
+ Form->create($group, ['role' => 'form']); ?> +
+ Form->control('description', ['label' => __('Descrizione')]); + echo $this->Form->control('is_default', ['label' => __('Profilo Default')]); + echo $this->Form->control('child_groups._ids', ['label' => __('Profili associati'), 'options' => $child_groups, 'multiple' => true, 'style="width: 100%']); + ?> +
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/Groups/handle_capabilities.php b/idrocap_wa/templates/Groups/handle_capabilities.php new file mode 100644 index 0000000..9f87622 --- /dev/null +++ b/idrocap_wa/templates/Groups/handle_capabilities.php @@ -0,0 +1,75 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Profilo Utente'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'groups', 'action' => 'view', $group->id], + ], + [ + 'title' => __('Gestione competenze'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ description) ?> +

+
+ + Form->create($group, ['role' => 'form']); ?> +
+ Form->control('description', ['type' => 'hidden']); + ?> +
+ + capabilities) > 0): ?> +
+ description); ?> + + + capabilities as $capability): ?> + id; ?> + + + + + + + +
is_configurable ? 'style="background-color:#bfbddc;" title="' . __('Competenza non visibile e non configurabile dai non SYSADMIN') . '"' : '' ?>>priority == 1 ? $this->Form->control('capabilities._ids[]', ['id' => "capability-id-$capability_id", 'value' => $capability->id, 'label' => $capability->description . (isset($capability->longdescription) ? ' (' . $capability->longdescription . ')' : ''), 'type' => 'checkbox', 'required' => false, 'checked' => in_array($capability->id, $group_capability_ids)]) : '' ?>is_configurable ? 'style="background-color:#bfbddc;" title="' . __('Competenza non visibile e non configurabile dai non SYSADMIN') . '"' : '' ?>>priority == 2 ? $this->Form->control('capabilities._ids[]', ['id' => "capability-id-$capability_id", 'value' => $capability->id, 'label' => $capability->description . (isset($capability->longdescription) ? ' (' . $capability->longdescription . ')' : ''), 'type' => 'checkbox', 'required' => false, 'checked' => in_array($capability->id, $group_capability_ids)]) : '' ?>is_configurable ? 'style="background-color:#bfbddc;" title="' . __('Competenza non visibile e non configurabile dai non SYSADMIN') . '"' : '' ?>>priority == 3 ? $this->Form->control('capabilities._ids[]', ['id' => "capability-id-$capability_id", 'value' => $capability->id, 'label' => $capability->description . (isset($capability->longdescription) ? ' (' . $capability->longdescription . ')' : ''), 'type' => 'checkbox', 'required' => false, 'checked' => in_array($capability->id, $group_capability_ids)]) : '' ?>
+
+ + +
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Groups/index.php b/idrocap_wa/templates/Groups/index.php new file mode 100644 index 0000000..2bc379f --- /dev/null +++ b/idrocap_wa/templates/Groups/index.php @@ -0,0 +1,63 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('description',__('Descrizione')) ?>Paginator->sort('is_default', __('Profilo Default')) ?>
description) ?>is_default ? __('SI') : __('NO') ?>child_groups_csv ?> + Html->link(__('Dettaglio'), ['action' => 'view', $group->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $group->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $group->id], ['confirm' => __('Sei sicuro che vuoi cancellare il profilo "{0}" ?', $group->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Groups/view.php b/idrocap_wa/templates/Groups/view.php new file mode 100644 index 0000000..90a714e --- /dev/null +++ b/idrocap_wa/templates/Groups/view.php @@ -0,0 +1,45 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei Profili Utente'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'groups', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Profilo Utente'), + 'icon' => 'fa fa-info', + ], + ]); +?> + +
+
+

+
+
+
+
+
description) ?>
+
+
is_default ? __('SI') : __('NO') ?>
+
+
child_groups_csv ?>
+
+
+ +
diff --git a/idrocap_wa/templates/Maps/index.php b/idrocap_wa/templates/Maps/index.php new file mode 100644 index 0000000..3cc1f79 --- /dev/null +++ b/idrocap_wa/templates/Maps/index.php @@ -0,0 +1,149 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => 'Mappe', + 'icon' => 'fa fa-map', + ], + ]); +?> + +
+
+

+ +

+
+
+ Form->control('feature_collection', ['type' => 'text', 'readonly' => true, 'label' => __('Campo esistente appartenente al form ospite'), 'id' => 'feature-collection-custom1', 'value' => '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[14.379508819839112,37.75776939310461],[15.079779119829889,37.74925139070119],[14.74580405368044,37.227801841878815],[14.379508819839112,37.75776939310461]]]},"properties":null},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[13.302169896776373,37.83438727544886],[13.33565484759548,37.8721796404016],[13.359158669099903,37.9143809499671],[13.371778122610326,37.95936327940137],[13.373028249605412,38.00539445333166],[13.362861008405815,38.0507051513184],[13.341667120388989,38.09355695996422],[13.310261054785746,38.13230874682358],[13.269849729084495,38.165478870642175],[13.221986127869002,38.19180096750125],[13.168509622491761,38.21027134460931],[13.111475285064454,38.220186354514],[13.053074913189183,38.221168496367],[12.995552800405811,38.213180384842815],[12.941119489249829,38.19652613223133],[12.89186682134241,38.17184009894592],[12.849687549090019,38.140063377845536],[12.816202598270912,38.10240878417548],[12.792698776766489,38.06031551994914],[12.780079323256066,38.01539506079607],[12.77882919626098,37.96937016275294],[12.788996437460577,37.924009190796056],[12.810190325477404,37.881058212202475],[12.841596391080646,37.84217345733417],[12.8820077167819,37.80885681076607],[12.92987131799739,37.782396943193774],[12.983347823374631,37.76381852162746],[13.040382160801938,37.75384164211793],[13.098782532677207,37.75285322445332],[13.156304645460581,37.76089160937822],[13.210737956616564,37.77764503105661],[13.259990624523983,37.80246403167463],[13.302169896776373,37.83438727544886]]]},"properties":null},{"type":"Feature","geometry":{"type":"Point","coordinates":[14.00244019676715,37.71516957586901]},"properties":null}]}']); + + echo $this->Cell('Map', [ + [-1], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Evento'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => true, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'feature_collection' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'feature-collection-custom1', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'feature_collection_custom1', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Collezione di geometrie'), + ], + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude-custom2', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude_custom2', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Longitudine'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude-custom3', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude_custom3', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Latitudine'), + ], + 'coordinates' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'coordinates-custom4', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'coordinates_custom4', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinate (Longitudine Latitudine)'), + ], + 'cap' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'cap', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'cap', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Cap'), + ], + 'province' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'province', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'province', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Provincia'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'address', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'address', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Indirizzo'), + ], + 'description' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'description', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'description', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Descrizione luogo'), + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+ +
diff --git a/idrocap_wa/templates/MobilePhones/add.php b/idrocap_wa/templates/MobilePhones/add.php new file mode 100644 index 0000000..5bc4fb9 --- /dev/null +++ b/idrocap_wa/templates/MobilePhones/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Cellulare'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($mobilePhone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Cellulare')]); + echo $this->Form->control('mobile_phone_description_id', ['label' => __('Descrizione'), 'options' => $mobilePhoneDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/MobilePhones/edit.php b/idrocap_wa/templates/MobilePhones/edit.php new file mode 100644 index 0000000..2496d6c --- /dev/null +++ b/idrocap_wa/templates/MobilePhones/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Cellulare'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $mobilePhone->delivery->actor->description) ?> +

+
+ Form->create($mobilePhone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Cellulare')]); + echo $this->Form->control('mobile_phone_description_id', ['label' => __('Descrizione'), 'options' => $mobilePhoneDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Notifications/index.php b/idrocap_wa/templates/Notifications/index.php new file mode 100644 index 0000000..601379c --- /dev/null +++ b/idrocap_wa/templates/Notifications/index.php @@ -0,0 +1,4 @@ +Notifications->create($user_notifications) ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/Notifications/read_all.php b/idrocap_wa/templates/Notifications/read_all.php new file mode 100644 index 0000000..af458c8 --- /dev/null +++ b/idrocap_wa/templates/Notifications/read_all.php @@ -0,0 +1,5 @@ +Notifications->create($user_notifications) ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/Organisations/add.php b/idrocap_wa/templates/Organisations/add.php new file mode 100644 index 0000000..55f90e8 --- /dev/null +++ b/idrocap_wa/templates/Organisations/add.php @@ -0,0 +1,197 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'organisations', 'action' => 'index'], + ], + [ + 'title' => __('Nuova Organizzazione'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($organisation, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('actor.description', ['label' => __('Nome')]); ?> +
+
+ Form->control('acronym', ['label' => __('Acronimo')]); ?> +
+
+ Form->control('organisation_type_id', ['label' => __('Tipo organizzazione'), 'style="width: 100%']); ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Organizzazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'feature_collection' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => true, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => true, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'feature-collection', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'feature_collection', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => null, + ], + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => true, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Longitudine'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => true, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Latitudine'), + ], + 'coordinates' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'coordinates', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'coordinates', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinate (Longitudine Latitudine)'), + ], + 'cap' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'cap', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'cap', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Cap'), + ], + 'province' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'province', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'province', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Provincia'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'address', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'address', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Indirizzo'), + ], + 'description' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'description', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'description', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Descrizione luogo'), + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+
+ Form->control('coordinates', ['label' => __('Coordinate (Longitudine Latitudine)'), 'type' => 'text', 'readonly' => true]); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('district', ['label' => __('Comune')]); ?> +
+
+ Form->control('province', ['label' => __('Provincia')]); ?> +
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/Organisations/edit.php b/idrocap_wa/templates/Organisations/edit.php new file mode 100644 index 0000000..1e94bb6 --- /dev/null +++ b/idrocap_wa/templates/Organisations/edit.php @@ -0,0 +1,118 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'organisations', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Organizzazione'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'organisations', 'action' => 'view', $organisation->id], + ], + [ + 'title' => __('Modifica Organizzazione'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($organisation, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('actor.description', ['label' => __('Nome')]); ?> +
+
+ Form->control('acronym', ['label' => __('Acronimo')]); ?> +
+
+ Form->control('organisation_type_id', ['label' => __('Tipo organizzazione'), 'style="width: 100%']); ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Organizzazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => true, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => true, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => true, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); + ?> +
+
+ Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('coordinates', ['label' => __('Coordinate (Longitudine Latitudine)'), 'type' => 'text', 'readonly' => true]); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('district', ['label' => __('Comune')]); ?> +
+
+ Form->control('province', ['label' => __('Provincia')]); ?> +
+ +
+ controllable_object_interface)) { + $attachment_options = [ + 'filepicker' => true, + 'coId' => $organisation->controllable_object_interface->controllable_object_id, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'view_in_frame_with_id' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]; + } else { + $attachment_options = [ + 'filepicker' => true, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]; + } + echo $this->element('attachments', $attachment_options); + ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/Organisations/index.php b/idrocap_wa/templates/Organisations/index.php new file mode 100644 index 0000000..bdd562c --- /dev/null +++ b/idrocap_wa/templates/Organisations/index.php @@ -0,0 +1,75 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_organisations ? __('{0} su {1}', $filtered_organisations, $total_organisations) : $total_organisations) ?> +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('Actors.description', __('Descrizione')) ?>Paginator->sort('acronym', __('Acronimo')) ?>Paginator->sort('OrganisationTypes.description', __('Tipologia')) ?>Paginator->sort('address', __('Indirizzo')) ?>Paginator->sort('cap', __('CAP')) ?>Paginator->sort('district', __('Comune')) ?>Paginator->sort('province', __('Provincia')) ?>
actor->description) ?>acronym) ?>organisation_type->description) ?>address) ?>cap) ?>district) ?>province) ?>actor->contacts) ?> + Html->link(__('Dettaglio'), ['action' => 'view', $organisation->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $organisation->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $organisation->id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'organizzazione "{0}" ?', $organisation->actor->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Organisations/view.php b/idrocap_wa/templates/Organisations/view.php new file mode 100644 index 0000000..badad7b --- /dev/null +++ b/idrocap_wa/templates/Organisations/view.php @@ -0,0 +1,99 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Organizzazioni'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'organisations', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Organizzazione'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($organisation, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('actor.description', ['label' => __('Nome')]); ?> +
+
+ Form->control('acronym', ['label' => __('Acronimo')]); ?> +
+
+ Form->control('organisation_type_id', ['label' => __('Tipo organizzazione'), 'style="width: 100%', 'disabled' => true]); ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Organizzazione'), + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> +
+
+ Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('coordinates', ['label' => __('Coordinate (Longitudine Latitudine)'), 'type' => 'text']); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('district', ['label' => __('Comune')]); ?> +
+
+ Form->control('province', ['label' => __('Provincia')]); ?> +
+
+ Form->control('deliveries', ['label' => __('Recapiti'), 'type' => 'text', 'value' => $organisation->actor->contacts]); ?> +
+
+ controllable_object_interface)) { + echo $this->element('attachments', [ + 'coId' => $organisation->controllable_object_interface->controllable_object_id, + 'viewer' => true + ]); + } + ?> +
+
+ Form->end(); ?> +
+ +
+ + diff --git a/idrocap_wa/templates/Pecs/add.php b/idrocap_wa/templates/Pecs/add.php new file mode 100644 index 0000000..d6c8b45 --- /dev/null +++ b/idrocap_wa/templates/Pecs/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi PEC'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($pec, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('PEC')]); + echo $this->Form->control('pec_description_id', ['label' => __('Descrizione'), 'options' => $pecDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Pecs/edit.php b/idrocap_wa/templates/Pecs/edit.php new file mode 100644 index 0000000..3bac119 --- /dev/null +++ b/idrocap_wa/templates/Pecs/edit.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica PEC'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $pec->delivery->actor->description) ?> +

+
+ Form->create($pec, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('PEC')]); + echo $this->Form->control('pec_description_id', ['label' => __('Descrizione'), 'options' => $pecDescriptions, 'empty' => false]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Phones/add.php b/idrocap_wa/templates/Phones/add.php new file mode 100644 index 0000000..d5c6e02 --- /dev/null +++ b/idrocap_wa/templates/Phones/add.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Telefono'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($phone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Telefono')]); + echo $this->Form->control('phone_description_id', ['label' => __('Descrizione'), 'options' => $phoneDescriptions, 'empty' => false]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Phones/edit.php b/idrocap_wa/templates/Phones/edit.php new file mode 100644 index 0000000..b346733 --- /dev/null +++ b/idrocap_wa/templates/Phones/edit.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Telefono'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $phone->delivery->actor->description) ?> +

+
+ Form->create($phone, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Telefono')]); + echo $this->Form->control('phone_description_id', ['label' => __('Descrizione'), 'options' => $phoneDescriptions, 'empty' => false]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Privacy/accept_privacy.php b/idrocap_wa/templates/Privacy/accept_privacy.php new file mode 100644 index 0000000..c1ba8d1 --- /dev/null +++ b/idrocap_wa/templates/Privacy/accept_privacy.php @@ -0,0 +1,29 @@ +Breadcrumb->render($breadcrumbs); ?> + +
+
+

+
+ Form->create($privacy, ['role' => 'form']); ?> +
+
+
+ Form->input('description', ['type' => 'textarea', 'id' => 'description']); ?> +
+
+
+ + Form->end(); ?> +
+ +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Privacy/edit.php b/idrocap_wa/templates/Privacy/edit.php new file mode 100644 index 0000000..8ff3081 --- /dev/null +++ b/idrocap_wa/templates/Privacy/edit.php @@ -0,0 +1,24 @@ +Breadcrumb->render($breadcrumbs); ?> + +
+
+

+
+ Form->create($privacy, ['role' => 'form']); ?> +
+
+
+ Form->input('description', ['type' => 'textarea', 'id' => 'description']); ?> +
+
+
+ + Form->end(); ?> +
+ +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Privacy/view.php b/idrocap_wa/templates/Privacy/view.php new file mode 100644 index 0000000..7b723a7 --- /dev/null +++ b/idrocap_wa/templates/Privacy/view.php @@ -0,0 +1,19 @@ +Breadcrumb->render($breadcrumbs); ?> + +
+
+

+
+ Form->create($privacy, ['role' => 'form']); ?> +
+
+
+ Form->input('description', ['type' => 'textarea', 'id' => 'description']); ?> +
+
+
+ Form->end(); ?> +
+ +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Privacy/view_public.php b/idrocap_wa/templates/Privacy/view_public.php new file mode 100644 index 0000000..bc7b4c0 --- /dev/null +++ b/idrocap_wa/templates/Privacy/view_public.php @@ -0,0 +1,10 @@ +Form->create($privacy, ['role' => 'form']); ?> +
+
+ description) ? $this->Form->input('description', ['type' => 'textarea', 'id' => 'description']) : ''; ?> +
+
+Form->end(); ?> + +Html->script(['/js/tinymce/tinymce.min.js']) ?> +Html->script(['/js/init_tiny_mce.js']) ?> \ No newline at end of file diff --git a/idrocap_wa/templates/Tags/add.php b/idrocap_wa/templates/Tags/add.php new file mode 100644 index 0000000..87514ef --- /dev/null +++ b/idrocap_wa/templates/Tags/add.php @@ -0,0 +1,54 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei tags'), + 'icon' => 'fa fa-list', + 'url' => ['action' => 'index'], + ], + [ + 'title' => __('Crea tag'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($tag, ['role' => 'form', 'type' => 'file', 'id' => 'editTag']); ?> +
+
+
+ Form->control('description', ['label' => __('Descrizione')]); ?> +
+
+ Form->control('code', ['label' => __('Codice')]); ?> +
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'required' => true, + 'upload_single' => true, + ]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Tags/edit.php b/idrocap_wa/templates/Tags/edit.php new file mode 100644 index 0000000..73f5144 --- /dev/null +++ b/idrocap_wa/templates/Tags/edit.php @@ -0,0 +1,55 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei tags'), + 'icon' => 'fa fa-list', + 'url' => ['action' => 'index'], + ], + [ + 'title' => __('Modifica tag'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($tag, ['role' => 'form', 'type' => 'file', 'id' => 'editTag']); ?> +
+
+
+ Form->control('description', ['label' => __('Descrizione')]); ?> +
+
+ Form->control('code', ['label' => __('Codice')]); ?> +
+
+ element('attachments', [ + 'coId' => isset($tag->controllable_object_id) ? $tag->controllable_object_id : null, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'required' => false, + 'upload_single' => true, + ]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Tags/index.php b/idrocap_wa/templates/Tags/index.php new file mode 100644 index 0000000..cd61756 --- /dev/null +++ b/idrocap_wa/templates/Tags/index.php @@ -0,0 +1,63 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli tags'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('id',__('Id')) ?>Paginator->sort('description', __('Descrizione')) ?>Paginator->sort('code', __('Codice')) ?>
id) ?>description) ?>code) ?> + Html->link(__('Dettaglio'), ['action' => 'view', $tag->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $tag->id], ['class'=>'btn btn-warning btn-xs']) : null ?> +
+
+ +
+ diff --git a/idrocap_wa/templates/Tags/view.php b/idrocap_wa/templates/Tags/view.php new file mode 100644 index 0000000..23b79de --- /dev/null +++ b/idrocap_wa/templates/Tags/view.php @@ -0,0 +1,52 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista dei tags'), + 'icon' => 'fa fa-list', + 'url' => ['action' => 'index'], + ], + [ + 'title' => __('Dettaglio tag'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($tag, ['role' => 'form', 'type' => 'file', 'id' => 'editTag']); ?> +
+
+
+ Form->control('description', ['label' => __('Descrizione'), 'disabled' => true]); ?> +
+
+ Form->control('code', ['label' => __('Codice'), 'disabled' => true]); ?> +
+
+ element('attachments', [ + 'coId' => $tag->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + ]); ?> +
+
+
+ Form->end(); ?> + +
diff --git a/idrocap_wa/templates/TelegramChats/add.php b/idrocap_wa/templates/TelegramChats/add.php new file mode 100644 index 0000000..6ebc23d --- /dev/null +++ b/idrocap_wa/templates/TelegramChats/add.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Aggiungi Chat Telegram'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+ actor_type->description, $actor->description) ?> +

+
+ Form->create($telegram_chat, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Chat Telegram ID')]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/TelegramChats/edit.php b/idrocap_wa/templates/TelegramChats/edit.php new file mode 100644 index 0000000..f5bdb3d --- /dev/null +++ b/idrocap_wa/templates/TelegramChats/edit.php @@ -0,0 +1,53 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista {0}', $actor->hasValue('organisation') ? __('Organizzazioni') : __('Utenti')), + 'icon' => 'fa fa-list', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio {0}', $actor->hasValue('organisation') ? __('Organizzazione') : __('Utente')), + 'icon' => 'fa fa-info', + 'url' => ['controller' => $actor->hasValue('organisation') ? 'organisations' : 'users', 'action' => 'view', $actor->organisation->id ?? $actor->user->id], + ], + [ + 'title' => __('Gestione recapiti'), + 'icon' => 'fa fa-phone', + 'url' => ['controller' => 'deliveries', 'action' => 'index', $actor->id], + ], + [ + 'title' => __('Modifica Chat Telegram'), + 'icon' => 'fa fa-pencil-alt', + ], + ]); +?> + +
+
+

+ delivery->actor->actor_type->description, $telegram_chat->delivery->actor->description) ?> +

+
+ Form->create($telegram_chat, ['role' => 'form']); ?> +
+ Form->control('value', ['label' => __('Chat Telegram ID')]); + echo $this->Form->control('enable_notifications', ['label' => __('Ricevi notifiche a questo recapito')]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/Users/add.php b/idrocap_wa/templates/Users/add.php new file mode 100644 index 0000000..453d8eb --- /dev/null +++ b/idrocap_wa/templates/Users/add.php @@ -0,0 +1,108 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'users', 'action' => 'index'], + ], + [ + 'title' => __('Nuovo Utente'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($user, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('username', ['label' => __('Nome utente')]); ?> +
+
+ Form->control('name', ['label' => __('Nome')]); ?> +
+
+ Form->control('surname', ['label' => __('Cognome')]); ?> +
+
+ Form->control('tax_code', ['label' => __('Codice Fiscale')]); ?> +
+
+ Form->control('password', ['label' => __('Password')]); ?> +
+
+ Form->control('birthday', ['type' => 'date', 'label' => __('Data di nascita'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('birthplace', ['label' => __('Luogo di nascita')]); ?> +
+
+ Form->control('gender', ['label' => __('Sesso'), 'type' => 'select', 'options' => ['M' => 'M', 'F' => 'F'], 'empty' => false, 'style="width: 100%']); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('city', ['label' => __('Città')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('language_id', ['label' => __('Lingua preferita'), 'style="width: 100%']); ?> +
+
+ Form->control('organisation_id', ['label' => __('Organizzazione'), 'empty' => true, 'style="width: 100%']); ?> +
+
+ Form->control('user_photo', ['label' => __('Foto del profilo (solo jpeg di dimensioni 160x160!)'), 'type' => 'file', 'accept' => '.jpeg']); ?> +
+ +
+ Form->control('groups._ids', ['label' => __('Profili'), 'options' => $groups, 'multiple' => true, 'disabled' => !$can_handle_profiles, 'style="width: 100%']); ?> +
+ +
+
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/Users/add_citizen.php b/idrocap_wa/templates/Users/add_citizen.php new file mode 100644 index 0000000..5429e85 --- /dev/null +++ b/idrocap_wa/templates/Users/add_citizen.php @@ -0,0 +1,256 @@ + +Html->css('/bower_components/select2/dist/css/select2.min'); ?> +
+
+

+
+ Form->create($user, ['role' => 'form', 'type' => 'file', 'id' => 'add-citizen-js']) ?> +
+
+
+ Form->control('username', ['label' => __('Nome utente')]); ?> +
+
+ getName() ?? ''): ?> + Form->control('name', ['label' => __('Nome'), + 'value' => $citizenRegistrationData?->getName() ?? '', + 'readonly' => $citizenRegistrationData?->getName() ? true : false + ]); ?> + + Form->control('name', ['label' => __('Nome'), 'required' => true]); ?> + +
+
+ getSurname() ?? ''): ?> + Form->control('surname', ['label' => __('Cognome'), + 'value' => $citizenRegistrationData?->getSurname() ?? '', + 'readonly' => $citizenRegistrationData?->getSurname() ? true : false + ]); ?> + + Form->control('surname', ['label' => __('Cognome'), 'required' => true]); ?> + +
+
+ getFiscalCode() ?? ''): ?> + Form->control('tax_code', ['label' => __('Codice Fiscale'), + 'value' => $citizenRegistrationData?->getFiscalCode() ?? '', + 'readonly' => $citizenRegistrationData?->getFiscalCode() ? true : false + ]); ?> + + Form->control('tax_code', ['label' => __('Codice Fiscale'), 'required' => true]); ?> + +
+ +
+ Form->control('email', ['label' => __('Email'), 'required' => true, 'type' => 'email']); ?> +
+ +
+ Form->control('password', ['label' => __('Password')]); ?> +
+ +
+ Form->control('confirmPassword', ['label' => __('Conferma password'), 'type' => 'password', 'required' => true]); ?> +
+ +
+ getBirthdate() ?? ''): ?> + Form->control('birthday', ['label' => __('Data di nascita'), + 'type' => 'date', + 'value' => $citizenRegistrationData?->getBirthdate() ?? '', + 'readonly' => $citizenRegistrationData?->getBirthdate() ? true : false + ]); ?> + + Form->control('birthday', ['type' => 'date', 'label' => __('Data di nascita'), 'max' => $today->format('Y-m-d')]); ?> + +
+
+ Form->control('birthplace', ['label' => __('Luogo di nascita')]); ?> +
+
+ getGender() ?? ''): ?> + Form->control('gender', ['label' => __('Sesso'), + 'value' => $citizenRegistrationData?->getGender() ?? '', + 'readonly' => $citizenRegistrationData?->getGender() ? true : false + ]); ?> + + Form->control('gender', ['label' => __('Sesso'), 'type' => 'select', 'options' => ['M' => 'M', 'F' => 'F'], 'empty' => false, 'style="width: 100%']); ?> + + +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('city', ['label' => __('Città')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('language_id', ['label' => __('Lingua preferita'), 'style="width: 100%']); ?> +
+
+ Form->control('user_photo', ['label' => __('Foto del profilo (solo jpeg di dimensioni 160x160!)'), 'type' => 'file', 'accept' => '.jpeg']); ?> +
+
+
+ + Form->end(); ?> +
+ +Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + +Html->script('/bower_components/select2/dist/js/select2.min'); ?> + + + + diff --git a/idrocap_wa/templates/Users/choose_new_password.php b/idrocap_wa/templates/Users/choose_new_password.php new file mode 100644 index 0000000..89aa06c --- /dev/null +++ b/idrocap_wa/templates/Users/choose_new_password.php @@ -0,0 +1,10 @@ +
+ Form->create() ?> +
+ + Form->control('new_password', ['label' => __('Digita la nuova password'), 'type' => 'password']) ?> + Form->control('confirm_new_password', ['label' => __('Ridigita la nuova password'), 'type' => 'password']) ?> +
+ Form->button(__('Salva'), ['class' => 'btn btn-success']); ?> + Form->end() ?> +
\ No newline at end of file diff --git a/idrocap_wa/templates/Users/edit.php b/idrocap_wa/templates/Users/edit.php new file mode 100644 index 0000000..d3c93cd --- /dev/null +++ b/idrocap_wa/templates/Users/edit.php @@ -0,0 +1,112 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Utente'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'users', 'action' => 'view', $user->id], + ], + [ + 'title' => __('Modifica Utente'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($user, ['role' => 'form', 'type' => 'file']) ?> +
+
+
+ Form->control('username', ['label' => __('Nome utente')]); ?> +
+
+ Form->control('name', ['label' => __('Nome')]); ?> +
+
+ Form->control('surname', ['label' => __('Cognome')]); ?> +
+
+ Form->control('tax_code', ['label' => __('Codice Fiscale')]); ?> +
+
+ Form->control('password', ['label' => __('Password')]); ?> +
+
+ Form->control('birthday', ['type' => 'date', 'label' => __('Data di nascita'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('birthplace', ['label' => __('Luogo di nascita')]); ?> +
+
+ Form->control('gender', ['label' => __('Sesso'), 'type' => 'select', 'options' => ['M' => 'M', 'F' => 'F'], 'empty' => false, 'style="width: 100%']); ?> +
+
+ Form->control('address', ['label' => __('Indirizzo')]); ?> +
+
+ Form->control('city', ['label' => __('Città')]); ?> +
+
+ Form->control('cap', ['label' => __('CAP')]); ?> +
+
+ Form->control('language_id', ['label' => __('Lingua preferita'), 'style="width: 100%']); ?> +
+
+ Form->control('organisation_id', ['label' => __('Organizzazione'), 'style="width: 100%']); ?> +
+
+ Form->control('user_photo', ['label' => __('Foto del profilo (solo jpeg di dimensioni 160x160!)'), 'type' => 'file', 'accept' => '.jpeg']); ?> +
+ +
+ Form->control('groups._ids', ['label' => __('Profili'), 'options' => $groups, 'multiple' => true, 'disabled' => !$can_handle_profiles, 'style="width: 100%']); ?> +
+ +
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/Users/index.php b/idrocap_wa/templates/Users/index.php new file mode 100644 index 0000000..0cdd4c0 --- /dev/null +++ b/idrocap_wa/templates/Users/index.php @@ -0,0 +1,71 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_users ? __('{0} su {1}', $filtered_users, $total_users) : $total_users) ?> +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('surname',__('Cognome')) ?>Paginator->sort('name', __('Nome')) ?>Paginator->sort('username', __('Username')) ?>Paginator->sort('OrganisationActors.description', __('Organizzazione')) ?>
surname) ?>name) ?>username) ?>actor->contacts) ?>profiles) ?>organisation->actor->description) ?> + Html->link(__('Dettaglio'), ['action' => 'view', $user->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $user->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $user->id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'utente "{0}" ?', $user->actor->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/Users/login.php b/idrocap_wa/templates/Users/login.php new file mode 100644 index 0000000..4f02e58 --- /dev/null +++ b/idrocap_wa/templates/Users/login.php @@ -0,0 +1,27 @@ + +
+ Form->create() ?> +
+ + Form->control('user_timezone', ['type' => 'hidden']) ?> + Form->control('username') ?> + Form->control('password') ?> +
Form->control('remember_me', ['label' => __(' Rimani connesso'), 'type' => 'checkbox', 'checked' => true]) ?>
+
+
+
+ Form->button(__('Login'), ['class' => 'btn btn-success']); ?> +
+
+ Html->link(__('Accedi con {0}', Configure::read('App.oidc.idp_name', 'OpenID Connect')), ['controller' => 'Users', 'action' => 'login_oidc'], ['class'=>'btn btn-info']) : ''?> +
+
+ Form->end() ?> +
+ diff --git a/idrocap_wa/templates/Users/one_time_password.php b/idrocap_wa/templates/Users/one_time_password.php new file mode 100644 index 0000000..fded58c --- /dev/null +++ b/idrocap_wa/templates/Users/one_time_password.php @@ -0,0 +1,8 @@ +
+ Form->create() ?> +
+ +
+
Form->button(__('Procedi'), ['class' => 'btn btn-success']); ?>
+ Form->end() ?> +
\ No newline at end of file diff --git a/idrocap_wa/templates/Users/password_recovery.php b/idrocap_wa/templates/Users/password_recovery.php new file mode 100644 index 0000000..079cbd2 --- /dev/null +++ b/idrocap_wa/templates/Users/password_recovery.php @@ -0,0 +1,9 @@ +
+ Form->create() ?> +
+ + Form->control('email') ?> +
+ Form->button(__('Richiedi reset password'), ['class' => 'btn btn-success']); ?> + Form->end() ?> +
\ No newline at end of file diff --git a/idrocap_wa/templates/Users/view.php b/idrocap_wa/templates/Users/view.php new file mode 100644 index 0000000..1ebab21 --- /dev/null +++ b/idrocap_wa/templates/Users/view.php @@ -0,0 +1,72 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista Utenti'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'users', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Utente'), + 'icon' => 'fa fa-info', + ], + ]); +?> +
+
+

+
+ photo): ?> +
+ Html->image("/users/getPhoto/" . $user->photo, array('class' => 'img-circle', 'alt' => 'User Image', 'style' => 'margin-right: 5px;')) ?> + Form->postLink(__('Elimina foto'), ['action' => 'deleteUserPhoto', $user->id], ['confirm' => __('Sei sicuro che vuoi eliminare la foto ?'), 'class'=>'btn btn-danger btn-xs']) ?> +
+ +
+
+
+
username) ?>
+
+
name) ?>
+
+
surname) ?>
+
+
tax_code) ?>
+
+
birthday) ? $user->birthday->format('d/m/Y') : '') ?>
+
+
birthplace) ?>
+
+
gender) ?>
+
+
address) ?>
+
+
city) ?>
+
+
cap) ?>
+
+
language->description) ? $user->language->description : __('Non specificata')) ?>
+
+
organisation->actor->description) ? $user->organisation->actor->description : '') ?>
+
+
profiles) ?>
+
+
actor->contacts) ?>
+
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingArticles/add.php b/idrocap_wa/templates/WaterDrawingArticles/add.php new file mode 100644 index 0000000..2a66599 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/add.php @@ -0,0 +1,45 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingArticles', 'action' => 'index'], + ], + [ + 'title' => __('Nuovo Articolo di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingArticle, ['role' => 'form']); ?> +
+
+
+ Form->control('description', ['label' => __('Articolo')]); ?> +
+
+ Form->control('long_description', ['label' => __('Descrizione')]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingArticles/edit.php b/idrocap_wa/templates/WaterDrawingArticles/edit.php new file mode 100644 index 0000000..9434199 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/edit.php @@ -0,0 +1,45 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingArticles', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Articolo di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingArticle, ['role' => 'form']); ?> +
+
+
+ Form->control('description', ['label' => __('Articolo')]); ?> +
+
+ Form->control('long_description', ['label' => __('Descrizione')]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingArticles/index.php b/idrocap_wa/templates/WaterDrawingArticles/index.php new file mode 100644 index 0000000..39d6d9c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/index.php @@ -0,0 +1,65 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('description',__('Articolo')) ?>Paginator->sort('long_description', __('Descrizione')) ?>Paginator->sort('disabled', __('Abilitato')) ?>
description) ?>long_description) ?>disable ? __('No') : __('Si') ?> + Html->link(__('Dettaglio'), ['action' => 'view', $waterDrawingArticle->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $waterDrawingArticle->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(($waterDrawingArticle->disable ? __('Abilita') : __('Disabilita')), ['action' => 'change_status', $waterDrawingArticle->id], ['confirm' => ($waterDrawingArticle->disable ? __('Sei sicuro che vuoi abilitare l\'articolo "{0}" ?', $waterDrawingArticle->description) : __('Sei sicuro che vuoi disabilitare l\'articolo "{0}" ?', $waterDrawingArticle->description)), 'class'=>'btn btn-info btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingArticle->id], ['confirm' => __('Sei sicuro che vuoi cancellare l\'articolo "{0}" ?', $waterDrawingArticle->description), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ diff --git a/idrocap_wa/templates/WaterDrawingArticles/view.php b/idrocap_wa/templates/WaterDrawingArticles/view.php new file mode 100644 index 0000000..86f6eb7 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingArticles/view.php @@ -0,0 +1,55 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Lista degli Articoli di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingArticles', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Articolo di legge delle pratiche d\'attingimento'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingArticle, ['role' => 'form']); ?> +
+
+
+ Form->control('description', ['label' => __('Articolo')]); ?> +
+
+ Form->control('long_description', ['label' => __('Descrizione')]); ?> +
+
+ Form->control('disabled', ['label' => __('Abilitato'), 'value' => ($waterDrawingArticle->disable ? __('No') : __('Si')), 'disabled' => true]); ?> +
+
+
+ + Form->end(); ?> +
+ diff --git a/idrocap_wa/templates/WaterDrawingDerivations/add.php b/idrocap_wa/templates/WaterDrawingDerivations/add.php new file mode 100644 index 0000000..3da6bad --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/add.php @@ -0,0 +1,250 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi Punto di prelievo/derivazione'), + 'icon' => 'fa fa-add', + ], +]); +?> +
+
+

+
+ Form->create($waterDrawingDerivation, ['role' => 'form', 'type' => 'file']); ?> +
+
+ +
+ Cell('Map', [ + [-2, -3, -4], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'location', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'location', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Contrada/Località'), + ], + 'district_code' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'istat', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'istat', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('ISTAT'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'table_name' => 'geo.rw_watersheds', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'swbcode' => 'swbcode' + ], + ], + [ + 'table_name' => 'geo.cw_draining_areas', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'cw_wise_co' => 'cw-wise-co' + ], + ], + [ + 'table_name' => 'geo.gwbs', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'wbcod' => 'wbcod', + ], + ], + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'COD_COMUNE' => 'cadastral-code', + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_code', ['label' => __('Codice catastale (Belfiore)'), 'type' => 'text']) ?> +
+
+ Form->control('location', ['label' => __('Contrada/Località'), 'type' => 'text']) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->hidden('water_drawing_paperwork_id', ['value' => $water_drawing_paperwork_id]) ?> + Form->control('water_drawing_derivation_type_id', ['label' => __('Tipo di derivazione'), 'options' => $waterDrawingDerivationTypes, 'onChange' => 'setWaterBody()']) ?> +
+
+ Form->control('water_body', ['label' => __('Corpo idrico'), 'type' => 'text']) ?> +
+ + +
+ Form->control('description', ['label' => __('Descrizione'), 'type' => 'text']) ?> +
+ +
+ Form->control('wbcod', ['label' => __('Codice corpo idrico sotterraneo'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('cw_wise_co', ['label' => __('Codice area afferente al corpo idrico marino costiero'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('swbcode', ['label' => __('Codice corpo idrico superficiale'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('istat', ['label' => __('Codice ISTAT'), 'type' => 'text']) ?> +
+
+ Form->control('derivation_status', ['label' => __('Status della derivazione'), 'type' => 'text']) ?> +
+
+ Form->control('withdrawals_amount', ['label' => __('N. prelievi'), 'type' => 'text']) ?> +
+
+ Form->control('annual_volume', ['label' => __('Volume annuo (m^3)'), 'type' => 'number', 'min' => 0]) ?> +
+
+ Form->control('average_flow_rate', ['label' => __('Portata media (l/s)'), 'type' => 'number', 'min' => 0]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+
+ Form->end(); ?> +
+
+ diff --git a/idrocap_wa/templates/WaterDrawingDerivations/edit.php b/idrocap_wa/templates/WaterDrawingDerivations/edit.php new file mode 100644 index 0000000..d1fb035 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/edit.php @@ -0,0 +1,235 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica Punto di prelievo/derivazione'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingDerivation, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_derivation_type_id', ['label' => __('Tipo di derivazione'), 'options' => $waterDrawingDerivationTypes]) ?> +
+
+ Form->control('water_body', ['label' => __('Corpo idrico'), 'type' => 'text']) ?> +
+ + +
+ Form->control('description', ['label' => __('Descrizione'), 'type' => 'text']) ?> +
+ +
+ Form->control('wbcod', ['label' => __('Codice corpo idrico sotterraneo'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('cw_wise_co', ['label' => __('Codice area afferente al corpo idrico marino costiero'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Form->control('swbcode', ['label' => __('Codice corpo idrico superficiale'), 'type' => 'text', 'readonly' => true]) ?> +
+
+ +
+ +
+ Cell('Map', [ + [-2, -3, -4], // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + 'address' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'location', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'location', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Contrada/Località'), + ], + 'district_code' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'istat', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'istat', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('ISTAT'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'table_name' => 'geo.rw_watersheds', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'swbcode' => 'swbcode' + ], + ], + [ + 'table_name' => 'geo.cw_draining_areas', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'cw_wise_co' => 'cw-wise-co' + ], + ], + [ + 'table_name' => 'geo.gwbs', // Nome della tabella dove risiede la geo-risorsa. Specificare il prefisso (esempio 'geo') qualora la risorsa si trovi al di fuori del datasource 'default' di Jixel + 'geometry_name' => 'SHAPE', // specifica il nome del campo di tipo GEOMETRY della geo-risorsa (se si omette, verrà preso il nome di default 'SHAPE') + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'wbcod' => 'wbcod', + ], + ], + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'COD_COMUNE' => 'cadastral-code', + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_code', ['label' => __('Codice catastale (Belfiore)'), 'type' => 'text']) ?> +
+
+ Form->control('location', ['label' => __('Contrada/Località'), 'type' => 'text']) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true, 'requred' => true,]) ?> +
+
+ Form->control('istat', ['label' => __('Codice ISTAT'), 'type' => 'text']) ?> +
+
+ Form->control('derivation_status', ['label' => __('Status della derivazione'), 'type' => 'text']) ?> +
+
+ Form->control('withdrawals_amount', ['label' => __('N. prelievi'), 'type' => 'text']) ?> +
+
+ Form->control('annual_volume', ['label' => __('Volume annuo (m^3)'), 'type' => 'number', 'min' => 0]) ?> +
+
+ Form->control('average_flow_rate', ['label' => __('Portata media (l/s)'), 'type' => 'number', 'min' => 0]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+
+ Form->end(); ?> +
+
+ diff --git a/idrocap_wa/templates/WaterDrawingDerivations/index.php b/idrocap_wa/templates/WaterDrawingDerivations/index.php new file mode 100644 index 0000000..f333f78 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/index.php @@ -0,0 +1,72 @@ + $waterDrawingDerivations + */ +?> +
+ Html->link(__('New Water Drawing Derivation'), ['action' => 'add'], ['class' => 'button float-right']) ?> +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id') ?>Paginator->sort('water_body') ?>Paginator->sort('district') ?>Paginator->sort('cadastral_code') ?>Paginator->sort('location') ?>Paginator->sort('cadastral_sheet') ?>Paginator->sort('cadastral_parcel') ?>Paginator->sort('latitude') ?>Paginator->sort('longitude') ?>Paginator->sort('istat') ?>Paginator->sort('derivation_status') ?>Paginator->sort('withdrawals_amount') ?>Paginator->sort('annual_volume') ?>Paginator->sort('average_flow_rate') ?>Paginator->sort('water_drawing_derivation_type_id') ?>Paginator->sort('water_drawing_paperwork_id') ?>
Number->format($waterDrawingDerivation->id) ?>water_body) ?>district) ?>cadastral_code) ?>location) ?>cadastral_sheet === null ? '' : $this->Number->format($waterDrawingDerivation->cadastral_sheet) ?>cadastral_parcel === null ? '' : $this->Number->format($waterDrawingDerivation->cadastral_parcel) ?>latitude) ?>longitude) ?>istat) ?>derivation_status) ?>withdrawals_amount === null ? '' : $this->Number->format($waterDrawingDerivation->withdrawals_amount) ?>annual_volume === null ? '' : $this->Number->format($waterDrawingDerivation->annual_volume) ?>average_flow_rate === null ? '' : $this->Number->format($waterDrawingDerivation->average_flow_rate) ?>hasValue('water_drawing_derivation_type') ? $this->Html->link($waterDrawingDerivation->water_drawing_derivation_type->id, ['controller' => 'WaterDrawingDerivationTypes', 'action' => 'view', $waterDrawingDerivation->water_drawing_derivation_type->id]) : '' ?>hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingDerivation->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork->id]) : '' ?> + Html->link(__('View'), ['action' => 'view', $waterDrawingDerivation->id]) ?> + Html->link(__('Edit'), ['action' => 'edit', $waterDrawingDerivation->id]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', $waterDrawingDerivation->id], ['confirm' => __('Are you sure you want to delete # {0}?', $waterDrawingDerivation->id)]) ?> +
+
+
+
    + Paginator->first('<< ' . __('first')) ?> + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> + Paginator->last(__('last') . ' >>') ?> +
+

Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?>

+
+
diff --git a/idrocap_wa/templates/WaterDrawingDerivations/view.php b/idrocap_wa/templates/WaterDrawingDerivations/view.php new file mode 100644 index 0000000..021f894 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingDerivations/view.php @@ -0,0 +1,104 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingDerivation->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli Punto di prelievo/derivazione'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingDerivation, ['id' => 'myForm', 'role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_derivation_type.description', ['label' => __('Tipo di derivazione'), 'type' => 'text', 'required' => false, 'disabled' => true]) ?> +
+
+ Form->control('water_body', ['label' => __('Corpo idrico'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('description', ['label' => __('Descrizione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_code', ['label' => __('Codice catastale (Belfiore)'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('location', ['label' => __('Contrada/Località'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0, 'disabled' => true]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true, 'disabled' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true, 'disabled' => true]) ?> +
+
+ Form->control('istat', ['label' => __('Codice ISTAT'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('derivation_status', ['label' => __('Status della derivazione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('withdrawals_amount', ['label' => __('N. prelievi'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('annual_volume', ['label' => __('Volume annuo (m^3)'), 'type' => 'number', 'min' => 0, 'disabled' => true]) ?> +
+
+ Form->control('average_flow_rate', ['label' => __('Portata media (l/s)'), 'type' => 'number', 'min' => 0, 'disabled' => true]) ?> +
+
+
+ Form->end(); ?> + +
diff --git a/idrocap_wa/templates/WaterDrawingFees/add.php b/idrocap_wa/templates/WaterDrawingFees/add.php new file mode 100644 index 0000000..9b91c12 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/add.php @@ -0,0 +1,46 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Dettagli pratica d\'attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi Canone annuale'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingFee, ['role' => 'form']); ?> +
+
+
+ Form->control('amount', ['label' => __('Canone'), 'required' => true, 'min' => 0]); ?> +
+
+ Form->control('year', ['label' => __('Anno'), 'type' => 'number', 'min' => 1900, 'max' => ((new \DateTime())->format("Y") + 1)]); ?> + Form->hidden('water_drawing_paperwork_id', ['value' => $water_drawing_paperwork_id]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingFees/edit.php b/idrocap_wa/templates/WaterDrawingFees/edit.php new file mode 100644 index 0000000..f7eeb8d --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/edit.php @@ -0,0 +1,46 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Dettagli pratica d\'attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica Canone annuale'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingFee, ['role' => 'form']); ?> +
+
+
+ Form->control('amount', ['label' => __('Canone'), 'required' => true, 'min' => 0]); ?> +
+
+ Form->control('year', ['label' => __('Anno'), 'type' => 'number', 'min' => 1900, 'max' => ((new \DateTime())->format("Y") + 1)]); ?> + Form->hidden('water_drawing_paperwork_id', ['value' => $waterDrawingFee->water_drawing_paperwork_id]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingFees/index.php b/idrocap_wa/templates/WaterDrawingFees/index.php new file mode 100644 index 0000000..e044f94 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/index.php @@ -0,0 +1,76 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Lista canoni annuali'), + 'icon' => 'fa fa-list', + ], +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_fees ? __('{0} su {1}', $filtered_water_drawing_fees, $total_water_drawing_fees) : $total_water_drawing_fees) ?> +

+ Html->link(__('Esporta lista (CSV)'), ['action' => 'index', '_ext' => 'csv', $water_drawing_paperwork_id], ['style="margin-left:1rem;"', 'class' => 'btn btn-success btn-xs']) : null ?> +
+
+ + + + + + + + + + + + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_edit ? $this->Html->link(__('Modifica'), ['controller' => 'waterDrawingFees', 'action' => 'edit', $waterDrawingFee->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + Html->link(__('Dettagli'), ['controller' => 'waterDrawingFees', 'action' => 'view', $waterDrawingFee->id], ['class' => 'btn btn-info btn-xs'])?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingFee->id], ['confirm' => __('Sei sicuro che vuoi cancellare il canone annuale "{0}" ?', $waterDrawingFee->year), 'class' => 'btn btn-danger btn-xs']) : null; ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingFees/view.php b/idrocap_wa/templates/WaterDrawingFees/view.php new file mode 100644 index 0000000..35fc10e --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingFees/view.php @@ -0,0 +1,91 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Configurazioni'), + 'icon' => 'fa fa-wrench', + ], + [ + 'title' => __('Dettagli pratica d\'attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingFee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli Canone annuale'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingFee, ['role' => 'form']); ?> +
+
+
+ Form->control('amount', ['label' => __('Canone'), 'required' => true, 'disabled' => true]); ?> +
+
+ Form->control('year', ['label' => __('Anno'), 'disabled' => true]); ?> + Form->hidden('water_drawing_paperwork_id', ['value' => $waterDrawingFee->water_drawing_paperwork_id]); ?> +
+
+ Form->end(); ?> +
+ +
+ +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_edit ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPayments', 'action' => 'delete', $waterDrawingPayment->id], ['confirm' => __('Sei sicuro che vuoi cancellare il pagamento n° "{0}" ?', $waterDrawingPayment->payment_number), 'class' => 'btn btn-danger btn-xs']) : null ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/add.php b/idrocap_wa/templates/WaterDrawingIntendedUses/add.php new file mode 100644 index 0000000..26ccb03 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/add.php @@ -0,0 +1,37 @@ + +
+ +
+
+ Form->create($waterDrawingIntendedUse) ?> +
+ + Form->control('area'); + echo $this->Form->control('cadastral_code'); + echo $this->Form->control('cadastral_sheet'); + echo $this->Form->control('cadastral_parcel'); + echo $this->Form->control('watering_system'); + echo $this->Form->control('consortium_area'); + echo $this->Form->control('rated_power_produced'); + echo $this->Form->control('water_drawing_paperwork_id', ['options' => $waterDrawingPaperworks]); + echo $this->Form->control('water_drawing_intended_use_type_id', ['options' => $waterDrawingIntendedUseTypes, 'empty' => true]); + ?> +
+ Form->button(__('Submit')) ?> + Form->end() ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/edit.php b/idrocap_wa/templates/WaterDrawingIntendedUses/edit.php new file mode 100644 index 0000000..abbd62c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/edit.php @@ -0,0 +1,42 @@ + +
+ +
+
+ Form->create($waterDrawingIntendedUse) ?> +
+ + Form->control('area'); + echo $this->Form->control('cadastral_code'); + echo $this->Form->control('cadastral_sheet'); + echo $this->Form->control('cadastral_parcel'); + echo $this->Form->control('watering_system'); + echo $this->Form->control('consortium_area'); + echo $this->Form->control('rated_power_produced'); + echo $this->Form->control('water_drawing_paperwork_id', ['options' => $waterDrawingPaperworks]); + echo $this->Form->control('water_drawing_intended_use_type_id', ['options' => $waterDrawingIntendedUseTypes, 'empty' => true]); + ?> +
+ Form->button(__('Submit')) ?> + Form->end() ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/index.php b/idrocap_wa/templates/WaterDrawingIntendedUses/index.php new file mode 100644 index 0000000..09b9ca4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/index.php @@ -0,0 +1,60 @@ + $waterDrawingIntendedUses + */ +?> +
+ Html->link(__('New Water Drawing Intended Use'), ['action' => 'add'], ['class' => 'button float-right']) ?> +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id') ?>Paginator->sort('area') ?>Paginator->sort('cadastral_code') ?>Paginator->sort('cadastral_sheet') ?>Paginator->sort('cadastral_parcel') ?>Paginator->sort('watering_system') ?>Paginator->sort('consortium_area') ?>Paginator->sort('rated_power_produced') ?>Paginator->sort('water_drawing_paperwork_id') ?>Paginator->sort('water_drawing_intended_use_type_id') ?>
Number->format($waterDrawingIntendedUse->id) ?>area) ?>cadastral_code) ?>cadastral_sheet) ?>cadastral_parcel) ?>watering_system) ?>consortium_area) ?>rated_power_produced) ?>hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_paperwork->id]) : '' ?>hasValue('water_drawing_intended_use_type') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_intended_use_type->id, ['controller' => 'WaterDrawingIntendedUseTypes', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_intended_use_type->id]) : '' ?> + Html->link(__('View'), ['action' => 'view', $waterDrawingIntendedUse->id]) ?> + Html->link(__('Edit'), ['action' => 'edit', $waterDrawingIntendedUse->id]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', $waterDrawingIntendedUse->id], ['confirm' => __('Are you sure you want to delete # {0}?', $waterDrawingIntendedUse->id)]) ?> +
+
+
+
    + Paginator->first('<< ' . __('first')) ?> + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> + Paginator->last(__('last') . ' >>') ?> +
+

Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?>

+
+
diff --git a/idrocap_wa/templates/WaterDrawingIntendedUses/view.php b/idrocap_wa/templates/WaterDrawingIntendedUses/view.php new file mode 100644 index 0000000..85d1f7c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingIntendedUses/view.php @@ -0,0 +1,64 @@ + +
+ +
+
+

id) ?>

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
area) ?>
cadastral_code) ?>
cadastral_sheet) ?>
cadastral_parcel) ?>
watering_system) ?>
consortium_area) ?>
rated_power_produced) ?>
hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_paperwork->id]) : '' ?>
hasValue('water_drawing_intended_use_type') ? $this->Html->link($waterDrawingIntendedUse->water_drawing_intended_use_type->id, ['controller' => 'WaterDrawingIntendedUseTypes', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_intended_use_type->id]) : '' ?>
Number->format($waterDrawingIntendedUse->id) ?>
+
+
+
diff --git a/idrocap_wa/templates/WaterDrawingMeasurements/add.php b/idrocap_wa/templates/WaterDrawingMeasurements/add.php new file mode 100644 index 0000000..e0f8a27 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeasurements/add.php @@ -0,0 +1,51 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'] + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan', $water_drawing_paperwork_id] + ], + [ + 'title' => __('Nuova lettura dello strumento'), + 'icon' => 'fa fa-plus', + ] +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeasurement, ['role' => 'form', 'type' => 'file']); ?> +
+
+ Form->control('water_drawing_meter_id', ['type' => 'hidden', 'value' => $water_drawing_meter_id]); ?> +
+ Form->control('volume', ['label' => __('Lettura volume (m^3)'), 'type' => 'number', 'required' => true, 'min' => 0]); ?> +
+
+ Form->control('date', ['label' => __('Data del rilievo'), 'style' => 'margin-left: 5px;', 'type' => 'date', 'max' => $today->format('Y-m-d')]); ?> +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingMeasurements/index.php b/idrocap_wa/templates/WaterDrawingMeasurements/index.php new file mode 100644 index 0000000..5586106 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeasurements/index.php @@ -0,0 +1,73 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'] + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id] + ], + [ + 'title' => __('Lista misurazioni relativi alla pratica'), + 'icon' => 'fa fa-list', + ], + +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_measurements ? __('{0} su {1}', $filtered_water_drawing_measurements, $total_water_drawing_measurements) : $total_water_drawing_measurements, $water_drawing_paperwork_id) ?> +

+ Html->link(__('Esporta lista (CSV)'), ['action' => 'index', '_ext' => 'csv', $water_drawing_paperwork_id], ['class' => 'btn btn-success btn-xs']) : null ?> +
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('water_drawing_meter_id', __('N° matricola strumento di misura')) ?>Paginator->sort('volume', __('Lettura volume (m^3)')) ?>Paginator->sort('date', __('Data lettura')) ?>Paginator->sort('volume', __('Utente')) ?>
water_drawing_meter->part_number) ?>volume) ?>date) ?>user) ?>
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingMeters/add.php b/idrocap_wa/templates/WaterDrawingMeters/add.php new file mode 100644 index 0000000..8315bd0 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/add.php @@ -0,0 +1,66 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi lo strumento di misura'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type_id', ['label' => __('Tipo'), 'type' => 'select', 'options' => $waterDrawingToolTypes, 'empty' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text']) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text']) ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingMeters/dismiss.php b/idrocap_wa/templates/WaterDrawingMeters/dismiss.php new file mode 100644 index 0000000..c7057cb --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/dismiss.php @@ -0,0 +1,67 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dismetti lo strumento di misura'), + 'icon' => 'fa fa-times-circle', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type.description', ['label' => __('Tipo'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text', 'disabled' => true]) ?> +
+
+
+
+ installation_date)):?> + Form->control('removal_date', ['label' => __('Data dismissione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'min' => $waterDrawingMeter->installation_date->format('Y-m-d'), 'max' => $today->format('Y-m-d')]) ?> + + Form->control('removal_date', ['label' => __('Data dismissione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> + +
+
+
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingMeters/edit.php b/idrocap_wa/templates/WaterDrawingMeters/edit.php new file mode 100644 index 0000000..14302c9 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/edit.php @@ -0,0 +1,66 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica lo strumento di misura'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type_id', ['label' => __('Tipo'), 'type' => 'select', 'options' => $waterDrawingToolTypes, 'empty' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text']) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text']) ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingMeters/view.php b/idrocap_wa/templates/WaterDrawingMeters/view.php new file mode 100644 index 0000000..5aaf288 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingMeters/view.php @@ -0,0 +1,103 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingMeter->water_drawing_intended_use->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettaglio dello strumento di misura'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingMeter, ['role' => 'form']); ?> +
+
+
+ Form->control('water_drawing_tool_type_id', ['label' => __('Tipo'), 'type' => 'select', 'options' => $waterDrawingToolTypes, 'empty' => true, 'disabled' => true]) ?> +
+
+ Form->control('installation_date', ['label' => __('Data installazione'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+
+
+ Form->control('manufacturer', ['label' => __('Marca'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('part_number', ['label' => __('Matricola'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->end(); ?> +
+ +
+ +
+
+

+ +

+
+
+ + + + + + + + + + water_drawing_measurements as $waterDrawingMeasurement) : ?> + + + + + + + +
user) ?>volume) ?>date->format("d/m/Y")) ?>
+
+ +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/add.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/add.php new file mode 100644 index 0000000..684edc2 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/add.php @@ -0,0 +1,62 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi il documento PEC'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperworkPec, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->hidden('water_drawing_paperwork_id', ['value' => $water_drawing_paperwork_id]) ?> + Form->control('document', ['label' => __('Documento'), 'type' => 'text']) ?> + Form->control('protocol_number', ['label' => __('Numero di protocollo'), 'type' => 'text']) ?> + Form->control('recipient', ['label' => __('Destinatario'), 'type' => 'text']) ?> + Form->control('sender', ['label' => __('Inviato da'), 'type' => 'text']) ?> + Form->control('protocol_date', ['label' => __('Data'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> + element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + ?> + Form->control('note', ['label' => 'Note:', 'type' => 'textarea']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/edit.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/edit.php new file mode 100644 index 0000000..6cdf4b4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/edit.php @@ -0,0 +1,62 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + //'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica il documento PEC'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperworkPec, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('document', ['label' => __('Documento'), 'type' => 'text']) ?> + Form->control('protocol_number', ['label' => __('Numero di protocollo'), 'type' => 'text']) ?> + Form->control('recipient', ['label' => __('Destinatario'), 'type' => 'text']) ?> + Form->control('sender', ['label' => __('Inviato da'), 'type' => 'text']) ?> + Form->control('protocol_date', ['label' => __('Data'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'max' => $today->format('Y-m-d')]) ?> + element('attachments', [ + 'coId' => $waterDrawingPaperworkPec->controllable_object_id, + 'filepicker' => true, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'tags' => $tags, + 'required' => false, + 'view_in_frame_with_id' => false, + 'accept_only' => ['.pdf'] + ]); + ?> + Form->control('note', ['label' => 'Note:', 'type' => 'textarea']); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/index.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/index.php new file mode 100644 index 0000000..7acbe21 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/index.php @@ -0,0 +1,81 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'] + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id] + ], + [ + 'title' => __('Lista misurazioni relativi alla pratica'), + 'icon' => 'fa fa-list', + ], + +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_papwork_pecs ? __('{0} su {1}', $filtered_water_drawing_papwork_pecs, $total_water_drawing_papwork_pecs) : $total_water_drawing_papwork_pecs, $water_drawing_paperwork_id) ?> +

+ + Html->link(__('Aggiungi documento'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'add', $water_drawing_paperwork_id], ['class' => 'btn btn-success btn-xs pull-right', 'style' => 'margin-right:1rem; margin-bottom:1rem;']); ?> + +
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('document', __('Documento')) ?>Paginator->sort('protocol_number', __('Numero protocollo')) ?>Paginator->sort('protocol_date', __('Data')) ?>Paginator->sort('user_id', __('Utente')) ?>
document) ?>protocol_number) ?>protocol_date) ?>user) ?> + can_edit_pec ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'edit', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']) : null; ?> + Html->link(__('Visualizza'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']); ?> + can_delete_pec ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'delete', $waterDrawingPaperworkPec->id], ['confirm' => __('Sei sicuro che vuoi cancellare la documentazione PEC "{0}" ?', $waterDrawingPaperworkPec->id), 'class' => 'btn btn-danger btn-xs', 'style' => 'margin-right:1rem']) : null; ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworkPecs/view.php b/idrocap_wa/templates/WaterDrawingPaperworkPecs/view.php new file mode 100644 index 0000000..17c80dc --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworkPecs/view.php @@ -0,0 +1,61 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettaglio Pratica di attingimento'), + 'icon' => 'fa fa-list', + //'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli documento PEC'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperworkPec, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('document', ['label' => __('Documento'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('protocol_number', ['label' => __('Numero di protocollo'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('recipient', ['label' => __('Destinatario'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('sender', ['label' => __('Inviato da'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('protocol_date', ['label' => __('Data'), 'type' => 'date', 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> + element('attachments', [ + 'coId' => $waterDrawingPaperworkPec->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'tags' => $tags, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => false, + ]); + ?> + Form->control('note', ['label' => 'Note:', 'type' => 'textarea', 'disabled' => true]); + ?> + Form->end(); ?> +
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/add.php b/idrocap_wa/templates/WaterDrawingPaperworks/add.php new file mode 100644 index 0000000..f27d3aa --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/add.php @@ -0,0 +1,632 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Gestione Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], +]); +?> +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+
+
+

+ +

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file', 'id' => 'editWaterDrawingPaperwork']); ?> +
+ +
+
+

+ +

+
+ +
+
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'required' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), "style" => "cursor: not-allowed", 'type' => 'text', "disabled" => true, 'value' => (isset($hide_authority_province) && $hide_authority_province) ? ($authority_civil_engineer_code ?? null) : null]) ?> +
+ + Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, autoFillTargetId: "authority-civil-engineer-code", autoFillTargetEnabled: true, fieldRequired: true, showProvinceFullName: true)]) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}']) ?> +
+
+ Form->control('protocol_number', ['label' => __('Numero di protocollo della pratica'), 'type' => 'text']) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'empty' => true, 'options' => $WaterDrawingArticles]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, "formContext" => $waterDrawingPaperwork]); + ?> +
+
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+
+ Cell('IntendedUses', ['intended_use_item_block' => 0]); + ?> +
+
+
+
+
+ +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date']) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text']) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text']) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)')]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'max' => $today->format('Y-m-d')]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)')]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text']) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+
+
+ +
+ + Form->end(); ?> +
+ + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/add_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/add_scan.php new file mode 100644 index 0000000..1c9660a --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/add_scan.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Nuova Pratica di attingimento Scansionata'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('water_drawing_paperwork_status_id', ['type' => 'hidden', 'value' => 1]); + echo $this->element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'required' => false, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/antimafia_request_to_anac.php b/idrocap_wa/templates/WaterDrawingPaperworks/antimafia_request_to_anac.php new file mode 100644 index 0000000..867f848 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/antimafia_request_to_anac.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica ricevuta della richiesta antimafia alla Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/applicants_water_drawing_paperworks_item_block.php b/idrocap_wa/templates/WaterDrawingPaperworks/applicants_water_drawing_paperworks_item_block.php new file mode 100644 index 0000000..093a6fe --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/applicants_water_drawing_paperworks_item_block.php @@ -0,0 +1,5 @@ +element('WaterDrawingPaperworks/applicants', [ + 'applicant_item_block' => $applicant_item_block, + 'water_drawing_paperwork_status_id' => isset($waterDrawingPaperwork) ? $waterDrawingPaperwork->water_drawing_paperwork_status_id : null, + 'water_drawing_paperwork_id' => isset($waterDrawingPaperwork) ? $waterDrawingPaperwork->id : null +]);?> \ No newline at end of file diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/assign.php b/idrocap_wa/templates/WaterDrawingPaperworks/assign.php new file mode 100644 index 0000000..8d89319 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/assign.php @@ -0,0 +1,48 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Assegna Pratica di attingimento'), + 'icon' => 'fa fa-user', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control(($organisation_type_id == 6 ? 'drar_user_id' : 'gc_user_id'), ['id' => 'select2user-id', 'label' => __('Ricerca utente'), 'type' => 'select', 'options' => $users, 'empty' => true, 'required' => true]); ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_index.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_index.php new file mode 100644 index 0000000..65fd6c5 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_index.php @@ -0,0 +1,115 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista documenti della richiesta di attingimento'), + 'icon' => 'fa fa-list', + ], +]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('original_file_name', __('Nome del file')) ?>Paginator->sort('mimetype', __('Tipologia file')) ?>Paginator->sort('description', __('Tipologia documento')) ?>Paginator->sort('upload_date', __('Caricato il')) ?>
original_file_name) ?>mimetype) ?>tags[0]->description) ?>upload_date) ?> + Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', $attachment->file_name], ['class' => 'btn btn-info btn-xs', 'target' => '_blank']) ?> + water_drawing_paperwork_status_id == 8 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 11) ? $this->Html->link(__('Elimina'), ['action' => 'delete_attachment', $waterDrawingPaperwork->id, $attachment->id], ['class' => 'btn btn-warning btn-xs', 'confirm' => __('Sei sicuro di voler cancellare questo documento?')]) : ''?> +
+
+
+ water_drawing_paperwork_status_id == 8 || $waterDrawingPaperwork->water_drawing_paperwork_status_id == 11 ? $this->Html->link(__('Aggiungi documentazione'), ['action' => 'citizen_documentation_requested', $waterDrawingPaperwork->id], ['class' => 'btn btn-success btn-xs']) : '' ?> + is_citizen_water_drawing_paperwork_ok_to_send() ? $this->Html->link(__('Invia richiesta'), ['action' => 'citizen_send_to_validation', $waterDrawingPaperwork->id], ['confirm' => __('Vuoi procedere con l\'invio ?'), 'class' => 'btn btn-info btn-xs']) : ''?> +
+ +
+ +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_requested.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_requested.php new file mode 100644 index 0000000..30451d0 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_documentation_requested.php @@ -0,0 +1,376 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista Documenti sottomessi della Pratica'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Lista modulistica'), + 'icon' => 'fa fa-list', + ], +]); +?> + +
+
+

+ +

+
+
+
+
+

+ +

+
+
+
+
+ +
+
+ check_adam) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 5], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 5], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+

+ +

+
+
+
+
+ +
+
+ check_rap) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 1], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 1], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_ia7) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 2], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 2], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_ia56) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 3], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 3], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_isu) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 6], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 6], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+ +
+ +
+
+ check_ira) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 4], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 4], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+ +
+
+ check_irc56) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 20], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 20], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+

+ +

+
+
+
+
+ +
+
+ check_thc_a) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 7], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 7], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_aa) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 8], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 8], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ab) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 9], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 9], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ac) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 10], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 10], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ad) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 11], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 11], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ae) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 12], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 12], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_af) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 13], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 13], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_ag) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 14], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 14], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b1) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 16], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 16], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b2) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 17], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 17], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b3) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 18], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 18], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_thc_b4) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 19], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Compila il documento'), ['action' => 'citizen_upload_attachment', $waterDrawingPaperwork->id, 19], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+
+ check_rpdi) { ?> + + Html->link(__('Modifica'), ['action' => 'citizen_upload_payment_receipt', $waterDrawingPaperwork->id, -15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } else { + echo $this->Html->link(__('Carica ricevuta'), ['action' => 'citizen_upload_payment_receipt', $waterDrawingPaperwork->id, -15], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + } ?> +
+
+
+
+ +
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_request_paperwork.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_request_paperwork.php new file mode 100644 index 0000000..e183541 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_request_paperwork.php @@ -0,0 +1,35 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Carica allegato'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+
+ Html->link(__('Per mio conto'), ['controller' => 'Applicants', 'action' => 'citizen_view'], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm']); + echo '

Per conto terzi

'; + ?> +
+
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submission_index.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submission_index.php new file mode 100644 index 0000000..b106d06 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submission_index.php @@ -0,0 +1,73 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + ], +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_paperworks ? __('{0} su {1}', $filtered_water_drawing_paperworks, $total_water_drawing_paperworks) : $total_water_drawing_paperworks) ?> +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id', __('ID')) ?>Paginator->sort('authority_identification_code_civil_engineering_office', __('Codice identificativo')) ?>Paginator->sort('WaterDrawingPaperworkStatuses.description', __('Stato')) ?>Paginator->sort('authority_province', __('Provincia')) ?>Paginator->sort('release_date', __('Data di rilascio')) ?>Paginator->sort('expiration_date', __('Scadenza')) ?>Paginator->sort('ControllableObjects.created', __('Creata il')) ?>Paginator->sort('ControllableObjects.modified', __('Modificata il')) ?>
Number->format($waterDrawingPaperwork->id) ?>authority_identification_code_civil_engineering_office) ?>water_drawing_paperwork_status->rgb) ? 'style="color:' . $waterDrawingPaperwork->water_drawing_paperwork_status->rgb . '"' : '' ?>>water_drawing_paperwork_status->description) ?>authority_province) ?>release_date) ?>expiration_date) ?>controllable_object->created) ?>controllable_object->modified) ?> + Html->link(__('Dettaglio'), ['action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], ['class' => 'btn btn-info btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submit_paperwork.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submit_paperwork.php new file mode 100644 index 0000000..154293e --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_submit_paperwork.php @@ -0,0 +1,46 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Selezione della provincia di competenza'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($applicant, ['role' => 'form', 'type' => 'file']); ?> +
+ Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $applicant, autoFillTargetEnabled: false, fieldRequired: true, showProvinceFullName: true)]) ?> +
+ + + +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_attachment.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_attachment.php new file mode 100644 index 0000000..ce7febd --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_attachment.php @@ -0,0 +1,60 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista documenti della richiesta di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Carica allegato'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ link != '') { + echo $this->Html->link($tag->description, ['controller' => 'Attachments', 'action' => 'view', $tag->link], ['target' => '_blank']); + echo $this->Html->link(__('Scarica'), ['controller' => 'Attachments', 'action' => 'view', $tag->link], ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm', 'target' => '_blank']); + } + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => [ + $tag->code => $tag->description, + ], + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.p7m'] + ]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_payment_receipt.php b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_payment_receipt.php new file mode 100644 index 0000000..a73695f --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/citizen_upload_payment_receipt.php @@ -0,0 +1,58 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Richieste di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_submission_index'], + ], + [ + 'title' => __('Lista documenti della richiesta di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'citizen_documentation_index', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Carica allegato'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

id) ?>

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ Html->link(__('Portale pagamenti - Regione Siciliana'), 'https://pagamenti.regione.sicilia.it/static/', ['target' => '_blank']); + echo $this->Html->link(__('Accedi al portale'), 'https://pagamenti.regione.sicilia.it/static/', ['style="margin-left:1rem;"', 'class' => 'btn btn-default btn-sm', 'target' => '_blank']); + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => [ + $tag->code => $tag->description, + ], + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/edit.php b/idrocap_wa/templates/WaterDrawingPaperworks/edit.php new file mode 100644 index 0000000..119f9dd --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/edit.php @@ -0,0 +1,641 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Pratica di attingimento'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+ +
+
+

+ +

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file', 'id' => 'editWaterDrawingPaperwork']); ?> +
+ +
+
+

+ +

+
+ +
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => true, + 'tags' => $tags_picker, + 'required' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); + + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'view_in_frame_with_id' => 'previewiframe', + 'tags' => $tags_viewer, + 'required' => false + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), "style" => "cursor: not-allowed", 'type' => 'text', "disabled" => true, 'value' => (isset($hide_authority_province) && $hide_authority_province) ? ($authority_civil_engineer_code ?? null) : null]) ?> +
+ + Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, autoFillTargetId: "authority-civil-engineer-code", autoFillTargetEnabled: true, fieldRequired: true, showProvinceFullName: true)]) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}']) ?> +
+
+ Form->control('protocol_number', ['label' => __('Numero di protocollo della pratica'), 'type' => 'text']) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'empty' => true, 'options' => $waterDrawingArticles]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'applicant' => $applicant, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses) == 0) echo $this->Cell('IntendedUses', ['intended_use_item_block' => 0]); + foreach ($waterDrawingPaperwork->water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date']) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text']) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text']) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)')]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'max' => $today->format('Y-m-d')]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)')]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text']) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text']) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+
+
+ +
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/edit_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/edit_scan.php new file mode 100644 index 0000000..9eff8e2 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/edit_scan.php @@ -0,0 +1,667 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Modifica Pratica di attingimento scansionata'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+ +
+
+

+ +

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file', 'id' => 'editWaterDrawingPaperwork']); ?> +
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status_id', ['type' => 'hidden', 'value' => $waterDrawingPaperwork->water_drawing_paperwork_status_id >= 6 ? $waterDrawingPaperwork->water_drawing_paperwork_status_id : ($waterDrawingPaperwork->water_drawing_paperwork_status_id == 4 ? 5 : 3)]); + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => true, + 'tags' => $tags_picker, + 'required' => false, + 'accept_only' => ['.pdf'], + 'upload_single' => true, + ]); + + echo $this->element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => true, + 'view_in_frame_with_id' => 'previewiframe', + 'tags' => $tags_viewer, + 'required' => false + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), "style" => "cursor: not-allowed", 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), "disabled" => true]) ?> +
+ Cell( + "DistrictProvince", + [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + autoFillTargetId: "authority-civil-engineer-code", + autoFillTargetEnabled: true, + fieldRequired: true, + fieldType: ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? InputFieldType::SELECT : InputFieldType::HIDDEN), + showProvinceFullName: true + ) + ] + ) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text']) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'select' : 'hidden'), 'options' => $waterDrawingArticles]) ?> +
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'applicant' => $applicant, 'water_drawing_paperwork_id' => $waterDrawingPaperwork->id, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+ +
+
+
+ + water_drawing_paperwork_status_id > 3) : ?> +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses) == 0) echo $this->Cell('IntendedUses', ['intended_use_item_block' => 0]); + foreach ($waterDrawingPaperwork->water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+ +
+
+
+ + + water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date']) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date']) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)')]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'style' => 'margin-left: 5px;']) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'number' : 'hidden'), 'pattern' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? '[0-9]*' : '')]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'style' => 'margin-left: 5px;']) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden')]) ?> +
+
+
+
+ + water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'min' => 0]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date']) ?> +
+
+
+
+ +
+ + + +
+ + +water_drawing_paperwork_status_id === 1): ?> + + Html->script('ia-form-filler/dist/entrypoints/content.js', ['type' => 'module']) ?> + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/index.php b/idrocap_wa/templates/WaterDrawingPaperworks/index.php new file mode 100644 index 0000000..d0a942c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/index.php @@ -0,0 +1,81 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_paperworks ? __('{0} su {1}', $filtered_water_drawing_paperworks, $total_water_drawing_paperworks) : $total_water_drawing_paperworks) ?> +

+ Html->link(__('Esporta CSV'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_csv'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> + Html->link(__('Estrai pagamenti'), ['controller' => 'WaterDrawingPayments', 'action' => 'index_all', '_ext' => 'csv'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> + Html->link(__('Visualizza Logs'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id', __('ID')) ?>Paginator->sort('authority_identification_code_civil_engineering_office', __('Codice identificativo')) ?>Paginator->sort('WaterDrawingPaperworkStatuses.description', __('Stato')) ?>Paginator->sort('authority_province', __('Provincia')) ?>Paginator->sort('release_date', __('Data di rilascio')) ?>Paginator->sort('expiration_date', __('Scadenza')) ?>Paginator->sort('ControllableObjects.created', __('Creata il')) ?>Paginator->sort('ControllableObjects.modified', __('Modificata il')) ?>
Number->format($waterDrawingPaperwork->id) ?>authority_identification_code_civil_engineering_office) ?>water_drawing_paperwork_status->rgb) ? 'style="color:'. $waterDrawingPaperwork->water_drawing_paperwork_status->rgb . '"' : '' ?>>water_drawing_paperwork_status->description) ?>authority_province) ?>release_date) ?>expiration_date) ?>percentage) ?>controllable_object->created) ?>controllable_object->modified) ?> + Html->link(__('Dettaglio'), ['action' => ($waterDrawingPaperwork->scanned ? 'view_scan' : 'view'), $waterDrawingPaperwork->id], ['class'=>'btn btn-info btn-xs']) ?> + can_edit ? $this->Html->link(__('Modifica'), ['action' => ($waterDrawingPaperwork->scanned ? 'edit_scan' : 'edit'), $waterDrawingPaperwork->id], ['class'=>'btn btn-warning btn-xs']) : null ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro che vuoi cancellare la pratica di attingimento con ID:"{0}" ?', $waterDrawingPaperwork->id), 'class'=>'btn btn-danger btn-xs']) : null ?> +
+
+ +
+ diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots.php b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots.php new file mode 100644 index 0000000..ee61e92 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots.php @@ -0,0 +1,80 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Storico Pratica di attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+ Html->link(__('Esporta CSV'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_csv', $water_drawing_paperwork_id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('when', __('Data')) ?>Paginator->sort('who', __('Da')) ?>Paginator->sort('what', __('Azione')) ?>Paginator->sort('water_drawing_paperwork_status', __('Stato Pratica')) ?>Paginator->sort('gc_user', __('Assegnatario Genio Civile')) ?>Paginator->sort('drar_user', __('Assegnatario DRAR')) ?>
when) ? (new DateTime($unpackedWaterDrawingPaperworkSnapshot->when))->i18nFormat('dd/MM/Y HH:mm:ss', $logged_user_timezone) : null) ?>who) ?>what) ?>water_drawing_paperwork_status) ?>gc_user) ?>drar_user) ?> + Html->link(__('Dettaglio'), ['action' => ($waterDrawingPaperwork->scanned ? 'view_scan_snapshot' : 'view_snapshot'), $unpackedWaterDrawingPaperworkSnapshot->snapshot_id], ['class'=>'btn btn-info btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots_all.php b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots_all.php new file mode 100644 index 0000000..deadc64 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/index_snapshots_all.php @@ -0,0 +1,77 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Logs Pratiche di attingimento'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+ Html->link(__('Esporta CSV'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all_csv'], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('when', __('Data')) ?>Paginator->sort('who', __('Da')) ?>Paginator->sort('what', __('Azione')) ?>Paginator->sort('water_drawing_paperwork_id', __('ID Pratica')) ?>Paginator->sort('water_drawing_paperwork_status', __('Stato Pratica')) ?>Paginator->sort('gc_user', __('Assegnatario Genio Civile')) ?>Paginator->sort('drar_user', __('Assegnatario DRAR')) ?>
when) ? (new DateTime($unpackedWaterDrawingPaperworkSnapshot->when))->i18nFormat('dd/MM/Y HH:mm:ss', $logged_user_timezone) : null) ?>who) ?>what) ?>water_drawing_paperwork_id) ?>water_drawing_paperwork_status) ?>gc_user) ?>drar_user) ?> + Html->link(__('Dettaglio'), ['action' => 'view_snapshot', $unpackedWaterDrawingPaperworkSnapshot->snapshot_id, '?' => ['origin' => 'logs']], ['class'=>'btn btn-info btn-xs']) ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/intended_uses_water_drawing_paperworks_item_block.php b/idrocap_wa/templates/WaterDrawingPaperworks/intended_uses_water_drawing_paperworks_item_block.php new file mode 100644 index 0000000..316ef1b --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/intended_uses_water_drawing_paperworks_item_block.php @@ -0,0 +1 @@ +Cell('IntendedUses', ['intended_use_item_block' => ($intended_use_item_block)]);?> \ No newline at end of file diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/upload_antimafia_attachment.php b/idrocap_wa/templates/WaterDrawingPaperworks/upload_antimafia_attachment.php new file mode 100644 index 0000000..fe9e69b --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/upload_antimafia_attachment.php @@ -0,0 +1,49 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica antimafia alla Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment.php b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment.php new file mode 100644 index 0000000..8720542 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment.php @@ -0,0 +1,50 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica allegato Pratica di attingimento'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment_scan.php new file mode 100644 index 0000000..f8ee0b4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/upload_attachment_scan.php @@ -0,0 +1,50 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Carica allegato Pratica di attingimento scansionata'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPaperwork, ['role' => 'form', 'type' => 'file']); ?> +
+ Form->control('water_drawing_paperwork_status_id', ['type' => 'hidden', 'value' => 1]); + echo $this->element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tag, + 'required' => true, + 'upload_single' => true, + 'accept_only' => ['.pdf'] + ]); + echo $this->Form->hidden('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true]); + ?> +
+ + Form->end(); ?> +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/validate.php b/idrocap_wa/templates/WaterDrawingPaperworks/validate.php new file mode 100644 index 0000000..146fdae --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/validate.php @@ -0,0 +1,713 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Validazione Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+
+
+ +
+ +
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> + Form->control('gc_user', ['label' => __('Assegnatario Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('drar_user', ['label' => __('Assegnatario DRAR'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ')?>check_dv ? __('Presente') : __('Assente ')?>check_lic ? __('Presente') : __('Assente ')?>check_dec ? __('Presente') : __('Assente ')?>check_sdd ? __('Presente') : __('Assente ')?>check_dsc ? __('Presente') : __('Assente ')?>check2a ? __('Presente') : __('Assente ')?>check_dam ? __('Presente') : __('Assente ')?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + 'tags' => null + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, fieldRequired: true, disabled: true, showProvinceFullName: true)]) ?> +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true, 'disabled' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'options' => $WaterDrawingArticles, 'empty' => true, 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude . ', ' . $waterDrawingDerivation->longitude) ?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'disabled' => true]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'disabled' => true]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'disabled' => true]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= -4) : ?> + + +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:0.5rem']); + } + ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_antimafia_certification_requests as $waterDrawinAntimafiaRequest) : ?> + + + + + + + +
user) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>water_drawing_antimafia_certification_request_status->description) . ($waterDrawinAntimafiaRequest->water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? __(' - Richiesta scaduta') : null) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>created) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + water_drawing_paperwork_pecs as $waterDrawingPaperworkPec) : ?> + + + + + + + + +
document) ?>protocol_number) ?>protocol_date->format('d/m/Y')) ?> + Html->link(__('Visualizza'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']); ?> +
+
+ +
+Form->end() ?> +
+
+

+ +

+ +
+
+ Form->create($waterDrawingPaperworkHistory, ['role' => 'form', 'type' => 'file']); ?> +
+
+ Form->hidden('water_drawing_paperwork_status_id', ['value' => $waterDrawingPaperwork->water_drawing_paperwork_status_id]); + echo $this->Form->control('result', ['label' => __('Esito'), 'onChange' => 'checkNote()', 'type' => 'radio', 'options' => [1 => __('Accettata'), 0 => __('Respinta')]]); + ?> +
+
+ + Form->control('note', ['label' => false, 'type' => 'textarea', 'id' => 'note-field']); + ?> +
+
+ element('attachments', [ + 'filepicker' => true, + 'viewer' => false, + 'currentFilesRemovable' => false, + 'tags' => $tags, + 'upload_single' => true, + 'required' => false, + 'accept_only' => ['.pdf'] + ]); + ?> +
+
+ Form->submit(__('Salva')); ?> +
+
+ Form->end(); ?> +
+ +
+ + + + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/validate_index.php b/idrocap_wa/templates/WaterDrawingPaperworks/validate_index.php new file mode 100644 index 0000000..0853e7b --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/validate_index.php @@ -0,0 +1,71 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento da validare'), + 'icon' => 'fa fa-list', + ], + ]); +?> + +
+
+

+ +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id', __('ID')) ?>Paginator->sort('WaterDrawingPaperworkStatuses.description', __('Stato')) ?>Paginator->sort('district', __('Comune')) ?>Paginator->sort('release_date', __('Data di rilascio')) ?>Paginator->sort('concession_duration', __('Durata della Derivazione (anni)')) ?>Paginator->sort('expiration_date', __('Scadenza')) ?>Paginator->sort('ControllableObjects.created', __('Creata il')) ?>Paginator->sort('ControllableObjects.modified', __('Modificata il')) ?>
Number->format($waterDrawingPaperwork->id) ?>water_drawing_paperwork_status->description) ?>district) ?>release_date) ?>concession_duration) ? $this->Number->format($waterDrawingPaperwork->concession_duration) : '' ?>expiration_date) ?>controllable_object->created) ?>controllable_object->modified) ?> + can_validate ? $this->Html->link(__('Valida'), ['controller' => 'WaterDrawingPaperworks', 'action' => ( $waterDrawingPaperwork->scanned ? 'validate_scan' : 'validate'), $waterDrawingPaperwork->id], ['class'=>'btn btn-info btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/validate_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/validate_scan.php new file mode 100644 index 0000000..a8764c7 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/validate_scan.php @@ -0,0 +1,728 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento scansionata'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ +
+ + + water_drawing_paperwork_status_id > 5): ?> + + water_drawing_paperwork_status_id > 3): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + +
+
+
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (((($logged_user_id === $waterDrawingPaperwork->gc_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < 0) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dam ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_upload_antimafia_attachment) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + fieldRequired: true, + disabled: true, + fieldType: ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? InputFieldType::SELECT : InputFieldType::HIDDEN), + showProvinceFullName: true + ) + ] + ) ?> +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'select' : 'hidden'), 'options' => $waterDrawingArticles, 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +water_drawing_paperwork_status_id > 5): ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude . ', ' . $waterDrawingDerivation->longitude) ?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 3) : ?> +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes]); + } + ?> +
+
+
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'number' : 'hidden'), 'pattern' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? '[0-9]*' : ''), 'disabled' => true]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+
+
+ +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingFees', 'action' => 'edit', $waterDrawingFees->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= -4) : ?> + + +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs']); + echo $this->Html->link(__('Dismetti'), ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-danger btn-xs']); + } else { + echo $this->Html->link(__('Aggiungi strumento di misura'), ['controller' => 'WaterDrawingMeters', 'action' => 'add', $waterDrawingIntendedUse->id], ['class' => 'btn btn-success btn-xs']); + } + ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('user_id', __('Utente')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+Form->end(); +echo $this->Form->create($waterDrawingPaperworkHistory, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); +?> + +
+
+

+
+
+
+
+ Form->control('result', ['label' => __('Esito'), 'onChange' => 'checkNote()', 'type' => 'radio', 'options' => [1 => __('Accettata'), 0 => __('Respinta')]]); ?> +
+
+ Form->control('note', ['label' => __('Note'), 'type' => 'textarea']); ?> +
+
+
+ + + Form->end() ?> + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/view.php b/idrocap_wa/templates/WaterDrawingPaperworks/view.php new file mode 100644 index 0000000..93e5af4 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/view.php @@ -0,0 +1,768 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+ +
+
+
+
+
+ +
+
+
+
+ + + + + + + + can_view_fee && $waterDrawingPaperwork->can_view_payment): ?> + + + + + + + +
+
+
+
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> + Form->control('gc_user', ['label' => __('Assegnatario Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('drar_user', ['label' => __('Assegnatario DRAR'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (((($logged_user_id === $waterDrawingPaperwork->gc_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < 0) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_ram ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_antimafia_request_to_anac) ? $this->Html->link(__('Carica'), ['action' => 'antimafia_request_to_anac', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_adam || $waterDrawingPaperwork->check_dam) ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_upload_antimafia_attachment) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [new ProvinceCellDto(fieldId: "authority-province", fieldName: "authority_province", formContext: $waterDrawingPaperwork, fieldRequired: true, disabled: true, showProvinceFullName: true)]) ?> +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true, 'disabled' => true]) ?> +
+
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'disabled' => true]) ?> +
+
+ Form->control('protocol_number', ['label' => __('Numero di protocollo della pratica'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'options' => $WaterDrawingArticles, 'empty' => true, 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'is_view' => true, "formContext" => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude, $waterDrawingDerivation->longitude) ? (number_format((float) $waterDrawingDerivation->latitude, 4) . ', ' . number_format((float) $waterDrawingDerivation->longitude, 4)) : '')?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude, $waterDrawingDerivation->longitude) ? (number_format((float) $waterDrawingDerivation->latitude, 4) . ', ' . number_format((float) $waterDrawingDerivation->longitude, 4)) : '')?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'disabled' => true]) ?> +
+
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'disabled' => true]) ?> +
+
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'disabled' => true]) ?> +
+
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+
+
+
+can_view_fee && $waterDrawingPaperwork->can_view_payment): ?> +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?>paied ? 'SI' : 'NO') ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingFees', 'action' => 'edit', $waterDrawingFees->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>applicant_tax_code) ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> + can_delete_payment ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPayments', 'action' => 'delete', $waterDrawingPayment->id], ['confirm' => __('Sei sicuro che vuoi cancellare il pagamento n° "{0}" ?', $waterDrawingPayment->payment_number), 'class' => 'btn btn-danger btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= -4) : ?> + + +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date?->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:0.5rem']); + echo $this->Html->link(__('Dismetti'), ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-danger btn-xs']); + } else { + echo $this->Html->link(__('Aggiungi strumento di misura'), ['controller' => 'WaterDrawingMeters', 'action' => 'add', $waterDrawingIntendedUse->id], ['class' => 'btn btn-success btn-xs', 'style' => 'margin-right:1rem']); + } + ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_antimafia_certification_requests as $waterDrawinAntimafiaRequest) : ?> + + + + + + + +
user) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>water_drawing_antimafia_certification_request_status->description) . ($waterDrawinAntimafiaRequest->water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? __(' - Richiesta scaduta') : null) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>created) ?>
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + water_drawing_paperwork_pecs as $waterDrawingPaperworkPec) : ?> + + + + + + + + +
document) ?>protocol_number) ?>protocol_date->format('d/m/Y')) ?> + can_edit_pec ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'edit', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']) : null; ?> + Html->link(__('Visualizza'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'view', $waterDrawingPaperworkPec->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']); ?> + can_delete_pec ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPaperworkPecs', 'action' => 'delete', $waterDrawingPaperworkPec->id], ['confirm' => __('Sei sicuro che vuoi cancellare la documentazione PEC "{0}" ?', $waterDrawingPaperworkPec->id), 'class' => 'btn btn-danger btn-xs', 'style' => 'margin-right:1rem']) : null; ?> +
+
+ +
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('user_id', __('Utente')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+ +
+
+

+
+
+
+ can_send_to_drar ? $this->Html->link(__('Invia pratica al DRAR'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_drar', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro di inviare la pratica al DRAR?'), 'class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_send_to_gc ? $this->Html->link(__('Invia pratica al GC'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'send_to_gc', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro di inviare la pratica al Genio Civile di competenza?'), 'class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_assign_to_drar ? $this->Html->link(__('Assegna pratica DRAR'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'assign', $waterDrawingPaperwork->id, 6], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_assign_to_gc ? $this->Html->link(__('Assegna pratica GC'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'assign', $waterDrawingPaperwork->id, 0], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_validate ? $this->Html->link(__('Verifica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'validate', $waterDrawingPaperwork->id], ['class' => 'btn btn-info btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_edit ? $this->Html->link(__('Modifica'), ['action' => 'edit', $waterDrawingPaperwork->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']) : null; + echo $waterDrawingPaperwork->can_delete ? $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingPaperwork->id], ['confirm' => __('Sei sicuro che vuoi cancellare la pratica di attingimento "{0}" ?', $waterDrawingPaperwork->id), 'class' => 'btn btn-danger btn-xs']) : null; + ?> +
+
+
+ +Form->end() ?> + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/view_scan.php b/idrocap_wa/templates/WaterDrawingPaperworks/view_scan.php new file mode 100644 index 0000000..f1bacb8 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/view_scan.php @@ -0,0 +1,727 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento scansionata'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+ +

+ can_view_snapshots ? $this->Html->link(__('Storico pratica'), ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], ['style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ +
+ + + water_drawing_paperwork_status_id > 5): ?> + + water_drawing_paperwork_status_id > 3): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + water_drawing_paperwork_status_id > 5): + ?> + + + +
+
+
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dam ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+ Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + fieldRequired: true, + disabled: true, + fieldType: ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? InputFieldType::SELECT : InputFieldType::HIDDEN), + showProvinceFullName: true + ) + ] + ) ?> + +
+ Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'text' : 'hidden'), 'disabled' => true]) ?> +
+
+ Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'type' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? 'select' : 'hidden'), 'options' => $WaterDrawingArticles, 'disabled' => true]) ?> +
+ +
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'water_drawing_paperwork_status_id' => $waterDrawingPaperwork->water_drawing_paperwork_status_id, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +water_drawing_paperwork_status_id > 5): ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + + +
latitude, $waterDrawingDerivation->longitude) ? (number_format((float) $waterDrawingDerivation->latitude, 4) . ', ' . number_format((float) $waterDrawingDerivation->longitude, 4)) : '')?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>Html->link(__('Dettaglio'), ['controller' => 'WaterDrawingDerivations', 'action' => 'view', $waterDrawingDerivation->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 3) : ?> +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>Html->link(__('Dettaglio'), ['controller' => 'waterDrawingReturnPoints', 'action' => 'view', $waterDrawingReturnPoint->id], ['class' => 'btn btn-info btn-xs']) ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): + ?> +
+ Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> +
+ +
+ Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> +
+
+ Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'pattern' => ($waterDrawingPaperwork->water_drawing_paperwork_status_id > 5 ? '[0-9]*' : ''), 'disabled' => true]) ?> +
+ +
+ Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'style' => 'margin-left: 5px;', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): ?> +
+ Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> +
+ water_drawing_paperwork_status_id > 5): + ?> +
+ Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+ +
+
+
+ +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingFees', 'action' => 'edit', $waterDrawingFees->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingFees', 'action' => 'view', $waterDrawingFees->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?> + can_add_payment ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + can_view_payment ? $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) : null ?> +
+ +
+ water_drawing_paperwork_status_id <= 5) : ?> + + +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + if (isset($waterDrawingIntendedUse->water_drawing_intended_use_type_id)): + ?> + + + + + + + + + + +
water_drawing_intended_use_type->description) ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date?->format('d/m/Y') : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>water_drawing_meters[0]->id)) { + echo $this->Html->link(__('Dettagli'), ['controller' => 'WaterDrawingMeters', 'action' => 'view', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-info btn-xs']); + echo $this->Html->link(__('Dismetti'), ['controller' => 'WaterDrawingMeters', 'action' => 'dismiss', $waterDrawingIntendedUse->water_drawing_meters[0]->id], ['class' => 'btn btn-danger btn-xs']); + } else { + echo $this->Html->link(__('Aggiungi strumento di misura'), ['controller' => 'WaterDrawingMeters', 'action' => 'add', $waterDrawingIntendedUse->id], ['class' => 'btn btn-success btn-xs']); + } + ?>
+
+ +
+ + +water_drawing_paperwork_status_id > 5) : ?> +
+
+

+ +

+
+ +
+
+
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> +
+
+ Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+
+
+ + +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('result', __('Esito della verifica')) ?>Paginator->sort('note', __('Note')) ?>Paginator->sort('user_id', __('Utente')) ?>Paginator->sort('created', __('Data e ora della verifica')) ?>
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+ +
+
+

+
+ +
+ +Form->end() ?> + + + diff --git a/idrocap_wa/templates/WaterDrawingPaperworks/view_snapshot.php b/idrocap_wa/templates/WaterDrawingPaperworks/view_snapshot.php new file mode 100644 index 0000000..cf408dd --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPaperworks/view_snapshot.php @@ -0,0 +1,641 @@ + +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Logs Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots_all'], + ], + [ + 'title' => __('Dettagli Istantanea Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], + ]); +} else { + echo $this->Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan' : 'view'), $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Storico Pratica di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index_snapshots', $waterDrawingPaperwork->id], + ], + [ + 'title' => __('Dettagli Istantanea Pratica di attingimento'), + 'icon' => 'fa fa-info', + ], + ]); +} +?> + +
+
+

i18nFormat('dd/MM/Y HH:mm:ss', $logged_user_timezone) : null)); ?>

+ Html->link('' . __('Istantanea precedente'), ['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan_snapshot' : 'view_snapshot'), $previous_snapshot_id, '?' => $back_to_logs ? ['origin' => 'logs'] : []], ['escape' => false, 'style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> + Html->link(__('Istantanea successiva') . '', ['controller' => 'WaterDrawingPaperworks', 'action' => ($waterDrawingPaperwork->scanned ? 'view_scan_snapshot' : 'view_snapshot'), $next_snapshot_id, '?' => $back_to_logs ? ['origin' => 'logs'] : []], ['escape' => false, 'style="margin-left:1rem;"', 'class' => 'btn btn-info btn-xs']) : '' ?> +
+
+ +
+ +
+ +Form->create($waterDrawingPaperwork, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> + +
+
+

+ +

+
+ +
+
+
+ Form->control('water_drawing_paperwork_status.description', ['label' => __('Stato della pratica'), 'type' => 'text', 'disabled' => true, 'required' => false]) ?> + Form->control('gc_user', ['label' => __('Assegnatario Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('drar_user', ['label' => __('Assegnatario DRAR'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
check_thc ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -8], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dv ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -7], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_lic ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -6], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dec ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -5], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_sdd ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -10], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dsc ? __('Presente') : __('Assente ') . (((($logged_user_id === $waterDrawingPaperwork->gc_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < 0) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -4], ['class' => 'btn btn-danger btn-xs']) : null) ?>check2a ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_edit && (($logged_user_id === $waterDrawingPaperwork->gc_user_id) || ($logged_user_id === $waterDrawingPaperwork->drar_user_id && $waterDrawingPaperwork->water_drawing_paperwork_status_id < -2))) ? $this->Html->link(__('Carica'), ['action' => 'upload_attachment', $waterDrawingPaperwork->id, -3], ['class' => 'btn btn-danger btn-xs']) : null) ?>check_dam ? __('Presente') : __('Assente ') . (($waterDrawingPaperwork->can_upload_antimafia_attachment) ? $this->Html->link(__('Carica'), ['action' => 'upload_antimafia_attachment', $waterDrawingPaperwork->id], ['class' => 'btn btn-danger btn-xs']) : null) ?>
+
+
+ element('attachments', [ + 'coId' => $waterDrawingPaperwork->controllable_object_id, + 'filepicker' => false, + 'viewer' => true, + 'currentFilesRemovable' => false, + 'view_in_frame_with_id' => 'previewiframe', + ]); + ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('authority_civil_engineer_code', ['label' => __('Codice Genio Civile'), 'type' => 'text', 'disabled' => true]) ?> + Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: "authority-province", + fieldName: "authority_province", + formContext: $waterDrawingPaperwork, + fieldRequired: true, + disabled: true, + fieldContainerClass: "", + showProvinceFullName: true + ) + ] + ) ?> + Form->control('authority_identification_code_civil_engineering_office', ['label' => __('Codice identificativo Concessione Ufficio Genio civile (es. AA0000)'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'required' => true, 'disabled' => true]) ?> + Form->control('authority_identification_code_derivation_department_water_waste', ['label' => __('Codice identificativo Concessione Dipartimento Acqua e rifiuti'), 'type' => 'text', 'pattern' => '[a-zA-Z]{2}[0-9]{4}', 'disabled' => true]) ?> + Form->control('water_drawing_article_id', ['label' => __('Articolo'), 'options' => $WaterDrawingArticles, 'empty' => true, 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+
+ applicants) == 0) echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => 0, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $waterDrawingPaperwork->applicants]); + foreach ($waterDrawingPaperwork->applicants as $applicant_item_block => $applicant) { + echo $this->element('WaterDrawingPaperworks/applicants', ['applicant_item_block' => $applicant_item_block, 'is_view' => true, 'formContext' => $waterDrawingPaperwork, 'districtProvinceApplicant' => $applicant]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + water_drawing_derivations as $waterDrawingDerivation) : ?> + + + + + + + + + + + + + +
latitude . ', ' . $waterDrawingDerivation->longitude) ?>water_drawing_derivation_type_id) ? $waterDrawingDerivation->water_drawing_derivation_type->description : null) ?>water_body) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>derivation_status) ?>annual_volume) ?>average_flow_rate ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+
+ water_drawing_intended_uses as $water_drawing_intended_use_item_block => $waterDrawingIntendedUse) { + echo $this->element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $water_drawing_intended_use_item_block, 'is_view' => true, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); + } + ?> +
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + water_drawing_return_points as $waterDrawingReturnPoint) : ?> + + + + + + + + +
latitude . ', ' . $waterDrawingReturnPoint->longitude) ?>district) ?>cadastral_sheet) ?>cadastral_parcel) ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('from_date', ['label' => __('Dal'), 'type' => 'date', 'disabled' => true]) ?> + Form->control('to_date', ['label' => __('Al'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('gurs_reference', ['label' => __('Estremi GURS con pubblicazione istanza'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('authorisation_type', ['label' => __('Natura del provvedimento di autorizzazione'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('concession_decree_number', ['label' => __('Decreto di Concessione n° (o di riconoscimento del diritto di derivazione)'), 'disabled' => true]) ?> + Form->control('release_date', ['label' => __('Data di rilascio del provvedimento'), 'disabled' => true]) ?> + Form->control('concession_duration', ['label' => __('Durata Concessione (in anni)'), 'type' => 'number', 'disabled' => true]) ?> + Form->control('expiration_date', ['label' => __('Validità fino a (scadenza del provvedimento)'), 'disabled' => true]) ?> + Form->control('first_istance', ['label' => __('Prima istanza'), 'type' => 'text', 'disabled' => true]) ?> + Form->control('takeover', ['label' => __('Subentro'), 'type' => 'text', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ can_view_fee): ?> +
+

+ +

+
+ + + + + + + + + + water_drawing_fees as $waterDrawingFees) : ?> + + + + + + + +
year) ?>amount . ' €') ?>to_pay . ' €') ?>
+ + can_view_payment): ?> +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee_year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>created) ?>user) ?>
+ +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + water_drawing_intended_uses as $waterDrawingIntendedUse) : + ?> + + + + + + + + + +
water_drawing_intended_use_type->description ?? '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->water_drawing_tool_type->description : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->installation_date : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->manufacturer : '') ?>water_drawing_meters[0]) ? $waterDrawingIntendedUse->water_drawing_meters[0]->part_number : '') ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ Form->control('static_level_water', ['label' => __('Livello statico dal boccaforo al momento del rinvenimento dell\'acqua (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> + Form->control('static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> + Form->control('initial_static_level_water', ['label' => __('Livello statico dal boccaforo il giorno di inizio derivazione (cm)'), 'type' => 'number', 'pattern' => '[0-9]*', 'disabled' => true]) ?> + Form->control('initial_static_level_water_date', ['label' => __('Data del rilievo'), 'type' => 'date', 'disabled' => true]) ?> +
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_antimafia_certification_requests as $waterDrawinAntimafiaRequest) : ?> + + + + + + + +
user) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>water_drawing_antimafia_certification_request_status->description) . ($waterDrawinAntimafiaRequest->water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? __(' - Richiesta scaduta') : null) ?>water_drawing_antimafia_certification_request_status_id == 2 && $waterDrawingPaperwork->can_request_self_certification ? 'style="color:red;"' : null ?>>created) ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + water_drawing_paperwork_pecs as $waterDrawingPaperworkPec) : ?> + + + + + + + +
document) ?>protocol_number) ?>protocol_date) ?>
+
+
+ +
+
+

+ +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
result == 1 ? 'Accettata' : 'Rifiutata') ?>note) ?>user) ?>created) ?>controllable_object->attachment_file_names) ? $this->Html->link(__('Visualizza'), ['controller' => 'Attachments', 'action' => 'view', array_keys($waterDrawingPaperworkHistory->controllable_object->attachment_file_names)[0]], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem', 'target' => '_blank']) : null ?>
+
+
+ +Form->end() ?> + + + + diff --git a/idrocap_wa/templates/WaterDrawingPayments/add.php b/idrocap_wa/templates/WaterDrawingPayments/add.php new file mode 100644 index 0000000..1bf3c60 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/add.php @@ -0,0 +1,93 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view_scan', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Nuovo pagamento'), + 'icon' => 'fa fa-plus', + ], + ]); +?> + +
+
+

+
+ Form->create($waterDrawingPayment, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_fee_id', ['label' => __('Anno'), 'options' => $waterDrawingFees, 'empty' => true, 'required' => true]);?> +
+
+ Form->control('water_drawing_payment_type_id', ['label' => __('Tipologia di pagamento'), 'empty' => true]); ?> +
+
+ Form->control('amount', ['label' => __('Importo'), 'min' => 0]); ?> +
+
+ Form->control('payment_number', ['label' => __('Numero del pagamento')]); ?> +
+
+
+
+ Form->control('receipt_number', ['label' => __('Numero quietanza')]); ?> +
+
+ Form->control('receipt_amount', ['label' => __('Importo quietanza'), 'min' => 0]); ?> +
+
+ Form->control('applicant_tax_code', ['label' => __('Codice fiscale concessionario'), 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('payment_date', ['label' => __('Data pagamento'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('receipt_date', ['label' => __('Data quietanza'), 'type' => 'date', 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('notes', ['label' => __('Note')]); ?> +
+
+
+ + Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPayments/edit.php b/idrocap_wa/templates/WaterDrawingPayments/edit.php new file mode 100644 index 0000000..250ec5e --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/edit.php @@ -0,0 +1,92 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica pagamento'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPayment, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_fee_id', ['label' => __('Anno'), 'options' => $waterDrawingFees, 'empty' => true, 'required' => true]); ?> +
+
+ Form->control('water_drawing_payment_type_id', ['label' => __('Tipologia di pagamento'), 'empty' => true]); ?> +
+
+ Form->control('amount', ['label' => __('Importo'), 'min' => 0]); ?> +
+
+ Form->control('payment_number', ['label' => __('Numero del pagamento')]); ?> +
+
+
+
+ Form->control('receipt_number', ['label' => __('Numero quietanza')]); ?> +
+
+ Form->control('receipt_amount', ['label' => __('Importo quietanza'), 'min' => 0]); ?> +
+
+ Form->control('applicant_tax_code', ['label' => __('Codice fiscale concessionario'), 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('payment_date', ['label' => __('Data pagamento'), 'max' => $today->format('Y-m-d')]); ?> +
+
+ Form->control('receipt_date', ['label' => __('Data quietanza'), 'type' => 'date', 'max' => $today->format('Y-m-d')]); ?> +
+
+
+
+ Form->control('notes', ['label' => __('Note')]); ?> +
+
+
+
+ +Form->end(); ?> +
+ + diff --git a/idrocap_wa/templates/WaterDrawingPayments/index.php b/idrocap_wa/templates/WaterDrawingPayments/index.php new file mode 100644 index 0000000..54e63a1 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/index.php @@ -0,0 +1,83 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Lista pagamenti'), + 'icon' => 'fa fa-list', + ], +]); +?> + +Cell('Filters', [__('Filtri')]) ?> + +
+
+

+ $filtered_water_drawing_payments ? __('{0} su {1}', $filtered_water_drawing_payments, $total_water_drawing_payments) : $total_water_drawing_payments, $water_drawing_paperwork_id) ?> +

+ Html->link(__('Esporta lista (CSV)'), ['controller' => 'WaterDrawingPayments', 'action' => 'index', '_ext' => 'csv', $water_drawing_paperwork_id], ['class' => 'btn btn-success btn-xs']) : null ?> +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
water_drawing_fee->year) ?>payment_date) ?>payment_number) ?>amount) ?>water_drawing_payment_type->description) ?>applicant_tax_code) ?> + can_edit ? $this->Html->link(__('Modifica'), ['controller' => 'WaterDrawingPayments', 'action' => 'edit', $waterDrawingPayment->id], ['class' => 'btn btn-warning btn-xs']) : null ?> + Html->link(__('Dettagli'), ['controller' => 'WaterDrawingPayments', 'action' => 'view', $waterDrawingPayment->id], ['class' => 'btn btn-info btn-xs']) ?> + can_delete ? $this->Form->postLink(__('Cancella'), ['controller' => 'WaterDrawingPayments', 'action' => 'delete', $waterDrawingPayment->id], ['confirm' => __('Sei sicuro che vuoi cancellare il pagamento n° "{0}" ?', $waterDrawingPayment->payment_number), 'class' => 'btn btn-danger btn-xs']) : null ?> +
+
+ +
diff --git a/idrocap_wa/templates/WaterDrawingPayments/view.php b/idrocap_wa/templates/WaterDrawingPayments/view.php new file mode 100644 index 0000000..c6a26e2 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingPayments/view.php @@ -0,0 +1,95 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingPayment->water_drawing_fee->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli pagamento'), + 'icon' => 'fa fa-plus', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingPayment, ['role' => 'form', 'type' => 'file']); ?> +
+
+
+ Form->control('water_drawing_fee_id', ['label' => __('Anno'), 'options' => $waterDrawingFees, 'empty' => true, 'disabled' => true]); ?> +
+
+ Form->control('water_drawing_payment_type_id', ['label' => __('Tipologia di pagamento'), 'empty' => true, 'disabled' => true]); ?> +
+
+ Form->control('amount', ['label' => __('Importo'), 'min' => 0, 'disabled' => true]); ?> +
+
+ Form->control('payment_number', ['label' => __('Numero del pagamento'), 'disabled' => true]); ?> +
+
+
+
+ Form->control('receipt_number', ['label' => __('Numero quietanza'), 'disabled' => true]); ?> +
+
+ Form->control('receipt_amount', ['label' => __('Importo quietanza'), 'min' => 0, 'disabled' => true]); ?> +
+
+ Form->control('applicant_tax_code', ['label' => __('Codice fiscale concessionario'), 'disabled' => true]); ?> +
+
+
+
+ Form->control('payment_date', ['label' => __('Data pagamento'), 'disabled' => true]); ?> +
+
+ Form->control('receipt_date', ['label' => __('Data quietanza'), 'type' => 'date', 'disabled' => true]); ?> +
+
+
+
+ Form->control('notes', ['label' => __('Note'), 'disabled' => true]); ?> +
+
+ Form->end(); ?> +
+ +
+ + + diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/add.php b/idrocap_wa/templates/WaterDrawingReturnPoints/add.php new file mode 100644 index 0000000..a0baa52 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/add.php @@ -0,0 +1,125 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $water_drawing_paperwork_id], + ], + [ + 'title' => __('Aggiungi Punto di restituzione'), + 'icon' => 'fa fa-plus', + ], +]); +?> + + +
+
+

+
+ Form->create($waterDrawingReturnPoint, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> +
+
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+ Form->end(); ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/edit.php b/idrocap_wa/templates/WaterDrawingReturnPoints/edit.php new file mode 100644 index 0000000..aff970c --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/edit.php @@ -0,0 +1,124 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id], + ], + [ + 'title' => __('Modifica Punto di restituzione'), + 'icon' => 'fa fa-pencil-alt', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingReturnPoint, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> +
+
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => true, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => true, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'min' => 0]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'readonly' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'readonly' => true]) ?> +
+
+
+ Form->submit(__('Salva'), ['id' => 'submitForm']); ?> +
+ Form->end(); ?> +
+
+
diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/index.php b/idrocap_wa/templates/WaterDrawingReturnPoints/index.php new file mode 100644 index 0000000..4a1e400 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/index.php @@ -0,0 +1,54 @@ + $waterDrawingReturnPoints + */ +?> +
+ Html->link(__('New Water Drawing Return Point'), ['action' => 'add'], ['class' => 'button float-right']) ?> +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Paginator->sort('id') ?>Paginator->sort('latitude') ?>Paginator->sort('longitude') ?>Paginator->sort('district') ?>Paginator->sort('cadastral_sheet') ?>Paginator->sort('cadastral_parcel') ?>Paginator->sort('water_drawing_paperwork_id') ?>
Number->format($waterDrawingReturnPoint->id) ?>latitude) ?>longitude) ?>district) ?>cadastral_sheet === null ? '' : $this->Number->format($waterDrawingReturnPoint->cadastral_sheet) ?>cadastral_parcel === null ? '' : $this->Number->format($waterDrawingReturnPoint->cadastral_parcel) ?>hasValue('water_drawing_paperwork') ? $this->Html->link($waterDrawingReturnPoint->water_drawing_paperwork->id, ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork->id]) : '' ?> + Html->link(__('View'), ['action' => 'view', $waterDrawingReturnPoint->id]) ?> + Html->link(__('Edit'), ['action' => 'edit', $waterDrawingReturnPoint->id]) ?> + Form->postLink(__('Delete'), ['action' => 'delete', $waterDrawingReturnPoint->id], ['confirm' => __('Are you sure you want to delete # {0}?', $waterDrawingReturnPoint->id)]) ?> +
+
+
+
    + Paginator->first('<< ' . __('first')) ?> + Paginator->prev('< ' . __('previous')) ?> + Paginator->numbers() ?> + Paginator->next(__('next') . ' >') ?> + Paginator->last(__('last') . ' >>') ?> +
+

Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?>

+
+
diff --git a/idrocap_wa/templates/WaterDrawingReturnPoints/view.php b/idrocap_wa/templates/WaterDrawingReturnPoints/view.php new file mode 100644 index 0000000..26f6132 --- /dev/null +++ b/idrocap_wa/templates/WaterDrawingReturnPoints/view.php @@ -0,0 +1,128 @@ +Breadcrumb->render([ + [ + 'title' => 'Home', + 'icon' => 'fa fa-home', + 'url' => '/', + ], + [ + 'title' => __('Documenti'), + 'icon' => 'fa fa-book', + ], + [ + 'title' => __('Lista Pratiche di attingimento'), + 'icon' => 'fa fa-list', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'index'], + ], + [ + 'title' => __('Dettagli Pratica di attingimento'), + 'icon' => 'fa fa-info', + 'url' => ['controller' => 'WaterDrawingPaperworks', 'action' => 'view', $waterDrawingReturnPoint->water_drawing_paperwork_id], + ], + [ + 'title' => __('Dettagli Punto di restituzione'), + 'icon' => 'fa fa-info', + ], +]); +?> + +
+
+

+
+ Form->create($waterDrawingReturnPoint, ['id' => 'myForm', 'role' => 'form', 'type' => 'file']); ?> +
+
+
+ Cell('Map', [ + null, // Array $layer_ids = null -> null = nessun layer verrà caricato. [] = tutti i layers della table maps verranno caricati. [1,2,3] = solamente i layers della table maps con id 1,2 e 3 verranno caricati + false, // Bool $get_current_position = false -> true = viene eseguito lo zoom in mappa sulla posizione utente (se disponibile dal browser e l'utente da i permessi) + [ // Array $tools = null -> null/[] = nessun tool verrà visualizzato in mappa. Altrimenti verranno inseriti i tools specificati e le relative configurazioni come specificato di seguito + 'drawing_layer_name' // String $drawing_layer_name = null -> se specificato, verrà utilizzato come nome del layer che gestisce le geometrie disegnate. Se lasciato vuoto o null, il nome di default verrà utilizzato + => __('Posizione Punto di prelievo/derivazione'), + 'geocoding' => false, // Bool $geocoding = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "freccia di localizzazione" per accedere alla funzione di geocoding. se l'indirizzo inserito è valido, verrà inserito un punto in mappa nella relativa location individuata + 'point' => false, // Bool $point = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "marker" per attivare la funzione di inserimento punti in mappa + 'multiple_points' => false, // Bool $multiple_points = false -> se true, permette l'inserimento di più punti in mappa. ATTENZIONE: se il tool di geocoding è attivo, $multiple_points non verrà considerato e non sarà permesso inserire più punti in mappa! + 'polygon' => false, // Bool $polygon = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "polygon" per attivare la funzione di disegno poligoni in mappa + 'circle' => false, // Bool $circle = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "circle" per attivare la funzione di disegno cerchi in mappa + 'delete_geometry' => false, // Bool $delete-geometry = false -> se true, visualizza in mappa (nel riquadro dei tools in alto a sinistra) un button con icona "cestino" per attivare la funzione di cancellazione geometrie (puntare sulla geometria precedentemente disegnata che si vuole eliminare). ATTENZIONE: se nessuno tra $geocoding, $point, $polygon e $circle è true, il button di cancellazione non verrà renderizzato! + 'fields' => [ // Array $fields = null -> null/[] = nessun campo verrà renderizzato o fillato. Altrimenti verranno gestiti i campi in base alle relative configurazioni come specificato di seguito + 'longitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'longitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'longitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lon'), + ], + 'latitude' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => true, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'latitude', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'latitude', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Coordinata WGS84 EPSG:4326 Lat'), + ], + 'district' => [ // Array = null -> null/[] = il campo feature_collection non verrà gestito. Altrimenti verrà gestito come specificato di seguito + 'render' => false, // Bool $render = false -> se true, verrà renderizzato il campo. Nota: se $render è false, $hidden, $name e $description (se specificati) non verranno utilizzati. Invece $id (se specificato) permetterà il filling del campo esistente con id specificato + 'hidden' => false, // Bool $hidden = false -> se true, verrà renderizzato il campo NASCOSTO. Nota: se $render = false, non verrà preso in considerazione + 'readonly' => false, // Bool $readonly = false -> se true, verrà renderizzato il campo in modalità READ ONLY. Nota: se $render = false, non verrà preso in considerazione + 'id' // String $id = null -> se specificato, verrà utilizzato come id del campo. Nota: se $render è false, questo id verrà utilizzato per il filling del campo già esistente con l'id specifiato + => 'district', + 'name' // String $name = null -> se specificato, verrà utilizzato come name del campo. Nota: se $render = false, non verrà preso in considerazione + => 'district', + 'label' // String $label = null -> se specificato, verrà utilizzato come label del campo. Nota: se $render = false, non verrà preso in considerazione + => __('Comune'), + ], + ], + 'geo_resources' => [ // Array = null -> null/[] = geo_resources serve a specificare delle geo-risorse dalle quali vogliamo estrarre degli attributi. per ogni geo-risorsa, tra le altre cose, bisogna specificare il mapping dei campi nella forma "attributo_geo_risorsa":"id-campo-nel-form" + [ + 'external' => true, // se la geo-risorsa è un servizio esterno, bisogna specificare 'external' => true! + 'url' // se la geo-risorsa è esterna va specificata la 'url' per chiamare il servizio + => 'https://wms.cartografia.agenziaentrate.gov.it/inspire/ajax/ajax.php?op=getDatiOggetto', + 'lon_parameter_name' => 'lon', // lon_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lon' + 'lat_parameter_name' => 'lat', // lat_parameter_name specifica come si chiama il parametro del servizio esterno per fornire in input la coordinata 'lat' + 'attributes_fields' => [ // elenco key/value che specifica gli attributi(KEY) da estrarre dalla geo-risorsa ed il corrispondere ID del campo(VALUE) del form a cui assegnare il valore estratto dall'attributo. + 'FOGLIO' => 'cadastral-sheet', + 'NUM_PART' => 'cadastral-parcel', + ], + ], + ], + ], + null, // Int $zoom_to_layer_with_id = null -> se si specifica un Int, verrà eseguito lo zoom sull'extent del layer con quell'id + ]); ?> + Form->control('feature_collection', ['type' => 'hidden']); ?> +
+
+ Form->control('district', ['label' => __('Comune'), 'type' => 'text', 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_sheet', ['label' => __('Foglio di Mappa'), 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('cadastral_parcel', ['label' => __('Particella'), 'requred' => true, 'disabled' => true]) ?> +
+
+ Form->control('longitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lon'), 'disabled' => true, 'disabled' => true]) ?> +
+
+ Form->control('latitude', ['label' => __('Coordinata WGS84 EPSG:4326 Lat'), 'disabled' => true, 'disabled' => true]) ?> +
+ Form->end(); ?> +
+
+ Html->link(__('Modifica'), ['action' => 'edit', $waterDrawingReturnPoint->id], ['class' => 'btn btn-warning btn-xs', 'style' => 'margin-right:1rem']); + echo $this->Form->postLink(__('Cancella'), ['action' => 'delete', $waterDrawingReturnPoint->id], ['confirm' => __('Sei sicuro che vuoi cancellare la pratica di attingimento "{0}" ?', $waterDrawingReturnPoint->id), 'class' => 'btn btn-danger btn-xs']); + ?> +
+
+
+
+
diff --git a/idrocap_wa/templates/cell/.gitkeep b/idrocap_wa/templates/cell/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/idrocap_wa/templates/cell/.gitkeep @@ -0,0 +1 @@ + diff --git a/idrocap_wa/templates/cell/DistrictProvince/display.php b/idrocap_wa/templates/cell/DistrictProvince/display.php new file mode 100644 index 0000000..2388116 --- /dev/null +++ b/idrocap_wa/templates/cell/DistrictProvince/display.php @@ -0,0 +1,41 @@ + + + + +
+ element("provinceSelect", [ + 'provinceConfig' => $provinceCellConfig, + "provinces" => $provinces['options'] ?? null + ]) ?> +
+ + + +
+ element("districtSelect", [ + 'districtConfig' => $districtCellConfig, + "codReg" => $codReg, + "provinces" => isset($provinces) && is_array($provinces) ? $provinces['map'] : null + ]) ?> +
+ diff --git a/idrocap_wa/templates/cell/FilterInput/display.php b/idrocap_wa/templates/cell/FilterInput/display.php new file mode 100644 index 0000000..cf532dd --- /dev/null +++ b/idrocap_wa/templates/cell/FilterInput/display.php @@ -0,0 +1,12 @@ +
+
+
+ Form->control('filters[' . $name . '][]', ['label' => $label, 'type' => $type, 'options' => $options, 'value' => $value, 'class' => "form-control$additional_classes"]); + ?> +
+
+ +
+
+
diff --git a/idrocap_wa/templates/cell/Filters/display.php b/idrocap_wa/templates/cell/Filters/display.php new file mode 100755 index 0000000..d06a21a --- /dev/null +++ b/idrocap_wa/templates/cell/Filters/display.php @@ -0,0 +1,152 @@ +
+
+

+ + +

+
+ +
+
+ + +
+Html->script('moment'); ?> +Html->script('jixel-primitives'); ?> + diff --git a/idrocap_wa/templates/cell/IntendedUses/display.php b/idrocap_wa/templates/cell/IntendedUses/display.php new file mode 100644 index 0000000..8a7f713 --- /dev/null +++ b/idrocap_wa/templates/cell/IntendedUses/display.php @@ -0,0 +1 @@ +Element('WaterDrawingPaperworks/intended_uses', ['intended_use_item_block' => $intended_use_item_block, 'intendedUseTypes' => $intendedUseTypes, 'cadastralCropTypes' => $cadastralCropTypes, 'wateringSystems' => $wateringSystems]); ?> diff --git a/idrocap_wa/templates/cell/Map/display.php b/idrocap_wa/templates/cell/Map/display.php new file mode 100755 index 0000000..bd4e174 --- /dev/null +++ b/idrocap_wa/templates/cell/Map/display.php @@ -0,0 +1,13 @@ +Element('Map', ['layers' => $layers, 'get_current_position' => $get_current_position, 'tools' => $tools, 'drawing_layer_name' => $drawing_layer_name, 'geocoding' => $geocoding, 'point' => $point, 'multiple_points' => $multiple_points, 'polygon' => $polygon, 'circle' => $circle, 'delete_geometry' => $delete_geometry, 'feature_collection_id' => $feature_collection['id'] ?? 'feature-collection', 'longitude_id' => $longitude['id'] ?? 'longitude', 'latitude_id' => $latitude['id'] ?? 'latitude', 'coordinates_id' => $coordinates['id'] ?? 'coordinates', 'cap_id' => $cap['id'] ?? 'cap', 'province_id' => $province['id'] ?? 'province', 'district_code_id' => $district_code['id'] ?? 'district-code', 'district_id' => $district['id'] ?? 'district', 'address_id' => $address['id'] ?? 'address', 'description_id' => $description['id'] ?? 'description', 'geo_resources' => $geo_resources]); + if ($feature_collection !== false && isset($feature_collection['render']) && $feature_collection['render'] === true) echo $this->Form->control($feature_collection['name'] ?? 'feature_collection', ['id' => $feature_collection['id'] ?? 'feature-collection', 'type' => isset($feature_collection['hidden']) && $feature_collection['hidden'] === true ? 'hidden' : 'text', 'label' => $feature_collection['label'] ?? null, 'readonly' => isset($feature_collection['readonly']) && $feature_collection['readonly'] === true]); + if ($longitude !== false && isset($longitude['render']) && $longitude['render'] === true) echo $this->Form->control($longitude['name'] ?? 'longitude', ['id' => $longitude['id'] ?? 'longitude', 'type' => isset($longitude['hidden']) && $longitude['hidden'] === true ? 'hidden' : 'text', 'label' => $longitude['label'] ?? null, 'readonly' => isset($longitude['readonly']) && $longitude['readonly'] === true]); + if ($latitude !== false && isset($latitude['render']) && $latitude['render'] === true) echo $this->Form->control($latitude['name'] ?? 'latitude', ['id' => $latitude['id'] ?? 'latitude', 'type' => isset($latitude['hidden']) && $latitude['hidden'] === true ? 'hidden' : 'text', 'label' => $latitude['label'] ?? null, 'readonly' => isset($latitude['readonly']) && $latitude['readonly'] === true]); + if ($coordinates !== false && isset($coordinates['render']) && $coordinates['render'] === true) echo $this->Form->control($coordinates['name'] ?? 'coordinates', ['id' => $coordinates['id'] ?? 'coordinates', 'type' => isset($coordinates['hidden']) && $coordinates['hidden'] === true ? 'hidden' : 'text', 'label' => $coordinates['label'] ?? null, 'readonly' => isset($coordinates['readonly']) && $coordinates['readonly'] === true]); + if ($cap !== false && isset($cap['render']) && $cap['render'] === true) echo $this->Form->control($cap['name'] ?? 'cap', ['id' => $cap['id'] ?? 'cap', 'type' => isset($cap['hidden']) && $cap['hidden'] === true ? 'hidden' : 'text', 'label' => $cap['label'] ?? null, 'readonly' => isset($cap['readonly']) && $cap['readonly'] === true]); + if ($province !== false && isset($province['render']) && $province['render'] === true) echo $this->Form->control($province['name'] ?? 'province', ['id' => $province['id'] ?? 'province', 'type' => isset($province['hidden']) && $province['hidden'] === true ? 'hidden' : 'text', 'label' => $province['label'] ?? null, 'readonly' => isset($province['readonly']) && $province['readonly'] === true]); + if ($district_code !== false && isset($district_code['render']) && $district_code['render'] === true) echo $this->Form->control($district_code['name'] ?? 'district_code', ['id' => $district_code['id'] ?? 'district-code', 'type' => isset($district_code['hidden']) && $district_code['hidden'] === true ? 'hidden' : 'text', 'label' => $district_code['label'] ?? null, 'readonly' => isset($district_code['readonly']) && $district_code['readonly'] === true]); + if ($district !== false && isset($district['render']) && $district['render'] === true) echo $this->Form->control($district['name'] ?? 'district', ['id' => $district['id'] ?? 'district', 'type' => isset($district['hidden']) && $district['hidden'] === true ? 'hidden' : 'text', 'label' => $district['label'] ?? null, 'readonly' => isset($district['readonly']) && $district['readonly'] === true]); + if ($address !== false && isset($address['render']) && $address['render'] === true) echo $this->Form->control($address['name'] ?? 'address', ['id' => $address['id'] ?? 'address', 'type' => isset($address['hidden']) && $address['hidden'] === true ? 'hidden' : 'text', 'label' => $address['label'] ?? null, 'readonly' => isset($address['readonly']) && $address['readonly'] === true]); + if ($description !== false && isset($description['render']) && $description['render'] === true) echo $this->Form->control($description['name'] ?? 'description', ['id' => $description['id'] ?? 'description', 'type' => isset($description['hidden']) && $description['hidden'] === true ? 'hidden' : 'text', 'label' => $description['label'] ?? null, 'readonly' => isset($description['readonly']) && $description['readonly'] === true]); +?> \ No newline at end of file diff --git a/idrocap_wa/templates/element/Map.php b/idrocap_wa/templates/element/Map.php new file mode 100755 index 0000000..da37f83 --- /dev/null +++ b/idrocap_wa/templates/element/Map.php @@ -0,0 +1,622 @@ +element('./MapCore/MapPrimitives') ?> + + diff --git a/idrocap_wa/templates/element/MapCore/MapPrimitives.php b/idrocap_wa/templates/element/MapCore/MapPrimitives.php new file mode 100644 index 0000000..42cfb31 --- /dev/null +++ b/idrocap_wa/templates/element/MapCore/MapPrimitives.php @@ -0,0 +1,373 @@ +Html->css('/node_modules/ol/ol'); ?> +Html->css('/ol-ext/ol-ext.min'); ?> +Html->css('jixel_ol'); ?> + +
+
+
+
+ +
+
+
+ +
+ + + + + + + + + + + + + + + +
+ +Html->script('/node_modules/ol/dist/ol'); ?> +Html->script('/ol-ext/ol-ext.min'); ?> +Html->script('moment'); ?> +Html->script('jixel-primitives'); ?> + diff --git a/idrocap_wa/templates/element/WaterDrawingPaperworks/applicants.php b/idrocap_wa/templates/element/WaterDrawingPaperworks/applicants.php new file mode 100644 index 0000000..bcac0ce --- /dev/null +++ b/idrocap_wa/templates/element/WaterDrawingPaperworks/applicants.php @@ -0,0 +1,196 @@ +province ?? null) : null; +$district = $applicant ? ($applicant->district ?? null) : null; +?> +
+
+
+

+
+ +
+ Form->control('select2applicants-' . $applicant_item_block, ['id' => 'select2applicants-' . $applicant_item_block, 'label' => __('Ricerca concessionario'), 'type' => 'select', 'options' => (isset($applicant) ? [$applicant->id => $applicant->tax_code . ' - ' . $applicant->name . ' ' . $applicant->surname] : []), 'empty' => true, 'style' => 'width:50%;']) ?> +
+
+ RESET +
+ + Form->hidden('applicants.' . $applicant_item_block . '.id', ['id' => 'applicants-' . $applicant_item_block . '-id', 'readonly' => true, 'disabled' => (!isset($applicant)), 'type' => 'number']) ?> + Form->hidden('applicants.' . $applicant_item_block . '._joinData.is_primary_applicant', ['value' => ($applicant_item_block == 0 ? 1 : 0)]) ?> + 5): ?> +
+ Form->hidden('applicants.' . $applicant_item_block . '.id', ['id' => 'applicants-' . $applicant_item_block . '-id', 'readonly' => true, 'disabled' => (!isset($applicant)), 'type' => 'number']) ?> + Form->hidden('applicants.' . $applicant_item_block . '._joinData.is_primary_applicant', ['value' => ($applicant_item_block == 0 ? 1 : 0)]) ?> + Form->control('applicants.' . $applicant_item_block . '.name', ['label' => __('Nome'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden'), 'required' => true]) ?> +
+ 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.surname', ['label' => __('Cognome'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden'), 'required' => true]) ?> +
+ +
+ Form->control('applicants.' . $applicant_item_block . '.tax_code', ['label' => __('Codice fiscale'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => 'text', 'required' => true]) ?> +
+ 5): + ?>
+ Form->control('applicants.' . $applicant_item_block . '.company_name', ['label' => __('Ragione sociale'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden')]) ?> +
+ +
+ Form->control('applicants.' . $applicant_item_block . '.vat_number', ['label' => __('Partita IVA'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => 'text']) ?> +
+ 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.address', ['label' => __('Indirizzo'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden'), 'required' => true]) ?> +
+ 5): + ?> + Cell("DistrictProvince", [ + new ProvinceCellDto( + fieldId: 'applicants-' . $applicant_item_block . '-province', + fieldName: 'applicants.' . $applicant_item_block . '.province', + formContext: $formContext ?? null, + fieldRequired: true, + disabled: (isset($is_view) || isset($applicant->id)), + fieldType: ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? InputFieldType::SELECT : InputFieldType::HIDDEN), + fieldValue: $province + ), + new DistrictCellDto( + fieldId: 'applicants-' . $applicant_item_block . '-district', + fieldName: 'applicants.' . $applicant_item_block . '.district', + provinceFieldId: 'applicants-' . $applicant_item_block . '-province', + fieldRequired: true, + disabled: (isset($is_view) || isset($applicant->id)), + fieldType: ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? InputFieldType::SELECT : InputFieldType::HIDDEN), + fieldValue: $district, + entity: $applicant + ) + ] + ) ?> + 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.pec_address', ['label' => __('Indirizzo PEC'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden')]) ?> +
+ 5): + ?> +
+ Form->control('applicants.' . $applicant_item_block . '.email_address', ['label' => __('Indirizzo email'), 'disabled' => (isset($is_view) || isset($applicant->id)), 'type' => ((!isset($water_drawing_paperwork_status_id) || $water_drawing_paperwork_status_id > 5) ? 'text' : 'hidden')]) ?> +
+ +
+ 0 && !(isset($is_view))) : ?> + + + Modifica +
+
+
+ diff --git a/idrocap_wa/templates/element/WaterDrawingPaperworks/intended_uses.php b/idrocap_wa/templates/element/WaterDrawingPaperworks/intended_uses.php new file mode 100644 index 0000000..980e8ec --- /dev/null +++ b/idrocap_wa/templates/element/WaterDrawingPaperworks/intended_uses.php @@ -0,0 +1,151 @@ +
+
+
+

+ water_drawing_intended_uses) && isset($waterDrawingPaperwork->water_drawing_intended_uses[$intended_use_item_block]->water_drawing_intended_use_type_id) && $waterDrawingPaperwork->water_drawing_intended_uses[$intended_use_item_block]->water_drawing_intended_use_type_id == 1) { + if ($waterDrawingPaperwork->water_drawing_intended_uses[$intended_use_item_block]->vegetation_match_status == -1) { + ?> +
+ water_drawing_intended_uses[$intended_use_item_block]->vegetation_match_status == 0) { + ?> +
+ water_drawing_intended_uses[$intended_use_item_block]->vegetation_match_status == 1) { + ?> +
+ +
+
+
+
+ Form->hidden('water_drawing_intended_uses.' . $intended_use_item_block . '.id', []) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.water_drawing_intended_use_type_id', ['id' => 'select2water-drawing-use-type-id-' . $intended_use_item_block, 'label' => __('Uso'), 'options' => $intendedUseTypes, 'empty' => true, "onChange" => "changeIntendedUseTypes($intended_use_item_block)" , 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.area', ['label' => __('Superficie da irrigare ( 00.00.00 ha )'), 'pattern' => '\d{2}([.,]\d{2}){2}', 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_code', ['label' => __('Codice comune'), 'type' => 'text', 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_sheet', ['label' => __('Foglio di mappa'), 'type' => 'text', 'disabled' => (isset($is_view)), 'type' => 'number', 'min' => 0]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_parcel', ['label' => __('Particella da irrigare'), 'type' => 'text', 'disabled' => (isset($is_view)), 'type' => 'number', 'min' => 0]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.water_drawing_watering_system_id', ['id' => 'select2watering-system-id-' . $intended_use_item_block, 'label' => __('Sistema di irrigazione'), 'options' => $wateringSystems, 'empty' => true, 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.cadastral_crop_types._ids', ['id' => 'select2cadastra-crop-type-ids-' . $intended_use_item_block, 'label' => __('Tipo coltura'), 'options' => $cadastralCropTypes, 'multiple' => true, 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.consortium_area', ['label' => __('Area consortile'), 'type' => 'text', 'disabled' => (isset($is_view))]) ?> + Form->control('water_drawing_intended_uses.' . $intended_use_item_block . '.rated_power_produced', ['label' => __('Potenza nominale prodotta (kW)'), 'type' => 'number', 'disabled' => (isset($is_view)), 'min' => 0]) ?> +
+
+ 0 && !(isset($is_view))) : ?> +
+
+ +
+
+ +
+ diff --git a/idrocap_wa/templates/element/attachmentPreview.php b/idrocap_wa/templates/element/attachmentPreview.php new file mode 100755 index 0000000..89af461 --- /dev/null +++ b/idrocap_wa/templates/element/attachmentPreview.php @@ -0,0 +1,41 @@ + [ + 'html' => '', + 'width' => '256px', + 'height' => '256px', + 'background' => 'url(\'/img/giphy.gif\')', + ], + 'video/mp4' => [ + 'html' => '', + 'width' => '256px', + 'height' => '256px', + 'background' => 'url(\'/img/giphy.gif\')', + ], + 'application/pdf' => [ + 'html' => '', + 'width' => '500px', + 'height' => '500px', + 'background' => 'none', + ] + ]; + + if(isset($element[$mimetype])){ + $result = $element[$mimetype]; + } + else + { + $result = ['html' => __("Anteprima non disponibile"), 'width' => '200px', 'height' => '50px', 'background' => 'none']; + } +?> +
+ diff --git a/idrocap_wa/templates/element/attachments.php b/idrocap_wa/templates/element/attachments.php new file mode 100755 index 0000000..7a9c8f2 --- /dev/null +++ b/idrocap_wa/templates/element/attachments.php @@ -0,0 +1,341 @@ + + aggiunge un prefisso a tutti gli element html e js per evitare conflitti + 'input_name_for_attachments' --------> opzionale override degli input name 'attachments' + 'input_name_for_removefiles' --------> opzionale override degli input name 'removefiles' + 'filepicker' => true/false --------> inserisce il filepicker oppure no + 'georeferenced' => true/false --------> stabilisce se ogni singolo allegato va georeferenziato oppure no. (se è true allore upload_single viene forzato anche a true!!!!!) + 'upload_single' => true/false --------> decide se l'upload è singolo o se sono consentiti upload multipli da più paths + 'accept_only' => [] --------> se si passa questo array, i tipi di files accettati saranno solo quelli specificati + 'viewer' => true/false --------> inserisce o meno il file viewer + 'coId' --------> controllable object id, necessario se la proprietà precedente 'viewer' è true + 'currentFilesRemovable' => true/false --------> decide se è possibile eliminare i files già presenti o meno + 'enableRelated' => true/false --------> visualizza anche gli allegati degli oggetti associati (esempio in un evento visualizza anche gli allegati delle observations) + 'allow_private' => true/false --------> stabilisce se devono esserci files pubblici e privati o soltanto pubblci + 'public_required' => true/false --------> setta allegato pubblico come obbligatorio oppure no + 'required' => true/false --------> setta l'allegato come obbligatorio oppure no + 'tags' => [] --------> serve a passare uno o + tags (vedi tabella Tags) per creare diverse sezioni di allegati. ogni elemento key=>value dell'array va inserito come code/description della sezione che si vuole creare. esempio: 'tags' => ['code1' => 'Allegati di tipo 1', 'code2' => 'Allegati di tipo 2', 'code3' => 'Allegati di tipo 3'] + 'view_in_frame_with_id' --------> se settato, viene effettuato il rendering dell'allegato all'interno deill'iframe con id specificato + */ + + $prefix = isset($prefix) && is_string($prefix) ? $prefix : ''; + $input_name_for_attachments = isset($input_name_for_attachments) && is_string($input_name_for_attachments) ? $input_name_for_attachments : 'attachments'; + $input_name_for_removefiles = isset($input_name_for_removefiles) && is_string($input_name_for_removefiles) ? $input_name_for_removefiles : 'removefiles'; + $accept = isset($accept_only) && is_array($accept_only) && count($accept_only) > 0 ? ('accept="' . implode(",", $accept_only) . '"') : ''; + $acceptText = isset($accept_only) && is_array($accept_only) && count($accept_only) > 0 ? __('di tipo: "{0}"', implode(",", $accept_only)) : ''; + $georeferenced = isset($georeferenced) && $georeferenced; + $multiple = $georeferenced || isset($upload_single) && $upload_single ? '': 'multiple="multiple"'; + $oneFilePicker = isset($upload_single) && $upload_single; + $public_required = isset($public_required) && $public_required; + $required = isset($required) && $required; + $coRelated = isset($coRelated) && $coRelated; + + if (isset($enableRelated) && $enableRelated) { + echo ''; + echo ''; + } +?> +
+
+
+ ($oneFilePicker ? __('Allega un file ') : __('Allega files ')) . $acceptText]; + } + else + { + if($allow_private) + { + $attachment_scope = ['public' => __('Allega file pubblico ') . $acceptText, 'private' => ($oneFilePicker ? __('Allega un file privato ') : __('Allega files privati ')) . $acceptText]; + } + else + { + $attachment_scope = ['' => __('Allega files...')]; + } + } + + if(isset($tags)){ + $attachment_scope = []; + foreach ($tags as $tag => $description) { + $attachment_scope[$tag] = __('Allega files {1} {0}',$description,$acceptText); + } + $csv_tags = implode(',',array_keys($tags)); + } + if (isset($filepicker) && $filepicker) { + + $attachment_index = $georeferenced ? '[0]' : '[]'; + $col = (12 / count($attachment_scope)) > 6 ? (12 / count($attachment_scope)) : 6; + foreach($attachment_scope as $scope => $label) + { + echo '
'; + echo ''; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + echo '
'; + } + + } + echo $this->Form->hidden($prefix.'removecurrentfiles', ['id' => $prefix.'removecurrentfiles', 'value' => isset($currentFilesRemovable) && $currentFilesRemovable ? 'true' : 'false']); +?> +
+ + +
+ +
+
+ + $label) + { + if ($scope == "public" || $oneFilePicker) { + continue; + } +?> + + + + + + + + + + + + +
+
+ +
+ +
+ + + +
diff --git a/idrocap_wa/templates/element/districtSelect.php b/idrocap_wa/templates/element/districtSelect.php new file mode 100644 index 0000000..a6b51f6 --- /dev/null +++ b/idrocap_wa/templates/element/districtSelect.php @@ -0,0 +1,210 @@ + $districtCellConfig->fieldId, + 'label' => __($districtCellConfig->fieldLabel), + 'type' => $districtCellConfig->fieldType->value, + "empty" => true, + "disabled" => $districtCellConfig->disabled, + 'required' => $districtCellConfig->fieldRequired +]; + +if (!empty($districtCellConfig->fieldValue)) { + $options['data-value'] = $districtCellConfig->fieldValue; +} +?> + +fieldId !== null && $districtCellConfig->fieldName !== null): ?> + Form->control($districtCellConfig->fieldName, $options) ?> + entity) && $districtCellConfig->entity->hasErrors($districtCellConfig->fieldName)): ?> +
+ entity->getError($districtCellConfig->fieldName); + + /* + * Qui ci finisco solo se siamo in un ciclo e quindi il nome del field non matcha con la rule + */ + if(empty($errors)) { + $errors = $districtCellConfig->entity->getError("district"); + } + + if (is_array($errors) && isset($errors['validDistrict'])) { + echo h($errors['validDistrict']); + } else { + echo is_array($errors) ? h(implode(', ', $errors)) : h($errors); + } + ?> +
+ + + + diff --git a/idrocap_wa/templates/element/flash/default.php b/idrocap_wa/templates/element/flash/default.php new file mode 100644 index 0000000..061c700 --- /dev/null +++ b/idrocap_wa/templates/element/flash/default.php @@ -0,0 +1,15 @@ + +
diff --git a/idrocap_wa/templates/element/flash/error.php b/idrocap_wa/templates/element/flash/error.php new file mode 100644 index 0000000..2ebf235 --- /dev/null +++ b/idrocap_wa/templates/element/flash/error.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/flash/info.php b/idrocap_wa/templates/element/flash/info.php new file mode 100644 index 0000000..e25b730 --- /dev/null +++ b/idrocap_wa/templates/element/flash/info.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/flash/success.php b/idrocap_wa/templates/element/flash/success.php new file mode 100644 index 0000000..73eaac4 --- /dev/null +++ b/idrocap_wa/templates/element/flash/success.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/flash/warning.php b/idrocap_wa/templates/element/flash/warning.php new file mode 100644 index 0000000..605537c --- /dev/null +++ b/idrocap_wa/templates/element/flash/warning.php @@ -0,0 +1,11 @@ + +
diff --git a/idrocap_wa/templates/element/provinceSelect.php b/idrocap_wa/templates/element/provinceSelect.php new file mode 100644 index 0000000..ee9fb73 --- /dev/null +++ b/idrocap_wa/templates/element/provinceSelect.php @@ -0,0 +1,145 @@ + $provinceConfig->fieldId, + 'label' => __($provinceConfig->fieldLabel), + 'type' => $provinceConfig->fieldType->value, + "empty" => true, + 'options' => $provinces ?? [], + 'disabled' => $provinceConfig->disabled, + 'required' => $provinceConfig->fieldRequired +]; + +if (!empty($provinceConfig->fieldValue)) { + $options['value'] = $provinceConfig->fieldValue; +} + +$formContext = $provinceConfig->formContext ?? null; + +/** + * Passo il contesto perchè CakePHP genera una nuova VIEW e altrimenti non sarebbe visibile alla view dell'element. + * Vedi caso in cui dobbiamo gestire il valore selected per edit o view + * Inoltre anche nel caso di errori in questo caso manteniamo la gestione nativa di cakephp. + */ +if (isset($formContext)) { + $this->Form->create($formContext, ['type' => 'context', 'id' => false, 'url' => false]); +} +?> + +fieldId !== null && $provinceConfig->fieldName !== null): ?> + Form->control($provinceConfig->fieldName, $options) ?> + + + + Form->end(); + } +endif; ?> diff --git a/idrocap_wa/templates/email/html/default.php b/idrocap_wa/templates/email/html/default.php new file mode 100644 index 0000000..bf4c131 --- /dev/null +++ b/idrocap_wa/templates/email/html/default.php @@ -0,0 +1,22 @@ + ' . $line . "

\n"; +endforeach; diff --git a/idrocap_wa/templates/email/text/default.php b/idrocap_wa/templates/email/text/default.php new file mode 100644 index 0000000..bb8461e --- /dev/null +++ b/idrocap_wa/templates/email/text/default.php @@ -0,0 +1,18 @@ +fetch('content'); diff --git a/idrocap_wa/templates/layout/default.php b/idrocap_wa/templates/layout/default.php new file mode 100644 index 0000000..de042c7 --- /dev/null +++ b/idrocap_wa/templates/layout/default.php @@ -0,0 +1,47 @@ + + + + + Html->charset() ?> + + + <?= \Cake\Core\Configure::read('Theme.title') ?>: + <?= $this->fetch('title') ?> + + Html->meta('icon') ?> + + + + Html->css(['normalize.min', 'milligram.min', 'cake']) ?> + + fetch('meta') ?> + fetch('css') ?> + fetch('script') ?> + + +
+
+ Flash->render() ?> + fetch('content') ?> +
+
+
+
+ + diff --git a/idrocap_wa/templates/layout/email/html/default.php b/idrocap_wa/templates/layout/email/html/default.php new file mode 100644 index 0000000..96b0e73 --- /dev/null +++ b/idrocap_wa/templates/layout/email/html/default.php @@ -0,0 +1,25 @@ + + + + + <?= $this->fetch('title') ?> + + + fetch('content') ?> + + diff --git a/idrocap_wa/templates/layout/email/text/default.php b/idrocap_wa/templates/layout/email/text/default.php new file mode 100644 index 0000000..cd51169 --- /dev/null +++ b/idrocap_wa/templates/layout/email/text/default.php @@ -0,0 +1,17 @@ +fetch('content'); diff --git a/idrocap_wa/templates/layout/error.php b/idrocap_wa/templates/layout/error.php new file mode 100644 index 0000000..28c09ba --- /dev/null +++ b/idrocap_wa/templates/layout/error.php @@ -0,0 +1,41 @@ + + + + + Html->charset() ?> + + <?= $this->fetch('title') ?> + + Html->meta('icon') ?> + + + + Html->css(['normalize.min', 'milligram.min', 'cake']) ?> + + fetch('meta') ?> + fetch('css') ?> + fetch('script') ?> + + +
+ Flash->render() ?> + fetch('content') ?> + Html->link(__('Back'), 'javascript:history.back()') ?> +
+ + diff --git a/idrocap_wa/templates/layout/view_public.php b/idrocap_wa/templates/layout/view_public.php new file mode 100644 index 0000000..d44e591 --- /dev/null +++ b/idrocap_wa/templates/layout/view_public.php @@ -0,0 +1,68 @@ +CakeLte + */ + +?> + + + + + + + + <?= $this->fetch('title') . ' | ' . strip_tags($this->CakeLte->getConfig('app-name')) ?> + + Html->meta('icon') ?> + fetch('meta') ?> + + + + + Html->css('/adminlte/plugins/fontawesome-free/css/all.min.css') ?> + + Html->css('/adminlte/dist/css/adminlte.min.css') ?> + Html->css('CakeLte.style') ?> + Html->css('idrocap-styles') ?> + element('CakeLte.extra/css') ?> + + Html->css('citizen-registration.css') ?> + + fetch('css') ?> + + + + + + + + Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + + Html->script('/adminlte/plugins/bootstrap/js/bootstrap.bundle.min.js') ?> + + Html->script('/adminlte/dist/js/adminlte.min.js') ?> + + element('CakeLte.extra/script') ?> + fetch('script') ?> + + + \ No newline at end of file diff --git a/idrocap_wa/templates/plugin/BootstrapUI/element/flash/default.php b/idrocap_wa/templates/plugin/BootstrapUI/element/flash/default.php new file mode 100644 index 0000000..5bffbfb --- /dev/null +++ b/idrocap_wa/templates/plugin/BootstrapUI/element/flash/default.php @@ -0,0 +1,30 @@ +Html->icon($icon, $params['iconOptions']); + } + $message = $icon . "
$message
"; +} + +if (in_array('alert-dismissible', $class)) { + $button = << +BUTTON; + $message = $button . $message; +} +if (is_array($class)) { + $class = join(' ', $class); +} +echo $this->Html->div($class, $message, $params['attributes']); diff --git a/idrocap_wa/templates/plugin/CakeLte/element/footer/main.php b/idrocap_wa/templates/plugin/CakeLte/element/footer/main.php new file mode 100644 index 0000000..b132fe8 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/footer/main.php @@ -0,0 +1,14 @@ + + + +
+ Copyright © Privacy Policy. + +
+ + + + + diff --git a/idrocap_wa/templates/plugin/CakeLte/element/header/main.php b/idrocap_wa/templates/plugin/CakeLte/element/header/main.php new file mode 100644 index 0000000..4ac2fc1 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/header/main.php @@ -0,0 +1,21 @@ + + + + + diff --git a/idrocap_wa/templates/plugin/CakeLte/element/header/menu.php b/idrocap_wa/templates/plugin/CakeLte/element/header/menu.php new file mode 100644 index 0000000..a50ed2a --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/header/menu.php @@ -0,0 +1,2 @@ + +Sections->create($menu_sections) ?> diff --git a/idrocap_wa/templates/plugin/CakeLte/element/header/notifications.php b/idrocap_wa/templates/plugin/CakeLte/element/header/notifications.php new file mode 100644 index 0000000..b84917f --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/header/notifications.php @@ -0,0 +1,51 @@ +Html->script('jixel-primitives'); ?> + +Notifications->create($user_notifications) ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/plugin/CakeLte/element/sidebar/main.php b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/main.php new file mode 100644 index 0000000..fd685e5 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/main.php @@ -0,0 +1,6 @@ + + diff --git a/idrocap_wa/templates/plugin/CakeLte/element/sidebar/menu.php b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/menu.php new file mode 100644 index 0000000..203861d --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/element/sidebar/menu.php @@ -0,0 +1,33 @@ + + + + + + + Menu->create($menu_items) ?> + + + Menu->create($sys_admin_menu_items); ?> + \ No newline at end of file diff --git a/idrocap_wa/templates/plugin/CakeLte/layout/default.php b/idrocap_wa/templates/plugin/CakeLte/layout/default.php new file mode 100644 index 0000000..0d04294 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/layout/default.php @@ -0,0 +1,108 @@ +CakeLte + */ + +?> + + + + + + + + + <?= strip_tags($this->fetch('title') . ' | ' . $this->CakeLte->getConfig('app-name')) ?> + + Html->meta('icon') ?> + fetch('meta') ?> + + + + + Html->css('/adminlte/plugins/fontawesome-free/css/all.min.css') ?> + + Html->css('/adminlte/dist/css/adminlte.min.css') ?> + Html->css('CakeLte.style') ?> + Html->css('idrocap-styles') ?> + + Html->css('/bower_components/select2/dist/css/select2.min'); ?> + + Html->css('/adminlte/plugins/daterangepicker/daterangepicker') ?> + element('CakeLte.extra/css') ?> + fetch('css') ?> + + + +
+ + + + + + + + +
+ +
+
+ Flash->render() ?> + fetch('content') ?> +
+
+ +
+ + + + + + + +
+ element('CakeLte.footer/main') ?> +
+
+ + + + Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + + Html->script('/adminlte/plugins/bootstrap/js/bootstrap.bundle.min.js') ?> + + Html->script('/adminlte/dist/js/adminlte.min.js') ?> + + element('CakeLte.extra/script') ?> + + Html->script('/bower_components/select2/dist/js/select2.min'); ?> + + Html->script('/adminlte/plugins/daterangepicker/daterangepicker'); ?> + + fetch('script') ?> + + + diff --git a/idrocap_wa/templates/plugin/CakeLte/layout/login.php b/idrocap_wa/templates/plugin/CakeLte/layout/login.php new file mode 100644 index 0000000..965a9d9 --- /dev/null +++ b/idrocap_wa/templates/plugin/CakeLte/layout/login.php @@ -0,0 +1,111 @@ +CakeLte + */ + +?> + + + + + + + + <?= $this->fetch('title') . ' | ' . strip_tags($this->CakeLte->getConfig('app-name')) ?> + + Html->meta('icon') ?> + fetch('meta') ?> + + + + + Html->css('/adminlte/plugins/fontawesome-free/css/all.min.css') ?> + + Html->css('/adminlte/dist/css/adminlte.min.css') ?> + Html->css('CakeLte.style') ?> + Html->css('idrocap-styles') ?> + element('CakeLte.extra/css') ?> + + Html->css('citizen-registration.css') ?> + + fetch('css') ?> + + + +
+ + + + + + + + +
+
+ + + + +
+ + + + + Html->script('/adminlte/plugins/jquery/jquery.min.js') ?> + + Html->script('/adminlte/plugins/bootstrap/js/bootstrap.bundle.min.js') ?> + + Html->script('/adminlte/dist/js/adminlte.min.js') ?> + + element('CakeLte.extra/script') ?> + fetch('script') ?> + + + + diff --git a/idrocap_wa/tests/Fixture/.gitkeep b/idrocap_wa/tests/Fixture/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/TestCase/ApplicationTest.php b/idrocap_wa/tests/TestCase/ApplicationTest.php new file mode 100644 index 0000000..6a65c52 --- /dev/null +++ b/idrocap_wa/tests/TestCase/ApplicationTest.php @@ -0,0 +1,85 @@ +bootstrap(); + $plugins = $app->getPlugins(); + + $this->assertTrue($plugins->has('Bake'), 'plugins has Bake?'); + $this->assertFalse($plugins->has('DebugKit'), 'plugins has DebugKit?'); + $this->assertTrue($plugins->has('Migrations'), 'plugins has Migrations?'); + } + + /** + * Test bootstrap add DebugKit plugin in debug mode. + * + * @return void + */ + public function testBootstrapInDebug() + { + Configure::write('debug', true); + $app = new Application(dirname(__DIR__, 2) . '/config'); + $app->bootstrap(); + $plugins = $app->getPlugins(); + + $this->assertTrue($plugins->has('DebugKit'), 'plugins has DebugKit?'); + } + + /** + * testMiddleware + * + * @return void + */ + public function testMiddleware() + { + $app = new Application(dirname(__DIR__, 2) . '/config'); + $middleware = new MiddlewareQueue(); + + $middleware = $app->middleware($middleware); + + $this->assertInstanceOf(ErrorHandlerMiddleware::class, $middleware->current()); + $middleware->seek(1); + $this->assertInstanceOf(AssetMiddleware::class, $middleware->current()); + $middleware->seek(2); + $this->assertInstanceOf(RoutingMiddleware::class, $middleware->current()); + } +} diff --git a/idrocap_wa/tests/TestCase/Controller/Component/.gitkeep b/idrocap_wa/tests/TestCase/Controller/Component/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/TestCase/Controller/PagesControllerTest.php b/idrocap_wa/tests/TestCase/Controller/PagesControllerTest.php new file mode 100644 index 0000000..73f9452 --- /dev/null +++ b/idrocap_wa/tests/TestCase/Controller/PagesControllerTest.php @@ -0,0 +1,115 @@ +get('/pages/home'); + $this->assertResponseOk(); + $this->assertResponseContains('CakePHP'); + $this->assertResponseContains(''); + } + + /** + * Test that missing template renders 404 page in production + * + * @return void + */ + public function testMissingTemplate() + { + Configure::write('debug', false); + $this->get('/pages/not_existing'); + + $this->assertResponseError(); + $this->assertResponseContains('Error'); + } + + /** + * Test that missing template in debug mode renders missing_template error page + * + * @return void + */ + public function testMissingTemplateInDebug() + { + Configure::write('debug', true); + $this->get('/pages/not_existing'); + + $this->assertResponseFailure(); + $this->assertResponseContains('Missing Template'); + $this->assertResponseContains('stack-frames'); + $this->assertResponseContains('not_existing.php'); + } + + /** + * Test directory traversal protection + * + * @return void + */ + public function testDirectoryTraversalProtection() + { + $this->get('/pages/../Layout/ajax'); + $this->assertResponseCode(403); + $this->assertResponseContains('Forbidden'); + } + + /** + * Test that CSRF protection is applied to page rendering. + * + * @return void + */ + public function testCsrfAppliedError() + { + $this->post('/pages/home', ['hello' => 'world']); + + $this->assertResponseCode(403); + $this->assertResponseContains('CSRF'); + } + + /** + * Test that CSRF protection is applied to page rendering. + * + * @return void + */ + public function testCsrfAppliedOk() + { + $this->enableCsrfToken(); + $this->post('/pages/home', ['hello' => 'world']); + + $this->assertThat(403, $this->logicalNot(new StatusCode($this->_response))); + $this->assertResponseNotContains('CSRF'); + } +} diff --git a/idrocap_wa/tests/TestCase/Model/Behavior/.gitkeep b/idrocap_wa/tests/TestCase/Model/Behavior/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/TestCase/View/Helper/.gitkeep b/idrocap_wa/tests/TestCase/View/Helper/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/idrocap_wa/tests/bootstrap.php b/idrocap_wa/tests/bootstrap.php new file mode 100644 index 0000000..1cb386d --- /dev/null +++ b/idrocap_wa/tests/bootstrap.php @@ -0,0 +1,66 @@ + 'Cake\Database\Connection', + 'driver' => 'Cake\Database\Driver\Sqlite', + 'database' => TMP . 'debug_kit.sqlite', + 'encoding' => 'utf8', + 'cacheMetadata' => true, + 'quoteIdentifiers' => false, +]); + +ConnectionManager::alias('test_debug_kit', 'debug_kit'); + +// Fixate sessionid early on, as php7.2+ +// does not allow the sessionid to be set after stdout +// has been written to. +session_id('cli'); + +// Use migrations to build test database schema. +// +// Will rebuild the database if the migration state differs +// from the migration history in files. +// +// If you are not using CakePHP's migrations you can +// hook into your migration tool of choice here or +// load schema from a SQL dump file with +// use Cake\TestSuite\Fixture\SchemaLoader; +// (new SchemaLoader())->loadSqlFiles('./tests/schema.sql', 'test'); + +(new Migrator())->run(); diff --git a/idrocap_wa/tests/schema.sql b/idrocap_wa/tests/schema.sql new file mode 100644 index 0000000..c7e4d3f --- /dev/null +++ b/idrocap_wa/tests/schema.sql @@ -0,0 +1,4 @@ +-- Test database schema. +-- +-- If you are not using CakePHP migrations you can put +-- your application's schema in this file and use it in tests. diff --git a/idrocap_wa/webroot/.gitignore b/idrocap_wa/webroot/.gitignore new file mode 100644 index 0000000..5cccb96 --- /dev/null +++ b/idrocap_wa/webroot/.gitignore @@ -0,0 +1,3 @@ +node_modules +bower_components + diff --git a/idrocap_wa/webroot/.htaccess b/idrocap_wa/webroot/.htaccess new file mode 100644 index 0000000..f5f2d63 --- /dev/null +++ b/idrocap_wa/webroot/.htaccess @@ -0,0 +1,5 @@ + + RewriteEngine On + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/idrocap_wa/webroot/adminlte b/idrocap_wa/webroot/adminlte new file mode 120000 index 0000000..be2cf15 --- /dev/null +++ b/idrocap_wa/webroot/adminlte @@ -0,0 +1 @@ +/var/www/jixel/vendor/almasaeed2010/adminlte/ \ No newline at end of file diff --git a/idrocap_wa/webroot/bower.json b/idrocap_wa/webroot/bower.json new file mode 100644 index 0000000..728e78e --- /dev/null +++ b/idrocap_wa/webroot/bower.json @@ -0,0 +1,17 @@ +{ + "name": "webroot", + "description": "", + "main": "", + "license": "MIT", + "homepage": "", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "select2": "~4.0" + } +} diff --git a/idrocap_wa/webroot/css/cake.css b/idrocap_wa/webroot/css/cake.css new file mode 100644 index 0000000..fbb0de9 --- /dev/null +++ b/idrocap_wa/webroot/css/cake.css @@ -0,0 +1,299 @@ +/* Milligram overrides */ +:root { + /* The following are official CakePHP colors */ + --color-cakephp-red: #d33c43; + --color-cakephp-gray: #404041; + --color-cakephp-blue: #2f85ae; + --color-cakephp-lightblue: #34bdd7; + + /* These are additional colors */ + --color-lightgray: #606c76; + --color-white: #fff; + + --color-main-bg: #f5f7fa; + --color-links: var(--color-cakephp-blue); + --color-links-active: #2a6496; + --color-headings: #363637; + + --color-message-success-bg: #e3fcec; + --color-message-success-text: #1f9d55; + --color-message-success-border: #51d88a; + + --color-message-warning-bg: #fffabc; + --color-message-warning-text: #8d7b00; + --color-message-warning-border: #d3b800; + + --color-message-error-bg: #fcebea; + --color-message-error-text: #cc1f1a; + --color-message-error-border: #ef5753; + + --color-message-info-bg: #eff8ff; + --color-message-info-text: #2779bd; + --color-message-info-border: #6cb2eb; +} + +.button, button, input[type='button'], input[type='reset'], input[type='submit'] { + background-color: var(--color-cakephp-red); + border-color: var(--color-cakephp-red); +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 400; + background: var(--color-main-bg); +} + +.top-nav-links, +.side-nav, +h1, h2, h3, h4, h5, h6 { + font-family: "Raleway", sans-serif; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 400; + color: var(--color-headings); +} + +a { + color: var(--color-links); + transition: color 0.2s linear; +} + +a:hover, +a:focus, +a:active { + color: var(--color-links-active); + transition: color 0.2s ease-out; +} + +.side-nav a, +.top-nav-links a, +th a, +.actions a { + color: var(--color-lightgray); +} + +.side-nav a:hover, +.side-nav a:focus, +.actions a:hover, +.actions a:focus { + color: var(--color-links-active); +} + +/* Utility */ +.table-responsive { + display: block; + width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +/* Main */ +.content { + padding: 2rem; + background: var(--color-white); + border-radius: 0.4rem; + /* Thanks Stripe */ + box-shadow: 0 7px 14px 0 rgba(60, 66, 87, 0.1), + 0 3px 6px 0 rgba(0, 0, 0, 0.07); +} +.content form { + margin: 0; +} +.actions a { + font-weight: bold; + padding: 0 0.4rem; +} +.actions a:first-child { + padding-left: 0; +} +th { + white-space: nowrap; +} + +/* Nav bar */ +.top-nav { + display: flex; + align-items: center; + justify-content: space-between; + max-width: 112rem; + padding: 2rem; + margin: 0 auto; +} +.top-nav-title a { + font-size: 2.4rem; + color: var(--color-cakephp-red); +} +.top-nav-title span { + color: var(--color-cakephp-gray); +} +.top-nav-links a { + margin: 0 0.5rem; +} +.top-nav-title a, +.top-nav-links a { + font-weight: bold; +} +.side-nav-item { + display: block; + padding: 0.5rem 0; +} + +/* View action */ +.view.content .text { + margin-top: 1.2rem; +} +.related { + margin-top: 2rem; +} + +/* Flash messages */ +.message { + padding: .5rem 1rem; + background: var(--color-message-info-bg); + color: var(--color-message-info-text); + border-color: var(--color-message-info-border); + border-width: 1px; + border-style: solid; + border-radius: 4px; + margin-bottom: 1rem; + cursor: pointer; +} +.message.hidden { + display: none; +} +.message.success { + background: var(--color-message-success-bg); + color: var(--color-message-success-text); + border-color: var(--color-message-success-border); +} +.message.warning { + background: var(--color-message-warning-bg); + color: var(--color-message-warning-text); + border-color: var(--color-message-warning-border); +} +.message.error { + background: var(--color-message-error-bg); + color: var(--color-message-error-text); + border-color: var(--color-message-error-border); +} + +/* Forms */ +.input.radio, +.input.checkbox, +.input.multicheckbox { + margin-bottom: 2.0rem; +} +.input.radio input, +.input.checkbox input, +.input.multicheckbox input { + margin: 0; +} +.input.radio label, +.input.checkbox label, +.input.multicheckbox label { + margin: 0; + display: flex; + align-items: center; +} +.input.radio label > input, +.input.checkbox label > input, +.input.multicheckbox label > input { + margin-right: 1.0rem; +} +input[type='color'] { + max-width: 4rem; + padding: 0.3rem .5rem 0.3rem; +} + +/* Paginator */ +.paginator { + text-align: right; +} +.paginator p { + margin-bottom: 0; +} +.pagination { + display: flex; + justify-content: center; + list-style: none; + margin: 0 0 1rem 0; + padding: 0; +} +.pagination li { + display: inline-block; + margin: 0.25em; + text-align: center; +} +.pagination a { + color: var(--color-cakephp-blue); + display: inline-block; + font-size: 1.25rem; + line-height: 3rem; + min-width: 3rem; + padding: 0; + position: relative; + text-decoration: none; + transition: background .3s,color .3s; +} +.pagination li.active a, +.pagination a:hover { + text-decoration: underline; +} +.pagination .disabled a { + cursor: not-allowed; + color: var(--color-lightgray); + text-decoration: none; +} +.first a, +.prev a, +.next a, +.last a { + padding: 0 .75rem; +} +.disabled a:hover { + background: initial; + color: initial; +} +.asc:after { + content: " \2193"; +} +.desc:after { + content: " \2191"; +} + +/* Error in non debug mode */ +.error-container { + align-items: center; + display: flex; + flex-direction: column; + height: 100vh; + justify-content: center; +} + +@media screen and (max-width: 640px) { + /* Fix milligram not having a responsive column system */ + .row .column[class*='column-'] { + flex: 0 0 100%; + max-width: 100% + } + .top-nav { + margin: 0 auto; + } + .side-nav { + margin-bottom: 1rem; + } + .heading { + margin-bottom: 1rem; + } + .side-nav-item { + display: inline; + margin: 0 1.5rem 0 0; + } + .asc:after { + content: " \2192"; + } + .desc:after { + content: " \2190"; + } +} diff --git a/idrocap_wa/webroot/css/citizen-registration.css b/idrocap_wa/webroot/css/citizen-registration.css new file mode 100644 index 0000000..bf2f717 --- /dev/null +++ b/idrocap_wa/webroot/css/citizen-registration.css @@ -0,0 +1,14 @@ +.add-citizen.add-citizen { + width: 80%; +} + +.login-page { + margin-top: 76px; + margin-bottom: 76px; + padding-left: 20px; + padding-right: 20px; +} + +.card-primary.card-outline { + border-top: none; +} diff --git a/idrocap_wa/webroot/css/fonts.css b/idrocap_wa/webroot/css/fonts.css new file mode 100644 index 0000000..1ba4808 --- /dev/null +++ b/idrocap_wa/webroot/css/fonts.css @@ -0,0 +1,80 @@ +/* cyrillic-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-cyrillic-ext.woff2') format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-vietnamese.woff2') format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-latin-ext.woff2') format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 400; + src: url('../font/raleway-400-latin.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} +/* cyrillic-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-cyrillic-ext.woff2') format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; +} +/* cyrillic */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} +/* vietnamese */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-vietnamese.woff2') format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} +/* latin-ext */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-latin-ext.woff2') format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} +/* latin */ +@font-face { + font-family: 'Raleway'; + font-style: normal; + font-weight: 700; + src: url('../font/raleway-700-latin.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} diff --git a/idrocap_wa/webroot/css/home.css b/idrocap_wa/webroot/css/home.css new file mode 100644 index 0000000..4648ed3 --- /dev/null +++ b/idrocap_wa/webroot/css/home.css @@ -0,0 +1,75 @@ +/* Home page styles */ +@font-face { + font-family: 'cakefont'; + src: url('../font/cakedingbats-webfont.eot'); + src: url('../font/cakedingbats-webfont.eot?#iefix') format('embedded-opentype'), + url('../font/cakedingbats-webfont.woff2') format('woff2'), + url('../font/cakedingbats-webfont.woff') format('woff'), + url('../font/cakedingbats-webfont.ttf') format('truetype'), + url('../font/cakedingbats-webfont.svg#cake_dingbatsregular') format('svg'); + font-weight: normal; + font-style: normal; +} +body { + padding: 60px 0; +} +header { + margin-bottom: 60px; +} +img { + margin-bottom: 30px; +} +h1 { + font-weight: bold; +} +ul { + list-style-type: none; + margin: 0 0 30px 0; + padding-left: 25px; +} +a { + color: #0071BC; + text-decoration: underline; +} +hr { + border-bottom: 1px solid #e7e7e7; + border-top: 0; + margin-bottom: 35px; +} + +.text-center { + text-align: center; +} +.links a { + margin-right: 10px; +} +.release-name { + color: #D33C43; + font-weight: 400; + font-style: italic; +} +.bullet:before { + font-family: 'cakefont', sans-serif; + font-size: 18px; + display: inline-block; + margin-left: -1.3em; + width: 1.2em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + vertical-align: -1px; +} +.success:before { + color: #88c671; + content: "\0056"; +} +.problem:before { + color: #d33d44; + content: "\0057"; +} +.cake-error { + padding: 10px; + margin: 10px 0; +} +#url-rewriting-warning { + display: none; +} diff --git a/idrocap_wa/webroot/css/idrocap-styles.css b/idrocap_wa/webroot/css/idrocap-styles.css new file mode 100644 index 0000000..a1bf189 --- /dev/null +++ b/idrocap_wa/webroot/css/idrocap-styles.css @@ -0,0 +1,33 @@ +.select2-container { + width: 100% !important; +} + +.select2-selection { + height: calc(2.25rem + 2px) !important; +} + +.select2-container--default .select2-selection--single .select2-selection__arrow.select2-selection__arrow { + top: 6px; +} + +.idrocap-filter-select { + width: 100%; + height: 2.25rem; + padding: 0.375rem 0.75rem; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + border-radius: 0.25rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +.tox-promotion { + display: none; +} +.tox-statusbar__branding { + display: none; +} \ No newline at end of file diff --git a/idrocap_wa/webroot/css/jixel_ol.css b/idrocap_wa/webroot/css/jixel_ol.css new file mode 100644 index 0000000..7449f92 --- /dev/null +++ b/idrocap_wa/webroot/css/jixel_ol.css @@ -0,0 +1,66 @@ +.jixel-ol-tools-button { + top: 65px; + left: .5em; +} + +.ol-attribution li { + font-size: 1.3rem; +} + +.layerup { + display:none !important; +} + +.ol-layerswitcher .panel li label { + max-width: 40em !important; +} +.olmap { + height: 500px; + width: 100%; +} +.jixel-ol-popup { + position: absolute; + background-color: white; + -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + padding: 15px; + border-radius: 10px; + border: 1px solid #cccccc; + bottom: 12px; + left: -50px; + min-width: 280px; +} +.jixel-ol-popup:after, .jixel-ol-popup:before { + top: 100%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; +} +.jixel-ol-popup:after { + border-top-color: white; + border-width: 10px; + left: 48px; + margin-left: -10px; +} +.jixel-ol-popup:before { + border-top-color: #cccccc; + border-width: 11px; + left: 48px; + margin-left: -11px; +} +.jixel-ol-popup-closer { + text-decoration: none; + position: absolute; + top: 5px; + right: 10px; +} +.jixel-ol-popup-closer:after { + content: "✖"; +} +.jixel-ol-popup-content { + height: 200px; + overflow-y: scroll; +} diff --git a/idrocap_wa/webroot/css/milligram.min.css b/idrocap_wa/webroot/css/milligram.min.css new file mode 100644 index 0000000..958f687 --- /dev/null +++ b/idrocap_wa/webroot/css/milligram.min.css @@ -0,0 +1,9 @@ +/*! + * Milligram v1.4.1 + * https://milligram.io + * + * Copyright (c) 2020 CJ Patoilo + * Licensed under the MIT license + */ + +*,*:after,*:before{box-sizing:inherit}html{box-sizing:border-box;font-size:62.5%}body{color:#606c76;font-family:'Roboto', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;font-size:1.6em;font-weight:300;letter-spacing:.01em;line-height:1.6}blockquote{border-left:0.3rem solid #d1d1d1;margin-left:0;margin-right:0;padding:1rem 1.5rem}blockquote *:last-child{margin-bottom:0}.button,button,input[type='button'],input[type='reset'],input[type='submit']{background-color:#9b4dca;border:0.1rem solid #9b4dca;border-radius:.4rem;color:#fff;cursor:pointer;display:inline-block;font-size:1.1rem;font-weight:700;height:3.8rem;letter-spacing:.1rem;line-height:3.8rem;padding:0 3.0rem;text-align:center;text-decoration:none;text-transform:uppercase;white-space:nowrap}.button:focus,.button:hover,button:focus,button:hover,input[type='button']:focus,input[type='button']:hover,input[type='reset']:focus,input[type='reset']:hover,input[type='submit']:focus,input[type='submit']:hover{background-color:#606c76;border-color:#606c76;color:#fff;outline:0}.button[disabled],button[disabled],input[type='button'][disabled],input[type='reset'][disabled],input[type='submit'][disabled]{cursor:default;opacity:.5}.button[disabled]:focus,.button[disabled]:hover,button[disabled]:focus,button[disabled]:hover,input[type='button'][disabled]:focus,input[type='button'][disabled]:hover,input[type='reset'][disabled]:focus,input[type='reset'][disabled]:hover,input[type='submit'][disabled]:focus,input[type='submit'][disabled]:hover{background-color:#9b4dca;border-color:#9b4dca}.button.button-outline,button.button-outline,input[type='button'].button-outline,input[type='reset'].button-outline,input[type='submit'].button-outline{background-color:transparent;color:#9b4dca}.button.button-outline:focus,.button.button-outline:hover,button.button-outline:focus,button.button-outline:hover,input[type='button'].button-outline:focus,input[type='button'].button-outline:hover,input[type='reset'].button-outline:focus,input[type='reset'].button-outline:hover,input[type='submit'].button-outline:focus,input[type='submit'].button-outline:hover{background-color:transparent;border-color:#606c76;color:#606c76}.button.button-outline[disabled]:focus,.button.button-outline[disabled]:hover,button.button-outline[disabled]:focus,button.button-outline[disabled]:hover,input[type='button'].button-outline[disabled]:focus,input[type='button'].button-outline[disabled]:hover,input[type='reset'].button-outline[disabled]:focus,input[type='reset'].button-outline[disabled]:hover,input[type='submit'].button-outline[disabled]:focus,input[type='submit'].button-outline[disabled]:hover{border-color:inherit;color:#9b4dca}.button.button-clear,button.button-clear,input[type='button'].button-clear,input[type='reset'].button-clear,input[type='submit'].button-clear{background-color:transparent;border-color:transparent;color:#9b4dca}.button.button-clear:focus,.button.button-clear:hover,button.button-clear:focus,button.button-clear:hover,input[type='button'].button-clear:focus,input[type='button'].button-clear:hover,input[type='reset'].button-clear:focus,input[type='reset'].button-clear:hover,input[type='submit'].button-clear:focus,input[type='submit'].button-clear:hover{background-color:transparent;border-color:transparent;color:#606c76}.button.button-clear[disabled]:focus,.button.button-clear[disabled]:hover,button.button-clear[disabled]:focus,button.button-clear[disabled]:hover,input[type='button'].button-clear[disabled]:focus,input[type='button'].button-clear[disabled]:hover,input[type='reset'].button-clear[disabled]:focus,input[type='reset'].button-clear[disabled]:hover,input[type='submit'].button-clear[disabled]:focus,input[type='submit'].button-clear[disabled]:hover{color:#9b4dca}code{background:#f4f5f6;border-radius:.4rem;font-size:86%;margin:0 .2rem;padding:.2rem .5rem;white-space:nowrap}pre{background:#f4f5f6;border-left:0.3rem solid #9b4dca;overflow-y:hidden}pre>code{border-radius:0;display:block;padding:1rem 1.5rem;white-space:pre}hr{border:0;border-top:0.1rem solid #f4f5f6;margin:3.0rem 0}input[type='color'],input[type='date'],input[type='datetime'],input[type='datetime-local'],input[type='email'],input[type='month'],input[type='number'],input[type='password'],input[type='search'],input[type='tel'],input[type='text'],input[type='url'],input[type='week'],input:not([type]),textarea,select{-webkit-appearance:none;background-color:transparent;border:0.1rem solid #d1d1d1;border-radius:.4rem;box-shadow:none;box-sizing:inherit;height:3.8rem;padding:.6rem 1.0rem .7rem;width:100%}input[type='color']:focus,input[type='date']:focus,input[type='datetime']:focus,input[type='datetime-local']:focus,input[type='email']:focus,input[type='month']:focus,input[type='number']:focus,input[type='password']:focus,input[type='search']:focus,input[type='tel']:focus,input[type='text']:focus,input[type='url']:focus,input[type='week']:focus,input:not([type]):focus,textarea:focus,select:focus{border-color:#9b4dca;outline:0}select{background:url('data:image/svg+xml;utf8,') center right no-repeat;padding-right:3.0rem}select:focus{background-image:url('data:image/svg+xml;utf8,')}select[multiple]{background:none;height:auto}textarea{min-height:6.5rem}label,legend{display:block;font-size:1.6rem;font-weight:700;margin-bottom:.5rem}fieldset{border-width:0;padding:0}input[type='checkbox'],input[type='radio']{display:inline}.label-inline{display:inline-block;font-weight:normal;margin-left:.5rem}.container{margin:0 auto;max-width:112.0rem;padding:0 2.0rem;position:relative;width:100%}.row{display:flex;flex-direction:column;padding:0;width:100%}.row.row-no-padding{padding:0}.row.row-no-padding>.column{padding:0}.row.row-wrap{flex-wrap:wrap}.row.row-top{align-items:flex-start}.row.row-bottom{align-items:flex-end}.row.row-center{align-items:center}.row.row-stretch{align-items:stretch}.row.row-baseline{align-items:baseline}.row .column{display:block;flex:1 1 auto;margin-left:0;max-width:100%;width:100%}.row .column.column-offset-10{margin-left:10%}.row .column.column-offset-20{margin-left:20%}.row .column.column-offset-25{margin-left:25%}.row .column.column-offset-33,.row .column.column-offset-34{margin-left:33.3333%}.row .column.column-offset-40{margin-left:40%}.row .column.column-offset-50{margin-left:50%}.row .column.column-offset-60{margin-left:60%}.row .column.column-offset-66,.row .column.column-offset-67{margin-left:66.6666%}.row .column.column-offset-75{margin-left:75%}.row .column.column-offset-80{margin-left:80%}.row .column.column-offset-90{margin-left:90%}.row .column.column-10{flex:0 0 10%;max-width:10%}.row .column.column-20{flex:0 0 20%;max-width:20%}.row .column.column-25{flex:0 0 25%;max-width:25%}.row .column.column-33,.row .column.column-34{flex:0 0 33.3333%;max-width:33.3333%}.row .column.column-40{flex:0 0 40%;max-width:40%}.row .column.column-50{flex:0 0 50%;max-width:50%}.row .column.column-60{flex:0 0 60%;max-width:60%}.row .column.column-66,.row .column.column-67{flex:0 0 66.6666%;max-width:66.6666%}.row .column.column-75{flex:0 0 75%;max-width:75%}.row .column.column-80{flex:0 0 80%;max-width:80%}.row .column.column-90{flex:0 0 90%;max-width:90%}.row .column .column-top{align-self:flex-start}.row .column .column-bottom{align-self:flex-end}.row .column .column-center{align-self:center}@media (min-width: 40rem){.row{flex-direction:row;margin-left:-1.0rem;width:calc(100% + 2.0rem)}.row .column{margin-bottom:inherit;padding:0 1.0rem}}a{color:#9b4dca;text-decoration:none}a:focus,a:hover{color:#606c76}dl,ol,ul{list-style:none;margin-top:0;padding-left:0}dl dl,dl ol,dl ul,ol dl,ol ol,ol ul,ul dl,ul ol,ul ul{font-size:90%;margin:1.5rem 0 1.5rem 3.0rem}ol{list-style:decimal inside}ul{list-style:circle inside}.button,button,dd,dt,li{margin-bottom:1.0rem}fieldset,input,select,textarea{margin-bottom:1.5rem}blockquote,dl,figure,form,ol,p,pre,table,ul{margin-bottom:2.5rem}table{border-spacing:0;overflow-x:auto;text-align:left;width:100%}td,th{border-bottom:0.1rem solid #e1e1e1;padding:1.2rem 1.5rem}td:first-child,th:first-child{padding-left:0}td:last-child,th:last-child{padding-right:0}@media (min-width: 40rem){table{display:table;overflow-x:initial}}b,strong{font-weight:bold}p{margin-top:0}h1,h2,h3,h4,h5,h6{font-weight:300;letter-spacing:-.1rem;margin-bottom:2.0rem;margin-top:0}h1{font-size:4.6rem;line-height:1.2}h2{font-size:3.6rem;line-height:1.25}h3{font-size:2.8rem;line-height:1.3}h4{font-size:2.2rem;letter-spacing:-.08rem;line-height:1.35}h5{font-size:1.8rem;letter-spacing:-.05rem;line-height:1.5}h6{font-size:1.6rem;letter-spacing:0;line-height:1.4}img{max-width:100%}.clearfix:after{clear:both;content:' ';display:table}.float-left{float:left}.float-right{float:right} diff --git a/idrocap_wa/webroot/css/normalize.min.css b/idrocap_wa/webroot/css/normalize.min.css new file mode 100644 index 0000000..bde07fc --- /dev/null +++ b/idrocap_wa/webroot/css/normalize.min.css @@ -0,0 +1,8 @@ +/** + * Minified by jsDelivr using clean-css v4.2.1. + * Original file: /npm/normalize.css@8.0.1/normalize.css + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:.35em .75em .625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} diff --git a/idrocap_wa/webroot/favicon.ico b/idrocap_wa/webroot/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..86c1a8c093c89251410271942191652b2d69a293 GIT binary patch literal 227390 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≶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 literal 0 HcmV?d00001 diff --git a/idrocap_wa/webroot/favicon2.ico b/idrocap_wa/webroot/favicon2.ico new file mode 100644 index 0000000000000000000000000000000000000000..49a060fc46e2bdfb8f3908c1873a45aa0e9babd0 GIT binary patch literal 15086 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 AlmGw# literal 0 HcmV?d00001 diff --git a/idrocap_wa/webroot/font/Raleway-License.txt b/idrocap_wa/webroot/font/Raleway-License.txt new file mode 100644 index 0000000..94dce24 --- /dev/null +++ b/idrocap_wa/webroot/font/Raleway-License.txt @@ -0,0 +1,51 @@ +License for 'Raleway' +SIL Open Font License +Copyright (c) 2010, Matt McInerney (matt@pixelspread.com), +Copyright (c) 2011, Pablo Impallari (www.impallari.com|impallari@gmail.com), +Copyright (c) 2011, Rodrigo Fuenzalida (www.rfuenzalida.com|hello@rfuenzalida.com), with Reserved Font Name Raleway + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + +—————————————————————————————- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +—————————————————————————————- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +DEFINITIONS +“Font Software” refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +“Reserved Font Name” refers to any names specified as such after the copyright statement(s). + +“Original Version” refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +“Modified Version” refers to any derivative made by adding to, deleting, or substituting—in part or in whole—any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +“Author” refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.eot b/idrocap_wa/webroot/font/cakedingbats-webfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..e8605d92685dc69e3555a2d46c934332ade64789 GIT binary patch literal 75538 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 J{3OkB{|TIQ9Sr~g literal 0 HcmV?d00001 diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.svg b/idrocap_wa/webroot/font/cakedingbats-webfont.svg new file mode 100644 index 0000000..d1e0c98 --- /dev/null +++ b/idrocap_wa/webroot/font/cakedingbats-webfont.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/idrocap_wa/webroot/font/cakedingbats-webfont.ttf b/idrocap_wa/webroot/font/cakedingbats-webfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..13d54454e71f4ed2ca3ad46bf8910b77acff1b24 GIT binary patch literal 75412 zcmb?^37izg^?z6Qbobo%eeK+{vpYL`%$~690qnwZ9}2r%$_B*qvK52BHTL=(k$kf=#a)Nt(Z|5o+vi1{V?{Xc*H=y&S%tE$&k)zztm*?hR*MjR_plAN-RUzq7>1&P?Mj}4AX!+ucq^>*baJ>NWD;LjQxg2~mZuT35 z>cz{}E~lB@5>+XnOrhJx7XYy4odRG+$WvCaxdGb!^E+tJXxX;YQ>7 zHOMnB``-MydmgyxuN(=zi};?4=B`=JUtztABjF{u4qZI=qJ@z!R$YnfO(=tT`S(_? z%Ia5s!I9YQ$X~yF#lq#gRy?_lBk@B>-+$S{d5b=6m_C^!i67uv0%+@SuMPY0n>2h| z|6~sfFT1^$#TaqrrW}sPHQ`18Xf0gfcIvt0Mo#2Z;sO!Z#IA(G*Z@#tmIlaL;RHZi<}L`c%D0sIF?3QEPety#I6KT6n-U+yB1e8l^?DB1y&0K za?IdXbN7a{q4Lmq@l&TyBc9_Zzm=N{K3Cuir@uP=$I~yJ-go-e_iNv`{^7&lj>^kt zS-$&2&_=Wf^dF(Mra1E-%0nCEzy1>?S*_9P^ai8JY_Zzx4yViQ@%sFMppva96pln= z@kFvXRZ^NR%am7CR%NUItH}Si$eRDRY#f*3s<={aEO#No6qn(SQb8i^IIfrD z(qnr$&7{uVgly^RC8w|JV7JDIE&6EgiXwoR14W4Ms^Al#mX!?-Jte zQ#zwvp`K7r$AX?vduYkr1-n#n79wI{Pgi+p7dN$YDSprC4DV{`@)gL1U0p*UM@8iz z3zGMALBa)j2?!ahd;p2W^w`iYAu*|Qa_6q@k-l9mBfEUzaHwt9{z;v?_K)<1ySk7{ zDwGr@UbobpFSCp?OC^X`D^jL*?rQPv;<|czsLZLI(eSSBo*rKh>XEoX}GJ5zAps5+=L$4if%bp zjG&{+TxK`n${U}ORff;2c1z;BjZXB}>LrjZYEE&sxHkc-Rtd<+Zsw zvMIMljGXv=tLk1nS@iVNbU(5a5?7zQa}UH z0f@7a(A>vGIQ2h}4Af9iNGySH0tuiNXa{KG2qZSYi*BST?}sG3)usJ-%WDu;RK|nE zVV7hhiAEAhq67)PrrKIp8_QOyTuL-jWvgoInn+D`BAG#2n!{mtN)v4KUxmk8Vaq++ z`HN*+PA^z+!37HzaHqH2z)`xX@zk}=_jYyO+uS^Scysf;on4G_+L5OmS*><5uCZCk zv4!OTeR|8XSEf%@GIS{!kQEeD7pLcHFB6}}bD54e<{x`$EveEfZ4Lk1CYXi*eN2EGQ&v;Thxx#a(ckQI1farB2IkOH)T9xy_Gk=ksP%SoRbk)n|# zi6rsxG9;N1YO0%fJf=F9f&_`nF0+SIQmH2(r>t)-WXgd3b^5;RTw97ib<{pn2RhU=gqy*a&O` zb^v>TmjT1Y|^%kE6P+7uL*}rrmUTG{^y(SB2yoGyR?Ltd_@(V zE^ArIzzJWlv1;wC{uh3JDyOciYItHz=e}ROwrJhgpS;yMf8&&xx>uKUnDjQgAnKA% zBZzec>b`2%s4r}hmLteVd9JJJ}ZA!Ebt@ar0!Bdall!aC00 zH?Ccj7@DDW%<1#(GsLYJU&nA4b2o60afi64xxL&LX!bCBHdMQOk5P|g1icSC9SGO7f7oT(TK`O;w)oO zaAkyKMr16xNwh_byxb&Yzm>{z2ukiV1oO$DV5@3U4R$3+$f%OIk+7-pk=KrWL&#Nc zkcwYlp9syUmAC%$lG+)e#Pz?<9eU%c-05$Qz4l1sm7g4VaCK|z>IV;eJkajE?rq|K z{M^rpgH(}Pk|x^UjT!U1+}F8Z;l_s#e)0`>dfjb*dwxr{ z^qS{#JFdum{mH?HhHTB9d}n*4`o??izwwel&&fBp7dJe3@XzZTcOLxo8^T@nAmLuR zp|a(j+?NpeeD1~EhhI#b_yq|-(~ZCljqkKn-tf|C?!l{0bKiV=aA)KCKOcOsp?Le7 zCwqoGbnug}b64!hJ$FrMcFXgByKUX+Z$3HraAV+-8}Gm8#_GuScZeu%HF^`3jnRhX z%NAx5Wx2YtL}uZ#S~!Cf~lZaDR+DdM-P)LMhtY}0717PCRC zR$2X#AMv83(MoEg!6;dZ(-j_T$m=l5rQ;Sg+Wc0nMEK~K>-H?mP8k}KO?F?%=B~(; z+J`J(G;3mW+I?cNJKa2S)}rM@?CG)!w=Lweo8-{YDcNOvt{X#U$wr4aWc8Gn6#>Hbxnf-Bz*M|2YhQ6EI3o}H7fukzzap=Q1^kE$OFb;hfhdzvBG>v04jbk*8500j1DMT4f&r-+=45p}7 z0~E6ii>U<`6Sb?Mo(UaK@e)B58)=t@?bF2LZBV)JQV4iknlPx+NI`}k4e}1Vk&i~a zw$Fvch}yV%;xo_hf9Af{OJCpK)wTWgOIz=IX8-fgOjIXohbJzRe36*hS{nCw;-yw| zEbNmr#j;)_iW-BQ6t^BfI_v&FY>=I9k6m9jVad>;OD2@*?H;#NzUKEoo_VTc*{*ovtgH3-KdnSiH17Lg*FNkrSEK7<8Dn9c`|#GU(7&j4RETZzo)1FbYTX7{y}DJP}}4>Lr?ku$C2KQL2Hc z02dpmFp#N&7~Q~>6rTI7Q2p3a@|=l%lfCws5Xo%rhTJ+o%rbNDMFcJCz}q?lL;tR`Y7#Sdv;49CAX`n}zkw@$d> z7k|tBdE3lAkN&7htyUS_D)qEyx;AmA|Il|`N3ddu->lMkH2k%=V>rEJ$dDzap*nW| za2WSz<)|B*06RPNf{QPhnyosoXZJf-T>j4Pp7W~mtkR`9l3aM{hPH7xT(NL;u|GQ| zBUv?CwTt%$BF)p5u4yS5(^6yCI(2F%o~;_scA7X;e3r9wNv?@o!(GXB!(Q3MjoQl< zBRYj=Ol@B^*T~*l`m6?@+fdL&cs?|ok8plDM=gHE@~_|)<3Ypzz%USImIUqfHrCcd zNmXr4bveO+A<6M*lgM6#a81+!#9?vD)EY@7Wmu5Z7GeL@RD*;6V2em{UA88QhiM{` zBa2vSRJxo3Wu5`DbllbF)k|W7*l=F=IDcLH%$Am!ZS@9GP+OkWn>EukCfT6MJ-SU8 zI=B0#yC+Pz`{wSsLxq8LO}QCOe7RsWI4ow1HmLJ>{W`nWuGg#8vSiSktyY6ZBkJZ| z?}V)?@MUVP)}WKsl61e%*X8$j;(woSWB8hf_n&|M{)g9x^(I+>Ek(|g)oRIT)*I9t z^pbRZ{_8J3(miHO_aiU9K7aS_-7jl24m|{$iX29RN>Jo7~&npD_S7kwvPx zd%4H)EXUzl_LD3LGQ;9Dbn;&rXC`T9oJ*mjx3VW+i`2hlPyUy9$`|7)UyQd|3*N=d z0P#XrEvR1Zw7HLnoQTO{6se*}Rg#Zu6}jI+@SgyFHVj}52oI0~8h{R<3s?%Q1vUfQ zft^4fZ~!pO?j`LgK^bJ1K{t$pdVPycO{ah}rM#B}5jz9)jB;vYlPu>15jIVnYk|$cc3>ya2OI#70LOsi0GlCdKzM)@ z&;WD*UBFUcEwCBb4(tT_fCIo0;23ZmFw-$j1HuEOfCiug=mM4kYk|$cc3>ya2OI#7 z0LOsifO$n9cReTngNfP-QClHuD@1LDsI3sS6{5C6)K-Yv3Q=1jYAZx-g{Z9%wH2ba zLe$p5N}Z(;rBY`p1OxS3cyc@N6luSH7~wjE`w;F!&wU#`_i^?#X{y8E9>%jiZSE!Z zLjdUeK(~T!&C}`zOZ5uu_ZIe2!TRTxGwKjWVBJ#{ z`!Fc_qV46LLb@HGdb#i6<{Ubg7Vk61ieo<1&v^@19O6UZloU8az!`<&(wvhKF2`$f zA*aGiIW5nfiSRGZ#dP~QRO4gd8T^9bOeOSTM#9#hkSk zBJ+BfZxokRJ_F> z$bD`P{`(8QI5ITtHE2H4sbi{>kEvp^{v(aSn{JFWl?3+%OE=Nql1-)bS9Bx-W^*9n zNH?1OiQMP^~qif5kq z`>gqDVkLHiRp*qo7#=M;J>Tl|@;)y?@e_hzFNkmFz5wJH-V;(=UJes z-Z>xiFQA!rU;yvuF2HSfK)dxrQw>tfPyid_U7F|ha@QjFb;!K|;YK=f)Sw(5AO$o4 z9Y7bb6j%#v2DSq`fj-~>a0EC890&4)>{$v?#-pw93s@jJt_pt`+ zOSdQVum%ECcSHPzU5%nGWSc{**Vsm6d3V7ecrri%@9cAWvF zXoZQ`!E!n57-nin$l`QbQe%ge>9sapq_NEFEo+QW72)?t!O~iiwE28CKpbH(8>m@Pv>Cdq|i2Lbxf{JR^{}Qtx!@Nb|_^ zj2>f0cj*y}cA)Q6op6AHEDM*%0-}Z|Hlu8E@hXk2oP=Ygv6SBl&88Lzu9vH;veqK|=EEshI&zoH?Gd~hec?q{5d|L8a zavovmeID!Y?2dtFM_PEHwZX*e2FC3mf8Rlx%OiobWb~V$gp4l1W^_B;fk=7oJ#{7& zDlzJeYMVv{L8@w=*9&1uimTH_cE8;yYRqc2S|pNMB0??CtF?Sgq6^$mIq<8h$BWdb zG6!?iP24TKelHZ5NSFT6<>%+M(q43UH8&DG=9w4?1u+r|Vk8vANGOPr&`;1D64E;YZ|4g((pUjz9CoU;_7xSY;X$O=}SZd9im)#*lcx>22O zRHqx&=|*+BQJrp7ryJGjMs>PToo-a88`bGXb-D+ubCyDs>YSwz80G@B(l)B-lr^b- zZZ@Z92J{c1>Mmf)EXqw_oHgK3MF*usUuwDt1#^t8F)C&k)+Z{cFPUVSA}M0YpnQny zJJ(Ee!26bgYn$0~R7=2FO=Pw(X@Xn`RaQ`Hn~|F8mpa9kRJ<52X6q5E_v+LUr^A!m zsnSW#+CZSjc}iz@5h9g@LRG_t)mTQ~F+L+X4LbE?y+P$R`V4N-Y0#@D>5XEFG+M3p zcwIErIc;J%=CWFCiMnWU=d?-T*va?r2n567Tf+)t zawV=3l2fnMPCNCiu{;=_aPEwBc1lB$%~(M%y4VGgeiWKelAem&<6ku`52FKtJ95`z zk+wWW#unLZpV`Vi}&#w1nG+V2^>d5M1Q&LeLJed~7 zl}QrSSS!cMSixUSQ;}Ng&2+F|DN6mD&^~AW=DnS8PYX>19!|v?a!GP6#8byLR92$4 z4yKjFoZ4}we(+OQo2+92HGb&iG6BO2iVb!Sq9i5A5LYc`os{i#FrGHctgFhIwaX64?tl`-|8ze9OtD%xW$_ZeppvCJBt%Qd zQX(0tiPT_%U0Yqla#B0anXHu{8aJW!LPERbkQ^1VJ(-9^ksbdx!6ak}PynQX4_~gJ ze0o!qpWfA3l_6Q0pW2+158KWjl~6hqDnn$HU3Owhm(RxdmDQD0>frw6zNF`#Y18iMxny$Lyq!naPrRvn$=FnC?2_)ACMxudI}Z)K ztJVdaMwi*_G&ucQwHj_@wOZ@Yl1t1EhnZX|$6fm|KbEh!;@jW-uDE<^np*2e9<#-1 zbOv-R4}R=A{zZRnsn=Ut>(7kRlW``e)0BHgKT7q0wa8_Ndi4&I(P{8S4Xz^6Q5s^G z`cR3<7qdHJKGVSC8Y)s>ZgzRKTAiS}Rg1E@3?ZGx!LI+=D$6P&3AtBQDpD(|N|rsp zWy+K-&o9e|ylilr?7U>h4~#pLL!-hCwW85tGaGol(E)$8?g`0+)eV&(Th&?(?+jJx zWsME{B@!ukBD_AA=}B3KbwZJRXb-yMT9e6Vu?fWn3(9UZnAIlZz=ynA6tMwAqtfzf zf!Byyk=L}+9~Ic5gHj^=0-|q_$7A;fi)1hs4XF* z(IxZNk%C6R!T{YI$joDchLJ>%LBax@D7|E)R;LpLmSY&ki18x}Y z8Wmjp8bA&A2C@s1ptDO5pw&FBbLccyQBbCjs0lQ^L&ona-Dh~&ANqUU4g9o)H(ZTj3~qtj_5PwLyse6=OsN7BP}xw(vWk8XI{TUG4w6j$Z` znERYb?+lYr<%klS39BFj-{hII0xu~%t-ejAKlQ8u9f0f*P54o_vrfA2hAC5S*vC3+ z?x7;LiTJ5A(P1?4P7@r3Mw7;@H0}57vvTBbT+lb^D>s8Xh%f` ztVa1wrm)2rRudKaqehR8tb#WRlTkSKw0fIbG;wRYe@)ma#ZbKIdkr*i<4P+D$cN+v$?+QA!aFq&?Iq`7_IHxnC1ew*TN(8`P}3RpCa8ss>H#&8QrJ&1Sug-$7;=}u z@T2rfxauz*j3vLr-5%j2Se)HRGad2k5x=1zXA9~<%g{^CL&|MP+0Wh1-AXo59+P($ z(%&;Ek8yTE(j$0U#+Z3tgS%o~Nf zO$6s{aNfz+x0j=wKOpTNu;%e5jN09-CPxqTV+~MgiC(e^hOZ4A`(T}jYw+%f>mzPz zZ=-ftyMuX5!*K|)qD*T{LUeVHaj^%0j6-Y$p&MZoVF+OiAx()rB`~N zDQS*52x-aYBE<7$D?$Baexd#g3T=aB7uG(D5W0|KF=XR8ktL9Q;b1DpxfCfbMJr>+ zA6WyMw(44hG#92DjDICU%D)OBWrMZ3q&M)#3UIo1yyn~SRT0znS;JksD=Mer9A0>gh_`qC_k@nr zH^8UBKLO@!RD*B>#XvnU8t4R;0Be9v!0o`pKriqL@EhP$;GY273!nz!28w}tU^LJP zECJR4n}FMahk;(;72r3(r@%h}^9n^F(ymKTK_4pEOG-iE>l;uJyf`I;4N4y>DMQM# za;W1%qlLkx>Ud0{si=acs&*~Hafq2PD1mf9^6dOQ6y@50H0LADf_%s9MVekhmFZ}N zix9KqJ94SQoQ)W&C~01*C`%EpLr6=q5#cC=n-J1;J&>?vumg~r3e>FyspvvvJ5tm8 z-hq(bm#WSpgj99j54*{SF09CX0GtO0J0jV2W_KmKk&Bk07a=WMKhnNB*iNkV4kCt@ z7G00fR(ca5E#)DEw6)$sNK5}VLMrJUgj5n$hBV*r5z_Qj0n+?O5z>4gBBTo7Q-t#o z9>bl#_)d$SL=3GNRd|;nqzaEfDe(wVQ=a;>Ac5B+gajzNeqLXY@EJH%%^@dmMToXy zY7P>i=9shAB})?x;-81L`gP@XPy_+zQlAxQ9{ zfr->)k(1CL{BI)PQkDWQUZ8|Rj&FH3L#beVx{WX zoVupf3nw^q;s{CSn6PklQ`6#(lsH`U8WWTCSWk+Ecv%p6y*AVq7VJrz%44@B25!W} z16z@McwJG@Gw@W8Ktq+JrPB>!&tJ;8M4B_>a-V(Y@=GNL#Dsz#{<}#dvQ{JIS-DTo zl$HBb$+n5+5*$h)R1&5_m_I!srN%5CrqoGlzV5)Si^E;5EiJ9BKR)-|AGbz@aF98` zBkrJl_o=7GTa)%GW5Ad`xA^GMqq)z<3r2p(<5%j6iaaVz7~QrN#b_#Lgtxeh66%MD zeZqvJDW$lmExx~~?LK;x*v60lAT?Mqoh*^st3SX$lMb^$+pQn)GuGLJbKq9sQ#yyn z5uBC#Y`A1l+w8YjI3=an4O&8`9j#PakyWHe|IpE#_UIwBC()y9N0(TJrH_`JaTo06 zzxwD=jZG72@nWapb5C3ee^c_j>`^i~I<0gZDGCNV5*179n-+~J7Kclzv5T7Wk9xSM zb5{oUB+KJtLp+|Cir2y+iFu>m7`9lfi6N#lZ-y%-Y7><-@KrvS2h!;z zI-_*aVNHw1rljU;U){DS+^IZQ`h<%U9l>xU5_UHf4Sd26*O??8bslM}KKNkZh@cmT zka=lVK-m^<36QTa9e3jf$?4?-J0_5M-KlPNJ5h4`1G-xB_0jLJRgycPu!$Xy{7F%- zwW=*24E!ddpJuBx3CmKsZAQ1=n-VU9v&p8-J@KF{VYVLBV}R+2;)f?Wo#!s4i9CUz z9uKysB=;GFwSOQPWV0bRoIdeWUrX`uwyR5&($L%bbwV|Yqq>jhy?^p2dk8Ct?{eSZ?j>Xh#>XzQl&mIq zlPAbN@*;T|BiMW7bMiOdz`L-iWir2#U(esbKgK`J|BQc~Kf)j5|E_P?%MZuuOa>O| zUj7PDY~KmL0u-B_^Vfme$YS?^`U#_60QC~1ehKO=MjZk52BY2u^&X=zpXdKXDQue) zu@#+C3qW-+>Pc*Y*}$k@!vnzNku27NoRkOaSq;mXQd6+nG=ovMfyeg1ke`5e592)q z>Pbd@jJyXy!Oqj*X8*bmz6-piz*=B4upQV5^Z^HeBfv4>IFR3ta+X4r?I>p{1lv)3 zD3O-hF`Q4?(CS0wd{|2NVJY2**7R{*z*1l>uo>76>;(FN1HcjB7;qfOSMDr@D3v=) zA=uEWVsprkVP5{8Z9$S@Tl}8QJB$U&RiHw73SURU6BDN11};&Etu9ct1*)z74QP}NXp{|Tlnton2K2fOXp{|T zlnrQ<4QP}NXp{|TlnrQ<4QP}NXp{|TlnsN8a+X4rMmb9%Xq2l^q9<9kuNkZ&{r37L zRPiNL@g-F8B~?Z8f;4>$lE0geI30i`2?@Bk^G0q6j_fTh4%U^B2C z*a`Fj2Y@5MG2l3$Y+VQ80a8E%&;fJ-OM$h(W?(z86X*jD07rmhz;VF5g09{}p?iQ7 z&;WD*;_QBSnBnH24}(Ms)UX1DR4kUxa{9=a{Qh^02p%8>Gyoky7qApq3v33q13Q5} z-~ez0I0hUC@-1_gLRfEvG!Kvh8h{R<3s?%Q1vUfQft^4fZ~!<090QI6<`w;<@amE8 z6}rJC1!`5EVl8+rZgwqhb}eppEpB$LvWrTC(a-~=fCiug=mM4kYk|$cc3>ya2OI#7 z0LOsiK)yZBQi#$XXDNj4qS9bU_W&uN0q6j_fTh4%U^B2C*a`Fj2Y@5MG2l3mug+Nt zQL1y6LhyL^7arw{1?r^&^>TrFr9i!!r&v=QL{l6@QyfH797IzbL{l6@QyfH797Izb zL{l6@QyfH797IzbL{l6@QyfH792{(lvlOB<#aRkLQ~a8Itc>pDH+c%ZT7n7c1QI|k z&<@aDJqzKZm~sf92V+REPMtsks0G>qn&=91AHRV5vH7V;I<;KMwhHtr&Tdou!XwB* z4IuiG!)EpXDWC!90BB9$Mba;j^j#$VI~7ho2InjIrg?&0MNU3M9nAa^PQ}lK8QhQZ z&E=P{L2hcE>gDIc?Yb83)3s<2N`D0UBe+sO9!!hgn$JaEDNyeWQfNFS7M>$z=MS7H zZ2wOk{p=%AO5_3|R%3r2d_IV0?j&3YQS97+uZdE&tQ@VQoczWeMzh#>HFn?7k4adz zI8rgEjtd(?;P;@;nkdayOPx}P!EM2olgtH#vY3c+mkh7$aaQ&~H}S5zAj(Wj37-wy zHto!d#GT+ULRJ(lPD@R1nU!%LR(fonp0!_2$d5}%F+Ct{!6Lp{%I7OZGTdBQ{(E)JKI=m zD=qH&Us~IRN)x(G4Ew3*hr9H{Tx<=O<8)spBP?M%jw8rgXreeaZeyz$y)|mio{y0a z5cU-i{D&^15U-(+w2;c_`tH-R2<(|63!ZgtjVQcO;2C)v?S9yghOO)Px`>Ji1M&ZmCUp6o!$u5E2TNy9e&MBtmYR}v$%pHP zr&FsEWU45Xm6h{+EM$!YT~a19rOe>SM$4+nlbNZR?^PSBpDkNewmVSK6t1W>RF|zR zGdSxL)osL7Q{pR++A0&C%A|{2UZN|}>aeBEr8BsUj*wctK(}C2=D_&IV7(JQk5q}f z#4bB414Else0dr&; zMpnk!$xxoJEY+2I((dzh=a&z9pVyQ0mAyG{!_Ln->Wz4rEEH_uYkh0ud%+Cq3@}daoVYShrHm|)bUtVjd z)DvwdRsPD>c+0q8WoxV%lCXgalB(05ikS25vXz;CWTv2jjn$L=`NqwxDl@w3<7ixC zHEY}o*0^hG&2FSx6 zPoCIz!;Nj@_?6XVWwjb@Dq7oCl1_v|H$9h*2aC3B(Yf`HKB2a%gAtQA=6pQ&Mx`s9 zB~tDU@=$hYZt~@+wrrp*_+oBywI@3Il2om$xF%SVbr)B!O2yE_l9J>P22#0iCR7j6 zO0sN{f?f(?mU~orj0&a)jWpW!V(NMC^V<|G(12&V( zWQhk#Ykg6*S^ZRM)~wVnY<>!9OEg8}Wv{KNCK;6jA&19eGQ?a(t|C*Q)Sqb1U_YGK zI3jmEnzoes2cp%sNV%^h<%pEsIH|atue8Q$qHC^+wPu6k8so#W!3m2iQ0^*Ud6g?! zb?-mE`syFKgI|7G^`8smhR~EO=so`tS z8yovwbU#nR&p{BV8lhumqMp{$gTrJ5@LK={_5 z3g_jjKR%x89vIdXjLxiUshGZ|Lm07UMs>q^>qhWK+n+m{8pjU&Qy5w@_JU@9^hF(U z5^ic47*#uPjEu`YBMi-94e->@|M_oH;5-2C^cd|J@#k2$F5*hD|GN&8_)FnS+`>JI zuU((Rl>L38!52Z!z1Y_;;!qpvv%3-$H7V$^Mj}p+pwvcC*E4D-ym!nOhedJ`bAK9J z0iH-HB7;YZ|4g((pUjuBOAc1fK z37{5e2c`jwfYrc8U>mRl*aN%_90ooHz6RI?Spwk%5mRl*aN%_90ooHz6NL&H==5rv0I=AeIUe4 z(;wuYa6h`B@~o+`4>uB=3Aoix+-fIowUe5_+)iZQik8`mtt!2spN6Q{(a|bc7kOPd zK<{-pabAZL=XE%7UWXG031;_k@G+zBJde!JBXcz}zX$p~CCit{@+Go-i7a0t%a`i&7c&o5y1+kbZaZ_RR&m>ynWli@a(k%cN zXDUEeFLwcGgv5wy8q50#4#GmdOTfhrI!Nl}E(MLfQ0xuLu8n$nHVCo~5#h z1*yM}(*A&ZmV26UXnxG9xGj+71${H-KbF5=A87jR<&8*#r^xdC z6uh72^SuT7t$e=Ug8nUNS}QzdmiANdKFz273iMa`w5LFyQuy>l0aj}#@;JdWnX!ip z3-bPaJ7dy=Zy#Xr($5tK4P7zrU`)FtQoFYX#%>LXTjC=Arva?#{0T$(=|k$99q#{=S*<^;zFtFgyrd7<8$DQ$&77pf->LNG}AX<~H$uhzCoU_g$i5PeiB|{cm zKW_ZS1w)1`*f^eqbAO<`l7Z3mlCsGq0~`2t{JN8Ed=uX^@FM>Ev}|mBQBnQ)Ov4y| zgR3&=EeTmHMWxGmdvq~h0;y!wXT?DxECJ@ciH%8+~vOaDlxB4UEwW)H)*<5xUDGRsdB~>UUS%MX{`t}dLynz55dwdAJTxkuZ+&ROq_@{pLtAPob{rmZ8`}d!? z9w!&2OUE~aqrO&$+aAeye3_`-<7|i|kvn~pt4MqzZ!45@ zS!~^1gO9v^$UT8q`9+*&^A&&BUTAU=hJ-Tei`Yy|sihe8uV&h;2U+MhU_S=u2FCdb z4&tMnpMmo#ON}qU@<(rs0j~i(SO(B&64TikP-aGX@P0~Wde8evjqJ<&=sl-8HEo3(e{*gGpK7AbrFWMMWCS0 zA>?y5XiP*awPAas2b;XxSSyAK)Y1ZVLxI{_pneGXK{{Y?7oi|eLe7(TK5d|10Zj+g z&q2Qm`c=>qK_3KtFrVf_b^=Pl^Po5m6h8(unjEizAA`?2n7W3iz=ki{|EsDlxH1O6 zD*G2t#=q0n|IU$7(AIvE*VY8Siv0IzHViGL1ef?EtuStU>sra5uR9Rf$!m>mG#q$F;odVl*DuEx{L?0X&YwSOZD&{5v>bMiq0QVH>WKbYw4;THgibeFQs+rx8!QR`sB&6SIwxZ znsL=?e|A*q#TS>3%KG`HQEO0)&MU{1jTu(unh~E^ks4X)M?p$(n3__MHhOp-79-3zn4Y`&z*Q&oO+@|@}GPr+qI^x?edw`b?L?7WT>_y zRWhb7R2-S%D+!pjHU5Y_Q6Eb+CT%*6I-N1H4umTcPaMc@2fbM~Hbt~+v3)#zbZ-IKYKz%+)Veh??4(7WC;ypkL zXaG8ZE?_CJ7T64I2X+E|zyaV0a11yO zL0GKM4sysj;3)HjUPk`~7NQ+RC`DMxHr3k6P^zjJw-Ve++{F%yyN)VBeA(Pfn!&9@ zI1=FsgjXS4gYa6as9*tN4wJ=ncd4RM;kXba4nK z{*PmOA_@W1uSuY1z``CBm|%Pu>QuftrQf$=KV#uwCHjSCfyX|gg?RX)+4jo(d5<&$ zs*5{9KCJ+?e(49rICvA^w$?N$-yXxwP8&n{%`&N|66yh0JvDx@Ig**IikUoka->pW z_T?$6s@xGL+bX&m6^Nce3uE=XP`tXWZFK_Qh^erTOvDK(Y8BC$ERv*>^x7X9oe8HA zN4ct0vNxQFcy5dt+*X~>A|*!H^}0-Hae35ls)?0VG+pQ?k#J^;+np&5MnnUSz{aUU zL~!5(L{Tr0Rk-!3I}Gh}mSvOe*gfF_&H#NR&)ztJ2;ZaoPpFE9P}}OrMjE zAJ9dd9#5GOUwGlrW>Lad__9=z@P(Y-dN<^$biAoL>)n&qU#p1BJM8M>55(P3dv|M@|(3*vmQqr z;%rKT(WiYX6jf`CDX+$&i3K%+N-qg6mu!$@PQBNq=0%Qv*CHiH+ZJ`lZIC*cz~9WNP+OvPwWxJ8sO4pR!s_(t2ObU@O3!Ue^EUdmu1POM>c*r+k4a@R z>wWh|%4{Z+tt{g4p#97Sy+O~3vCA(JaC(+7gD^EB9h$7^CPmp5$`b&{Yx*@U)p zxoG?4Lw06lo4i_l8K1lPxT)M_u(EH)Xz?hlyf3&DM2(tccEgRd8*ZfCa3k#= zbZDKW5XGT&mO?NN(Wp+ zujm0xEFKdaLZ>?YT#oxWkr)pK0LdVq6(OcPB%BWu2&ueUI`-{=FR2V;UzUw@8kpe{ z>kmfo=$O}!nbrr)x>ybl8xJuXi}PSuCaraU}6AD}vLZE@7Kr2!oU zP0tSL+D+3V+5zIWK}9Sp}EHcdzK- z6v}y4%Ia%)FfBYW7K|P^SC9@J$^b%tDQRH_H#Wc?s0#$LR zdvpo^kUNSKba6ngq_(Iv13}7n#;XGSLsZT{S8=_`8?`G}3Wxp<#xl-dZC;1l?eN-c zUIuG%Ynj^?2nTGG%?Ni{Yq6&+Y;)W3=|2&P&g_pnY<>;SJiwKuTI!ea8MZ+-30kdS zaKw#8qSI(}ibck_gPsvcVYFJYuxXt}?_!KOoiQWj*W=S{6iA~VXV9o|RItV%+^N@` zdRA>fxoyQP+L5RV5N9wRb?dBZwOyzDx-4pkp1d~@W7YlApN%_FVWUQ0Uu=(fO^|80 zjQ-$kUe8$5S1@=|Stnp96*3yl4vX=8d?T-$YqShBmjr^P zrNKbS5}VOrvl)ywvc;}GAUV2>7K@ReOdCTvdpIMF6c1q@E^|7JD>nEME@10Bk8tmC zA99~yJoyLt+g?oSMR<&W}#;IL|Ro7k4>0z1$agpAC4QX$VEcU5s%2yYviU zB={4coFNRt1EhckpaY;1mI7;m&A@hGC(s8R01UJHxm~!ga&qxc3e-y|Qy0?}ALMz; z-9OHk;xDku|6YjcLV3QX=elC=5UT=|9tXb!Dl-*SH=}-nwon$O;AjU;V>iIrj??-; z5%4}|)Tf|6V$=bodYe&y1n&bz{T|fc8TA)XikhVdob6^j4dh_o4Vr8TROu?FB2_4| z3My?03aJCF1Fbi3AJQ#`7A>F^vxSdNgY*an1q5za$65BUk`ZJ@V- zrs*FB{V?bQpdUrk>_;gSRlFOVpCNV^!j~|?u)!g0p-y2y4A+E-BU+O`76`uV3{UNB z=u&)?M6U*Y6qrF!bX2WY{hiG`s zvrGupXhnmcX;DRqV<9lhAoPQ?a0L5KvSDoQu!J!Wz>Fgr#^GN>cslQKV1g1!VwzN4 zJB0pe6j!vS&K0hSJNyKJ1KUMh;l8WcKYsea=e#X<{~lFuusZ2g-aPUeF%r$B zlXEH?E=Yy3q)w@&Uu!g{R%x~TbsDwN?6#X{-w1u8wW%$V`WchQW*+E?)|VD(b8)0u z;js*yQl;$)d`1%2hRcRTiQcHgap1iA)J+&=lC&WkZLSi879V=%~GA z@~CTSnwu*sYHyvqY}R4B-)(oA52vv1&L?JPhg^`1M#?gYS=phK%ADM%OK7zTozSXw z=$uBY@thxNa2|@;jVk@rVjOtVm8!ufL|IL=WZ;~upfCTV4b~L932Dc7Ra#MKCxl<3 zv1(!?eA8dG<>Iqyuf!Ie8vx~*xtY?IKaQ!sG zrx8cx?gzaeH08e!`u#lrkD&huv+6U{?NO#6zs^%i+WayW%~vp{aId^E#nO;8468If zH57Au_D7)TTv~8ZONE`3j2Dww;`Bwwt4Mdb;qL`xL}hXh2POW#4EWRxVG4l0x9spR zXbn11hqZ%OJ6wfBqm03}p{I)C6yARc<^1)(#t&W(#^c~C#X7P}XWRg5T!U=#tlAZb z*v-UY*6L-W*`{+v8am?vmCYve2XoJhQmUcJxj5Ravkhw><#Uu*RaaL!-43fMSW{cy zJf_T15YCHThghCVoHfjFvd3@Nia0qAywLb(Q+7MXkY|o1HW7cBLK7 zizig+5|KqCtf^#Jr_Kx;)mmqwXDyk%$xPB~@+aNVQk~jmbY}f}oz@zTSCVdzD_w%~ zjfp4=s*<$J^Q4ZPqt$p!2AA6IhefH0`uV8G(TvY=M3%;@D!; zR7`58!VH;;N$pf5n#vZVFjeEasD)ArdyE=ce(0hJ%x1un8MOew8v&{w6ecxxBM#-m zXpDD~%@pv?1#v_lK6u8og-#mcRXEp|P7JW&b#OSQqph+cP2Wdpn$}l7W^r5df=MmD znM;?y^2qgbve`M;Kk~}*@+|U~`~Y?2ZO!G%b6& zHX1IQcgIB+{b*iU*}NZZ@^_3IGb9>onv(G}F4_9PGc#s9^Wc`Hjg3pUJowCvN%!4$ zeQkAnQ6j>dOcm2xlQ=Sq@3NbXu7z{PK6la8hwqp^{f@&|(-6;so*jFEc)N5j48{PS z2mPAy`&iP!)9?aqXe}AdEQ8h}q<;ZV29MgH2AT#B!^0j1R_O8f5|uygGm>#IYeYP} z8VEfI+v&PhD_T~u_;83etVB90Snzig>65_LCLG~G+rJEHs#*KvkU?q%!3e>z`O2Tj z!)eFV_K@ju$M9RiT?zH(u-T~_7Ax>{&uK)Wo>_WbLu$ef@%D7+#Ob26h%=w~Ze7G~ zk7)UIGB4eBa+~UcTnYX((+_bd8?Q5Hu238BXCpON)7i?^8UuO%2wjlN@o%! zqDourcFW1%83m(h?481oaLkk%=PTuYN!7$!I-9$S&Oipn-+8Cf&%33Eq-Ws{=s+#$ zp{;xAiPM<8)4oMNoTuH!l0R^{2A`4V9k)!U!`z}F7MpOUAJx$8FY?gdIBal3uXK4? z*EvI4J8ye!)vDKS?;P7*>~eOUQ+#e|YeUhZ_Vmn5vhvcAv@SEhqLv9u)`j1n%MyD;pseSd1x@%Affy%$W7`5 z{=zNYLbixVd+8}rY-y6NaDeatDWC!90J?ysz*=B4upQV5^Z^HeBfv4>IH0U>fbak* zpaJLrx`3s?T3|D<9oPx<0SAC1z%k%BkY9#9OCk6~%>ZG_!B>eqr5Hi@Ll$)R&bQ~! z&;cDA%W=jcM&bW%9x zDsgT}sLGUFG_3W?3#YjB(o9M3nsVWlt*sYLNaMm5YRi2lr6*j}nvWkbU~d~avaRir z88aSj)7msbBoyr|&vZq-Md}>`Cl1Xy^yZvHhvvL_XbyQjG9}fH@7i4rf$XYbt;?9e z^n_)tt?LGFWh)l_q=emaT`Nm5od2xtQ7XG_#E3TRU`>q+Me)zu7#jG6@aCL1@&BRO zZ@xJj?>E&uN2J@afhr5FfYvjh-xT4+Kx5KN8`5}~Ho#0Wzrs!b?qB}hf$8zBL+M+O zP?*k@n9GPL#>u~RM~P3HTrShekvol5{lOtwi2d}BK{!CiB-Dy7Y zg4yZIG(r7ld`_HQNz;ohH0SXL={3csK?1W-`SdbblzxovYD3NFFgF&UZZ;RS{9u(u zk~qAVe(XS3m=Z~iGJVTy0wU0nhn~JnXM4~BPzOq4R~y=O-ETHd|5Bl{V#KxuhlIu_r8c_;7g7Tfty*>eR`xNNvL54WwGq3+B&B z4r{Wi-ug+%>m^sKU3#mvIsH`oZ)nZGLMUWyD5OJv@t;P2M+f+f62h@c{ zrHX)x3;fZCKA%3cw2A-k@7y~>K>q*t-lx!C&Tr0k&pG#;bIMtxR^Kp1o(B}*E#qO@Ezci=d0jf6P64I?;znW?AcnD^ZdC7w;Dli;Cn78nVcSyHODv>ctFfv$M$kI=Fg>S6 z?NqsB!KuZTme!zhAup^2!1(IZ#Eej!Uc~;v8-SuX`9P|G7GN?k3@isO0ImYA2kr#E z0_+2x24t9?qqY<1(g{$vJHW35ztX|41;3Voc)|6Y)}by~zo720U|dK8uK!e6iME~! z#!_;w3oH<|Ol%6SkWT)|^MWud6+gF2=>>69O2}z$rWntGlS!C19QhAfd~*GgjoRyp z>S~eN#ma@dbamI7iD?abe+yp#Qh0|coe1ioztNyp9&AZ5t+MBTdKkw*=yGs4kfdRF~RG zrA#(u=9;@T!{K)s{{mMG!HkgK_wR3d17V+)#|CRCGTa@Xh)jw#aX9>&iA!fSH_uu+ z(FwIzJ-R1#Q9zG}VqW)UCyK4o#h1Cgv5=()FG_k0@ATV##r$$`RKC z7o{jZW9;VX>z8zOEm=Q(h8>O_(&JIj>A$@EzCN>}Dw`i%I@x%v zeO`Zauw`y zm*17WKzjh}kYM_oF4K@>`T^tb*cEwLFbKI`ELjS66GT}^E!flhE?SXngF5oh`kUad zgTKzocImVA*IBzNhtfBQDt;snO9Mrq9~c6b0&9RPfUUqCz%Jks;7Q;R@EY(IpiYe* zkTg&P`hg)}DX<2(0@w=N0qg=E0iFa70j~jX0k#eSNE#>t{lE~g6j%dX0c-{C0CoY7 z08avkfY*Sx0I>=88+eJh1w!QHL1gZ7+EdztvT?bZoz9QAPH->|%pOKJ4HSWXUW+msR5L;QYK{l2gAdzXWiS@JfA zVL!Erc)f5Nz6CBy62kU*6#P-}SHYhEf5O3^1{VoT$^WME0L41Y0KI={SJv=5Y*kha;u_GwRZB--^Hz}Z1? z*f1Jw7)_2$KLN)HpTd6z{xk635dTYXvCu2{@4$Zt{uKD1!T;>UzYR_ux`&W@^&&f0 z5!LRi%WcrF*B>_iE_2+qi}c$_zm4>J%B|IRIoLk^VbUKY{XsSR**LR6D=-Kw09F9& zfQ`U*U?*@tupc-Gya>Dj90u%{1Cj+=fk9vaumV^IYy`FgJAwOw{lG!sMc@tKFkrtN zkSx#&3<3*)6~H=RBd{IV3EU6t2Mz)+0&f6^0rohfkFLE+*HEXCZW?P|-e)X&4(I~s z_Y&|W_U3PJ#4|YJNg3lB@N2;T4$c|a;0&zrZ-Rf*sq07JKk6DW{#YJT<7gSfl(sYY z@>y}mW#PT`!bbmt!V}?5QkLbH9*x$;} zG~%&+26NtU5r*t%8^in_w(B+4gRgh+4d9}KL_3UI!EfbxjEZpxoKZ7qv-*wwYvYg3 z=!|e;u*Ye{I9h%_Ja)Tviq-1&!z3Li@Td*EOBhlU>InQzbDX?|Xqqe21H{|jhI-|o zToGARhkHd*ksAWk7R7UMXejMzyL^M;8d%2(6zBk3d<#f#v?=*$ZYYS|u z(|_N<|5s#mz!n;{Wk#WB!h;<^(sG7jaDcZ3HRa*&mX@S}BAO!2ZEP?r8Ev6W66KyD zdO_S;97#__7$BDGOeIdy7Lj;y#6R)s68UFgQk6+AOfm==r)n9ja*M`~hdms^sTwyN zGT1`Lc+Y4co~kZTB=8L3Omj_pzrm2Z&iKJ#EF9X1Ge9yJB_*ii`KPgP=Vrisu(YO%laxU>5wZMmHr4!Sb|vzgbltNHyn~m6h32 znL*B|DG_1k`srmFN-v~K;|mNRTlLNY9KRSbCF|T*(d9N&6>VHP~`=XH;CLq*8~R(6|-F_k1wo>1)Zg2Se?- zmOe8a%t!GPVOsupI2=!o?PwdyWP3W(-BnhDWet|9db4vbud|xtJu7nI;KZ)_CQrOJ zl*mO=@q22TI+|+ki6qQ|Zp4giHS)P_sc-==8wOCbW zMza1`DpbEYlW&ex2RGyVCI$=8)J8o)yt|k|tdirpa{9GK)S`*g@~A`R zvZ07i_qhGiaYl=Q`KQqeA@QNxqs3rqmoppz!yV6rLiLGYI`y8>8S8aM#0W?>|9b`` zpw~=S!_ncjhr^@mjHU-KK8)sf-?J80MoSYqQ|Zo*)@Xgce)>R1)Z;h9Gnbq>L6*^D zp2ECKmt_)pZ=%2U)HB+!#@dk`4A<4wM*?{((~+FtIQ1g6wq$)dpuJuljx={CEi2jG z90`XbNYsV(A#Yb{LXWJTkk`}9Yzqz_=krYL%5+xsoSuuDFPvhwPRe$-)Oya&v`4N@ zr>~8)XU_K2wsdDFwVJ0qg1_Q0bdeB_Qw%H>uLy)fffcxU3462w* zH`FGsiA1hR)Na6yk7m`j>MzTZV!_}brkFuJDdG-!-2o#xyBKe>vJF1Zg~@nx1A`g% z8rfVdl&lX#s&ht|rLKE;UR^``qD0gmY^e_E-jMET>|rIxQ^$8S#3LO?K4Vr7o;g2Z zr9Fx1v!+;)`ntOCV7}X^F-!H>EN&gf%}}7WI~t$TA8IW&wGt6Azc$C+(4H(6s?5cu z+?sg6wnbCUsb;Tt~8fc284i?|a6#!A$qtl!4+>}iMoBD(h3b*(qKeDsSqmrHQW_G3%!J!2<5~Q8hTaS7!1zR29z^5 zu_JPh$K&8}u5~Is1dT;(bl5p(kW=^pQqz1DyAJF^g-P7y3fm5LGvo;Io>Q)8gy%de zy!r=W5{N+R0caP7(kC5pEkZs(c=d4XU0+n)xC_p1h)a|#mk@_8B;OT;4a9PNqdQ;bmz1^@7Lc4wnavoc z;!J9vBkiM+P}Gr+vX4+^Su%;UtkTIZqO4CTPAr^FIj<^lBaBvwoB$^kB8r*DGRI)L zIK7W3DNK~?Mc>P^h0YQ8Kww-K7l%qHp}?__>UfBKWyll~ikV-a(t^w^r9L#M6kNhEMX*U~zx_Gg#uQ>1W`tFl3Qh8r( z@4V8HKeX2w-|s(rxV2q-<(BQ+Z@J#krgT`{HRWdIx*C&aeqvLSbCmU=@(TEL@64G! zCrN(eq=%(B59dq#M_}XM@04aG8@h6x?_lw|_NpU&l?MKxs=Y4$_P0Z^Sjf1Yo`~D8tAeHNX4tMnv$!ELu zUQx!h4X#Pb=gU5A16DRJQLE%!%ACup``9~a)bs^n(WMbjCrTM4PgvxBo+dHyqX(QSilv735V?#rPy7t{XS&dI%@Q#U^~@__=bf%r?}=Jgo2E9B6&37b4z^D_ zoo@b^ZvL2Zf*%Dx3UOj}IWJ9f%F{F(6VDbhaK>L@$*E=7uHi!zp`1y5Q*nwgK41xp zwF`hHG*wJ_AhVN7Dx-0gpt0GxPQqX--z?vS%0*Z1z#{(~ReZYUak9|kP@XcN?xkd| z)6}2xrPQdDmxsOc7>aOBFV{WpF&Wb-+9kr$wz#G=0*2o^j~ItaZWJ~!mFGBhovztl zU3-b_74b|MxxC=%v9Kc)KI>j54y?@_Zj} zkccLJGZ5j_l3VXj5 zhy+tU3QNL_;LP_Rt7GQaig3~jSfOA%5JLz7*O}4bFruR>#!A{Te=?$DmwEj96*1oh z+RCpshQeJ&!0+BQcAIvQf>%YTt8Svt4Cb1ea=E62SvX$_f1>@8va3o_Gj2I?eP}I8 z*-yke7SrZ0Nf<1f*`+B>= zuu-O@I^=BB;}S)^eXe%4q8R(PRf$u|eXhuif! zXUf;%cD)X_>vgzYuk*2d9d6g_aJycI+x0r!uGisqz3wm#K(at9FbFIFRsidOjlgzb zCvZQoA2`hCAR1#Vjk4 zi6`TcP{0?Brh}OfSH?cex-4i$eSXnr30Co?jZMTg?AbF1ClAj%;jD1O$sMz%Oqd$+ z7tEO7@3YK|CwW|3XVumRq|89V$Sxip7|gV%dydce(_U@awAqF13EhRltSKnU zC;YyaiJ_`c<7BI7-loPMWgtV+}cBP0<% zzq&(yDiZQ6Wn*jR)O)e(3mB&RF1k2>(l;G&?O_KL?O;)I^Esa8GhhX^Ofu>cB?4!c zvREz^=?ZdRs*ZLZ2SY60Pr)qE3Jd}Z0P{?hP#~c|LV<(=3Hb6rC$LzlWrBn4b8+_M zil+A0J?v_G$h3!DZ4bNJ9(J`o>}q@1)%LKf?O|8j!>+c6U2PA$+8%bbJ?v_G*wyxw z_t#^r#MT@?#!8Uy{YIs$kJI^#8oH+{*z=X{XXySb4Du@s@*D4p{j(?*%tNq7uE_WD zo*v}gjBvY0pq-dUiLs^bZiVA0+uH#y(VAnm^Jk=fPsO3p?WiO?LEP2q{m$c|aQqOB z6-!+2T(#%%-ZB5gd-swma{5J5EpQ85O2xtBPN^F38t`8e{|)eO(1pio)1yvjzvucH z7>e_xKTrDewuq{*F3N&%Tx@Hx1a4oCMKaE`SsR50TT{Z(RCM>M?M!av=t`7#Gn+vo zrOQ#=zuDPRib3F3nu|(=mwIhIM>bnim@4C$B^rJpBD^dwn8NKcUJq3A^Wwa~tP9cIee-_6)B2%*8YQ^I&yzb9HsG z7~Iow`@>H^`jshDc75xqNABpn^wZsi&u!fJxkC4+FYUbJk*B`3Ys!?bJo@y*w|AVe z`J|?%lQy3*@t#MYf9mTqW_zz*=+_{c6fvP4T7$vnRJ!4PLloPq8{zEas|<+KpCyd+(Im zASzcuPjzb5+R=4uSEZ^w!Du`ctew)^UT^&|QB#P73pEKZ?(CtBSEZ~l^1R4JyZ*5& z+U7Y8r&M9YNUL4HakscX>fYi0iu+sc=iR?^|CQ5k(rhv(ne)uk!b1mGAC5I!{VPhGWl5fQIV@>?O9$=I8Ap|T(3^%h~)|Q*K z6jV2UZqu#|F%~hle#?)+`VrI-A4kyTFdEhF`mwAP%~0A(8q(@OD=-Kw0K~}YE0P%@ zD#P`PT3Cn*xLR3&Kjs00;DbsSgqCH2R$vfV0IUGk0ULqsz)s+PU_WpWcoBF5I1Jdr zARt+w6&M5-04soXz(!y@uoJi+*bf{8UIg9%4g-#)&M{WPHhLVDJ*hhTB%Pc?C+DaU z;zeYER$vfV0Puk^*1BIbZj|iCT3aw?E#fF^5l2~zILcbYQPv`kvKDcawTPpvMI2=< z;wWnoM_G$F%38!x)*_Cw7IBodh@-4^#sVY@v;u>`0$>HO4%i562X+GY1N(u4z>B~e zz+u1v+|&U|D&OwBY<1p0v?K7TBoZ=hXwbJ6;u^Pqi(ER|i5lcdEDQSu??@=4&2l1pZky!a6W0iDI+dWEz% z$oB^M1pfp0AD|`~;C~1IJJh5^Wp%s)&!G*1{88$k|(|m#L*qC3Y&Y zbIP$&t2U3=dBmQ~aS8v55X~+aHzD^M4~Vp#_5pHzfL!a#X~vC|6@nU0O6bvk?IUWL z-{d+;`-rOLE(cTn)jmtk&vxx|zeuSsBIvS~kPoW%4Li>Li|6*ae?k3^x?gnvg7S9G z?~nrtKx4VQM%;M=2=g>i7U?PNRr3F~(&{&iChd@vDH{rSkrz5!d z`|F6Fb={)BC~edyl;0fheV=|G!aw&>W|n?fzfYwvF27^_)CzV^1-rCdn!5MtpQQ9B zDSc}>R{s;RyNSgBuzLEx$(z!ju9SaS|C26eWz;Oue@9OInCNdhEgsQF%a~zRu!7Ue z5u;e{ugop?5+ukbGOiPm{F*gB#b84*=GdcboC1#7WMfr%50SZO@D>f;qV^H+&ET8K zvBeqJee#~&eY~AMVs9{Rboa@~7`K<_fwqlOcT(z3(q*qyGuqha%&`&Ud*f%D@fp5Ly1+LL&0#68jJ!-#uUxi{`5q~Z11y|_FA z#&TlLC+6Zx?n^7!=5jeTg4fYU^h*@Z40V6enVDY)|2nfyYWgNPa&|I{-QNcPwiEw7 za4dMrtakqm{BJgHqJ?6L<`Sc9)`8bK_yq6?4n7Nf7Pv*8Wt@kNCtat>_tuaz@0sdb z{5T%h|5Gqy7hiH)KJSOf?6s)4w~^U{!-e!-HI8#uD(qyiOTqRTZ?mB##qG6AXZz4z z-sk4r>y~q`i{ElOj?e}yi79a4HbR_Dq_ch|W%os7=mW8Eiyn+%}@X}(WehmC$PCIS{hvKiVWMk-6 z?6lj75qnUd)>rDv?Y8TOl=(cdpC|T%BJ*!IH#4LPVVRuz(`mED$Ti%idqOm~K6CVXf@LE0LCGeN1>$l}m z(%vYS(@tcY^df5+aO&JAqos2r(=E2cZ23uS)=ul$pzZfFqAxCwfqrTQJIBFfw(Zw1 zlo{quQzP6SeXDHHZZEE7Jcd+j{m|7*q3zU9=(!VVC z7}-2ivEAf_dA@>gI4RqwDSl$G8C7vNO7}SGcDV%aMaEdfb@1IdZr; za=6QHZ=Zf4dDjuUj@XOKdDSyE5W9ic&8`~#6Y|zn>>b43VXqDMz2NtPON%&CxH(ej z_kc71+%o?Je-`{%C;yA!FFLLM6ZoI(y}@MvG81-wvjkpp@M+-F!s!wYAX2(B zvrF-r^+H3{}i&sB}ve zLu^2(yRiO5ecMwJiBwJnl#Hl6&PHsSv9#I?NmzRrxI3MGUxLW-7QQ4j3vpTu)8 z`>JJR5F|T}+?>%DatUQABLk}FC${FWv=AXx83AuAmg73+m;_ zWBI2FF+#SWak-R3n8vDt%KJ~H>=z~Fi?$cFUNuF8m`xdJrkX(Nfr$BZ!Ubj|HkAqk5#rE3dxaDMOU#Inp`FuE^!R-Rh;|$;~E|t8S5xS4T1DRf?5f zDa6BtTtDDUWSKK+OvxW*PI}cVwmAWeZ=G1aohdC=!!jVFp&nx|fxHNitC=FgA&S*& zw+Uu!j~dUuadVimyfHNr@6hpKW83eH0cq2`CDk!zyR#zXf&8-ziKGg@=(vaMQ(-=DX9ijg$wg5-ST`b+GrHX{d6) zU)lGGW7?^LVnJD!hh$-h%9O_U{vIe3CCmBJGO5ZxByl`W;=s7dB%iTl_wKR7qmSr! zKm5knecD-}@05T3UVa{ZN!c@N?#;J!1gznhAk5- z5XC+eI*Vz|n%|bIZtV){ZatLhtFG=NcOqF;O}1cXYaAK1d>@P*OeIRC3#c^aqp9TT zs~%_%bhbpQBW?37H%u|R%8WJKnyYT>M7usYiTYCV^m2Wc=?hu)xu_n;Dq|)Xsf*W4 z^n0dtnErfsD3pkVsw2@tOs~u9m@)Qaf+^&W1ZypK1n(Htm_`hy5>_nU7>UOs0Spz_ z1w)~Ti3oN&ju|u~9E~C9sfV*cc=|zlsV7s3y3VB4kawF_Aei#RQl`fYdSU+5Scy1X zeXpk~YnZK_TBxJ8qupa-jWLj&V4@jfiY-cC(yJpzta}2jt-3jJQAn%H*C5Y}^sN|o z&h+r@Lc+KwAIb);aL8?V{q1!ya5Q&KuBI>P$tN14X>3QDo@gXi6E9hs=?m6d>GoJS z9*z3UXgJjvsgD^3?+3xsk}pz_ZE?F2>BEBRS^vi52Bo;MCvUW5M6#9tMT)CQ5rl|hDQm5BH~g-E0(m`O5J znhbA8JXKJ`YXlOel|*t}dPhBpq0x5jJu$llsQUAjHG zk*Z+2hT+u=8Q+N(h!L2W&(iInse1$M^+@JwCjG7H9XGz-NW`ihH@;Rl;SssvXeila z5AdYwQhmugetg?&7+;uTjBkE&(37yTGP;pys$E8Ro*La?TE;LKs#3#inC|fCp92;g zykrf`-*BMV-WmzIgK0BdgBX5nU~;$L+k{fIKj_bdJpnJqJ%f29MGd#1*PA}GG%M=X zb4*~LAE{hlf*I!-8^Nqsi0P^Y5I1H9XT36a?HEn-Os=2?shZ|*E9ZAYpHohAeg{0U z0Aj5%#BrAySRnT!KEvN`!F?Fz0*{Zw8G9sK5hEwjJyDVakiYrWP{F*0zVywpf77P^ z!B{YM+1R`?essTfU~HZ?DP0o%@M1=`lYCWM2QsisF1OlHQpr?HRh~V9{lxEgHWV?g z+R_n}-KWO%no-%KQj@B4y~#kQy-Cqij5g+Ls8#J{R0`jeb)vSEmZ}eezVwAE=uk>)McQGwm#EpPPqQTL}%Lc9^E9%3@ivg`KlA-`R$S zidxxhoE}-(d5kd-#VG6U9@#c)*fwif*M^T4XL>DJ@iNZ2w2ZUbH$xHGHG7kW9*L-Z zGk}IeG?K`%uHF9fwi&ASL@~x!SIZ~I8DC$d7+2$K1T$8!y*goUo8d@)N>FW@F<%@Z z^V9@;*JOm#;cPgZkILvG=2Y1-{lRnyk@OlyR-5JwEn@rjmMLS)XDQ(IBbLpM`OeUK z%v2&~y?bnVeU+g#LeZF4Hcc5^*)zKm@%N0a-!O}8nfAzLa+uGPZ<35G!-&YfvuS=- z!)d2Kj-BJGT%tA=G|YZ9bPW0S)>dVj`z*8Gk8v>_3wlO?71WZ~+9w9H;hc%Ah0f^f zOmeSrwSiE-FQn-)KC>ZQ&cl{Nd4>oyR*Ym*86%CHmuN9NcNFVmA?;p0s(w0k%t{)n zkgDS(>_r<|*uyilY2fHEDf~wD*T&D$d`x33JcsaAkh2rO4DD=<4V!{eT=D2G_Z;up z2K#FYj--BolK%|tYHgeLDeW`bm$bdw0qqakU$nn7wF~;7=a&btbna2S>jT-PKUR1{_Su zAM8f{U^nsyyJ61lM*d(o@&~(-KiG}@!EWRab|ZhV8~KCX$RF%R{$Mxq2fL9!*zI}? zaOAs=u@YPU;20}GAZm9^REzwt~Gc3>xPKd>J-2)qcq0UQP#$**Iq1g_W$ z-tdTPbES)$?JjPnb(?A3W?HwI)@>%^W?HwI)@`PBn`zx{*a_SZ><114F9L4>hXHY`xr+C=iud?LrISyf zo^h7&eO#M)&u5cPHRu!qUHpE(S#O3jN8lmElye}b|%gWv4n zw}IaV{z>9L1^y}UhrxG(?{x6bf`8V@^IaC&>7+l4fcao~Nohmcy=s~5)Aq6$&mqq_ zLOw0GUAq82!uKJ#t|spLGAp%CWwQ`24K`er5Oeqx@dZh6Kp zN%?mtWkmaHrTpINTfslr1XO-K07-cTgiMI>I>dPGUhpRHCI_DY4hMn_WS>4& z>;Rldhs6$-_A$&}X&-a>%XYA|n0tSHjz%pPha3!z}_%!fk;2XeG zz)ykKfxiK4E7pHoiEjhe!nTt84nW^9!mP5pJffZB42#UApKBjv7)F>&Wo(m!?bEKI z>DSX~hE;>9q210<3w{qcu1#bhw9hl6c2!;qgQ-2DX5V*hE~*$I(jcL#@F_wWj^D{F zbjrvqwDXQ=e{(SVDM!hDl&5@h+{6+KGfp6Tv23 z^1U5rZ{UArZa}%LPveVbBFp+7Gsg>4J!FIgYKw%j#6IeQCSM$cw%O)Eo6jOt_X! zI=o9q-j4L5HR7au`v)8>F|JGksujd5{s=<<2q0lWcZSv@L`d3Ht1~*tjX}(#KmC(< z3v^38K!|PvcEbSs|!UvliRC1!{N@Fw#gio z>toSse<+m?k-lP&{Qqvt4>_CrmOW+ZSylIsCQ22u^L5jy|-ufWwm-! zBTBaDv)2_piM*(-m+r1<>J+W@lxVHjiq<;B3@>ClTW|awt#ywc=KQI&))DPRkr=B-Y}!tyLdPx7Jat(VGriXC}jD>M;xLHi5B|;z)@=hVmk(9L_

~D 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 literal 0 HcmV?d00001 diff --git a/idrocap_wa/webroot/font/raleway-400-cyrillic-ext.woff2 b/idrocap_wa/webroot/font/raleway-400-cyrillic-ext.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..039269ecd6602a9917ec8a4bc6240b11da2730ca GIT binary patch literal 22516 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