diff --git a/assets/js/components/mock/service_create_form.html b/assets/js/components/mock/service_create_form.html
index 5041f1cb4..9ec105c3f 100644
--- a/assets/js/components/mock/service_create_form.html
+++ b/assets/js/components/mock/service_create_form.html
@@ -20,6 +20,12 @@
diff --git a/migrations/Version20240514071702.php b/migrations/Version20240514071702.php
index 7dc3e48c9..d6e6eef97 100644
--- a/migrations/Version20240514071702.php
+++ b/migrations/Version20240514071702.php
@@ -1,5 +1,21 @@
addSql('ALTER TABLE service DROP production_entities_enabled');
}
public function down(Schema $schema): void
{
- // this down() migration is auto-generated, please modify it to your needs
- $this->addSql('ALTER TABLE service ADD production_entities_enabled TINYINT(1) NOT NULL');
}
-}
+}
\ No newline at end of file
diff --git a/migrations/Version20241031120000.php b/migrations/Version20241031120000.php
new file mode 100644
index 000000000..830b1d4ce
--- /dev/null
+++ b/migrations/Version20241031120000.php
@@ -0,0 +1,33 @@
+connection->createSchemaManager()->listTableColumns('service');
+ $columnExists = false;
+ foreach ($columns as $column) {
+ if ($column->getName() === 'production_entities_enabled') {
+ $columnExists = true;
+ break;
+ }
+ }
+
+ if (!$columnExists) {
+ $this->addSql('ALTER TABLE service ADD production_entities_enabled TINYINT(1) NOT NULL DEFAULT 0');
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/CreateServiceCommand.php b/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/CreateServiceCommand.php
index ee0bc04b5..4861d8fec 100644
--- a/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/CreateServiceCommand.php
+++ b/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/CreateServiceCommand.php
@@ -58,6 +58,7 @@ class CreateServiceCommand implements Command
*/
private $institutionId;
+ private bool $productionEntitiesEnabled = false;
private bool $privacyQuestionsEnabled = true;
@@ -103,6 +104,11 @@ public function setName($name): void
$this->name = $name;
}
+ public function setProductionEntitiesEnabled(bool $enabled): void
+ {
+ $this->productionEntitiesEnabled = $enabled;
+ }
+
public function setPrivacyQuestionsEnabled(bool $privacyQuestionsEnabled): void
{
$this->privacyQuestionsEnabled = $privacyQuestionsEnabled;
@@ -160,6 +166,11 @@ public function getName()
return $this->name;
}
+ public function isProductionEntitiesEnabled(): bool
+ {
+ return $this->productionEntitiesEnabled;
+ }
+
public function isPrivacyQuestionsEnabled(): bool
{
return $this->privacyQuestionsEnabled;
diff --git a/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/EditServiceCommand.php b/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/EditServiceCommand.php
index 0044897a9..cab482b7d 100644
--- a/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/EditServiceCommand.php
+++ b/src/Surfnet/ServiceProviderDashboard/Application/Command/Service/EditServiceCommand.php
@@ -42,6 +42,7 @@ public function __construct(
#[SpDashboardAssert\UrnFormattedTeamName]
#[Assert\NotBlank]
private string $teamName,
+ private bool $productionEntitiesEnabled,
private bool $privacyQuestionsEnabled,
private bool $clientCredentialClientsEnabled,
#[Assert\NotBlank]
@@ -74,6 +75,11 @@ public function setName(string $name): void
$this->name = $name;
}
+ public function setProductionEntitiesEnabled(bool $enabled): void
+ {
+ $this->productionEntitiesEnabled = $enabled;
+ }
+
public function setPrivacyQuestionsEnabled(bool $privacyQuestionsEnabled): void
{
$this->privacyQuestionsEnabled = $privacyQuestionsEnabled;
@@ -189,6 +195,11 @@ public function isPrivacyQuestionsAnswered(): bool
return $this->privacyQuestionsAnswered;
}
+ public function isProductionEntitiesEnabled(): bool
+ {
+ return $this->productionEntitiesEnabled;
+ }
+
public function isPrivacyQuestionsEnabled(): bool
{
return $this->privacyQuestionsEnabled;
diff --git a/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/CreateServiceCommandHandler.php b/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/CreateServiceCommandHandler.php
index e6e369ea8..c8e15d047 100644
--- a/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/CreateServiceCommandHandler.php
+++ b/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/CreateServiceCommandHandler.php
@@ -61,6 +61,7 @@ public function handle(CreateServiceCommand $command): void
$service->setName($name);
$service->setGuid($command->getGuid());
$service->setTeamName($fullTeamName);
+ $service->setProductionEntitiesEnabled($command->isProductionEntitiesEnabled());
$service->setPrivacyQuestionsEnabled($command->isPrivacyQuestionsEnabled());
$service->setClientCredentialClientsEnabled($command->isClientCredentialClientsEnabled());
$service->setServiceType($command->getServiceType());
diff --git a/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/EditServiceCommandHandler.php b/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/EditServiceCommandHandler.php
index 1452dff37..83f829d12 100644
--- a/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/EditServiceCommandHandler.php
+++ b/src/Surfnet/ServiceProviderDashboard/Application/CommandHandler/Service/EditServiceCommandHandler.php
@@ -46,6 +46,7 @@ public function handle(EditServiceCommand $command): void
$service->setName($command->getName());
$service->setGuid($command->getGuid());
+ $service->setProductionEntitiesEnabled($command->isProductionEntitiesEnabled());
$service->setPrivacyQuestionsEnabled($command->isPrivacyQuestionsEnabled());
$service->setClientCredentialClientsEnabled($command->isClientCredentialClientsEnabled());
diff --git a/src/Surfnet/ServiceProviderDashboard/Application/ViewObject/Service.php b/src/Surfnet/ServiceProviderDashboard/Application/ViewObject/Service.php
index 41367f54a..5443eda8b 100644
--- a/src/Surfnet/ServiceProviderDashboard/Application/ViewObject/Service.php
+++ b/src/Surfnet/ServiceProviderDashboard/Application/ViewObject/Service.php
@@ -28,6 +28,7 @@ public function __construct(
private readonly bool $privacyQuestionsEnabled,
private readonly EntityList $entityList,
private readonly RouterInterface $router,
+ private readonly bool $productionEntitiesEnabled = false,
) {
}
@@ -39,6 +40,7 @@ public static function fromService(DomainService $service, EntityList $entityLis
$service->isPrivacyQuestionsEnabled(),
$entityList,
$router,
+ $service->isProductionEntitiesEnabled()
);
}
@@ -71,4 +73,9 @@ public function hasTestEntities() : bool
{
return $this->getEntityList()->hasTestEntities();
}
+
+ public function isProductionEntitiesEnabled(): bool
+ {
+ return $this->productionEntitiesEnabled || $this->hasTestEntities();
+ }
}
diff --git a/src/Surfnet/ServiceProviderDashboard/Domain/Entity/Service.php b/src/Surfnet/ServiceProviderDashboard/Domain/Entity/Service.php
index 3b677c75f..c708f0da6 100644
--- a/src/Surfnet/ServiceProviderDashboard/Domain/Entity/Service.php
+++ b/src/Surfnet/ServiceProviderDashboard/Domain/Entity/Service.php
@@ -22,10 +22,13 @@
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
+use Surfnet\ServiceProviderDashboard\Domain\Entity\PrivacyQuestions;
use Gedmo\Mapping\Annotation as Gedmo;
use Surfnet\ServiceProviderDashboard\Infrastructure\DashboardBundle\Repository\ServiceRepository;
/**
+ * @package Surfnet\ServiceProviderDashboard\Entity
+ *
* @SuppressWarnings(PHPMD.TooManyFields)
* @SuppressWarnings(PHPMD.UnusedPrivateField) - the createdAt field is not used in code, but used by TPM's to check for
* the creation date of a service.
@@ -89,6 +92,9 @@ class Service
#[ORM\Column(length: 255)]
private $teamName;
+ #[ORM\Column(type: 'boolean')]
+ private bool $productionEntitiesEnabled = false;
+
#[ORM\Column(type: 'boolean')]
private bool $privacyQuestionsEnabled = true;
@@ -192,6 +198,11 @@ public function setName($name): void
$this->name = $name;
}
+ public function setProductionEntitiesEnabled(bool $enabled): void
+ {
+ $this->productionEntitiesEnabled = $enabled;
+ }
+
public function setPrivacyQuestionsEnabled(bool $privacyQuestionsEnabled): void
{
$this->privacyQuestionsEnabled = $privacyQuestionsEnabled;
@@ -218,6 +229,11 @@ public function setPrivacyQuestions(PrivacyQuestions $privacyQuestions): void
$this->privacyQuestions = $privacyQuestions;
}
+ public function isProductionEntitiesEnabled(): bool
+ {
+ return $this->productionEntitiesEnabled;
+ }
+
public function isPrivacyQuestionsEnabled(): bool
{
return $this->privacyQuestionsEnabled;
diff --git a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/EntityCreateController.php b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/EntityCreateController.php
index 328067429..0e25cb0c3 100644
--- a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/EntityCreateController.php
+++ b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/EntityCreateController.php
@@ -82,6 +82,7 @@ public function type(
$entityList = $this->entityService
->getEntityListForService($service)
->sortEntitiesByEnvironment();
+ $isProductionEnabled = $entityList->hasTestEntities() || $service->isProductionEntitiesEnabled();
$form = $this->createForm(CreateNewEntityType::class, $formId);
$form->handleRequest($request);
@@ -129,6 +130,7 @@ public function type(
'environment' => $targetEnvironment,
'inputId' => $inputId,
'protocols' => $choices,
+ 'productionEnabled' => $isProductionEnabled,
'entities' => $entityList->getEntities(),
'manageId' => $formId,
]
@@ -155,7 +157,9 @@ public function create(Request $request, $serviceId, $targetEnvironment, $type):
$hasTestEntities = $this->entityService
->getEntityListForService($service)->hasTestEntities();
- if (!$hasTestEntities && $targetEnvironment !== Constants::ENVIRONMENT_TEST) {
+ if (!$service->isProductionEntitiesEnabled() && !$hasTestEntities
+ && $targetEnvironment !== Constants::ENVIRONMENT_TEST
+ ) {
throw $this->createAccessDeniedException(
'You do not have access to create entities without publishing to the test environment first'
);
diff --git a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/ServiceController.php b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/ServiceController.php
index 12377f38f..ffa4eda50 100644
--- a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/ServiceController.php
+++ b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Controller/ServiceController.php
@@ -162,6 +162,7 @@ public function edit(Request $request, int $serviceId): RedirectResponse|Respons
$service->getGuid(),
$service->getName(),
$service->getTeamName(),
+ $service->isProductionEntitiesEnabled(),
$service->isPrivacyQuestionsEnabled(),
$service->isClientCredentialClientsEnabled(),
$service->getServiceType(),
diff --git a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/DataFixtures/ORM/WebTestFixtures.php b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/DataFixtures/ORM/WebTestFixtures.php
index 0adf01866..a24ac8e4e 100644
--- a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/DataFixtures/ORM/WebTestFixtures.php
+++ b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/DataFixtures/ORM/WebTestFixtures.php
@@ -34,9 +34,11 @@ class WebTestFixtures extends Fixture
public function load(ObjectManager $manager): void
{
$service = $this->createService('SURFnet', self::TEAMNAME_SURF);
+ $service->setProductionEntitiesEnabled(false);
$manager->persist($service);
$service = $this->createService('Ibuildings B.V.', self::TEAMNAME_IBUILDINGS);
+ $service->setProductionEntitiesEnabled(true);
$service->setPrivacyQuestionsEnabled(true);
$service->setClientCredentialClientsEnabled(true);
$manager->persist($service);
diff --git a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/CreateServiceType.php b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/CreateServiceType.php
index d58233d4f..731426401 100644
--- a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/CreateServiceType.php
+++ b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/CreateServiceType.php
@@ -73,6 +73,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'attr' => ['class' => 'institution-id-container'],
]
)
+ ->add(
+ 'productionEntitiesEnabled',
+ CheckboxType::class,
+ [
+ 'required' => false,
+ ]
+ )
->add(
'privacyQuestionsEnabled',
CheckboxType::class,
diff --git a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/EditServiceType.php b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/EditServiceType.php
index ac03bbcc8..3763c3df3 100644
--- a/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/EditServiceType.php
+++ b/src/Surfnet/ServiceProviderDashboard/Infrastructure/DashboardBundle/Form/Service/EditServiceType.php
@@ -69,6 +69,13 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
'attr' => ['class' => 'institution-id-container'],
]
)
+ ->add(
+ 'productionEntitiesEnabled',
+ CheckboxType::class,
+ [
+ 'required' => false,
+ ]
+ )
->add(
'privacyQuestionsEnabled',
CheckboxType::class,
diff --git a/templates/EntityModal/addEntityModal.html.twig b/templates/EntityModal/addEntityModal.html.twig
index 5a8ea2f39..bf1433da4 100644
--- a/templates/EntityModal/addEntityModal.html.twig
+++ b/templates/EntityModal/addEntityModal.html.twig
@@ -7,7 +7,7 @@
{% set fieldName = manageId ~ '_environment' %}
{% set fieldId = manageId ~ '_prod' %}
-
+
diff --git a/templates/Service/overview.html.twig b/templates/Service/overview.html.twig
index c26a3b401..058ec0ebd 100644
--- a/templates/Service/overview.html.twig
+++ b/templates/Service/overview.html.twig
@@ -21,7 +21,9 @@
{% set testId = "add-for-test-" ~ shortName %}
{% set productionId = "add-for-production-" ~ shortName %}
-
+ {% if service.isProductionEntitiesEnabled %}
+
+ {% endif %}
-
{{ render(controller('Surfnet\\ServiceProviderDashboard\\Infrastructure\\DashboardBundle\\Controller\\EntityCreateController::type', {serviceId: service.id, targetEnvironment: "production", inputId: productionId })) }}
+ {% if service.isProductionEntitiesEnabled %}
+
{{ render(controller('Surfnet\\ServiceProviderDashboard\\Infrastructure\\DashboardBundle\\Controller\\EntityCreateController::type', {serviceId: service.id, targetEnvironment: "production", inputId: productionId })) }}
+ {% endif %}
{{ render(controller('Surfnet\\ServiceProviderDashboard\\Infrastructure\\DashboardBundle\\Controller\\EntityCreateController::type', {serviceId: service.id, targetEnvironment: "test", inputId: testId})) }}
diff --git a/tests/integration/Application/CommandHandler/Service/CreateServiceCommandHandlerTest.php b/tests/integration/Application/CommandHandler/Service/CreateServiceCommandHandlerTest.php
index 1ad84e501..46f0cc80f 100644
--- a/tests/integration/Application/CommandHandler/Service/CreateServiceCommandHandlerTest.php
+++ b/tests/integration/Application/CommandHandler/Service/CreateServiceCommandHandlerTest.php
@@ -80,6 +80,7 @@ public function test_it_can_process_a_create_service_command()
$service->setTeamName('team-foobar');
$service->setGuid('30dd879c-ee2f-11db-8314-0800200c9a66');
$service->setPrivacyQuestionsEnabled(true);
+ $service->setProductionEntitiesEnabled(true);
$service->setServiceType('institution');
$service->setIntakeStatus('yes');
@@ -94,6 +95,7 @@ public function test_it_can_process_a_create_service_command()
$command->setTeamManagerEmail('tiffany@aching.do');
$command->setGuid($service->getGuid());
$command->setPrivacyQuestionsEnabled($service->isPrivacyQuestionsEnabled());
+ $command->setProductionEntitiesEnabled($service->isProductionEntitiesEnabled());
$command->setOrganizationNameEn($service->getOrganizationNameEn());
$command->setOrganizationNameNl($service->getOrganizationNameNl());
$command->setServiceType($service->getServiceType());
@@ -126,6 +128,7 @@ public function test_it_rejects_non_unique_create_service_command()
$command->setTeamName('team-foobar');
$command->setTeamManagerEmail('tiffany@aching.do');
$command->setGuid('30dd879c-ee2f-11db-8314-0800200c9a66');
+ $command->setProductionEntitiesEnabled(true);
$command->setPrivacyQuestionsEnabled(false);
$command->setServiceType('institution');
diff --git a/tests/integration/Application/CommandHandler/Service/EditServiceCommandHandlerTest.php b/tests/integration/Application/CommandHandler/Service/EditServiceCommandHandlerTest.php
index 7413d35ac..5a587cc95 100644
--- a/tests/integration/Application/CommandHandler/Service/EditServiceCommandHandlerTest.php
+++ b/tests/integration/Application/CommandHandler/Service/EditServiceCommandHandlerTest.php
@@ -53,6 +53,7 @@ public function test_it_can_process_an_edit_service_command()
'Foobar',
'team-foobar',
false,
+ false,
true,
'institution',
'not-applicable',
@@ -67,6 +68,7 @@ public function test_it_can_process_an_edit_service_command()
$command->setTeamName('team-foobar');
$command->setGuid('30dd879c-ee2f-11db-8314-0800200c9a66');
$command->setPrivacyQuestionsEnabled(false);
+ $command->setProductionEntitiesEnabled(false);
$command->setPrivacyQuestionsAnswered(true);
$command->setServiceType('institution');
@@ -84,6 +86,7 @@ public function test_it_can_process_an_edit_service_command()
$this->assertEquals('Foobar', $arg->getName());
$this->assertEquals('team-foobar', $arg->getTeamName());
$this->assertEquals('30dd879c-ee2f-11db-8314-0800200c9a66', $arg->getGuid());
+ $this->assertEquals(false, $arg->isPrivacyQuestionsEnabled());
$this->assertEquals('no', $arg->getContractSigned());
$this->assertEquals('no', $arg->getSurfconextRepresentativeApproved());
$this->assertEquals('not-applicable', $arg->getIntakeStatus());
@@ -113,6 +116,7 @@ public function test_it_rejects_non_existing_service()
'Foobar',
'team-foobar',
false,
+ false,
true,
'institution',
'not-applicable',
@@ -143,6 +147,7 @@ public function test_it_rejects_non_unique_edit_service_command()
'team-foobar',
false,
false,
+ false,
'institution',
'not-applicable',
'no',