From 45c8ebd00280d8b4a2d1209db4764a77cca59f43 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Tue, 11 Jun 2024 11:35:58 +0200 Subject: [PATCH 01/20] Always select first integration type by default --- resources/ts/Pages/Integrations/New.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/resources/ts/Pages/Integrations/New.tsx b/resources/ts/Pages/Integrations/New.tsx index 37cb95941..a1f700e1b 100644 --- a/resources/ts/Pages/Integrations/New.tsx +++ b/resources/ts/Pages/Integrations/New.tsx @@ -45,11 +45,13 @@ const New = ({ subscriptions }: Props) => { ) .map((subscription) => subscription.id); + const integrationTypesInfo = useIntegrationTypesInfo(); + const url = new URL(document.location.href); const activeTypeFromUrl = url.searchParams.get("type"); const activeType = isIntegrationType(activeTypeFromUrl) ? activeTypeFromUrl - : IntegrationType.EntryApi; + : integrationTypesInfo[0].type; const initialFormValues = { integrationType: activeType, @@ -95,7 +97,6 @@ const New = ({ subscriptions }: Props) => { [IntegrationType.SearchApi, IntegrationType.Widgets] as IntegrationType[] ).includes(data.integrationType); - const integrationTypesInfo = useIntegrationTypesInfo(); const pricingPlans = useGetPricingPlans(data.integrationType, subscriptions); return ( From 3343c2b4537e411ec9f0bf4fc37d546899141380 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Tue, 25 Jun 2024 12:25:31 +0200 Subject: [PATCH 02/20] Add safe access for integration type --- resources/ts/Pages/Integrations/New.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ts/Pages/Integrations/New.tsx b/resources/ts/Pages/Integrations/New.tsx index a1f700e1b..3bde64454 100644 --- a/resources/ts/Pages/Integrations/New.tsx +++ b/resources/ts/Pages/Integrations/New.tsx @@ -51,7 +51,7 @@ const New = ({ subscriptions }: Props) => { const activeTypeFromUrl = url.searchParams.get("type"); const activeType = isIntegrationType(activeTypeFromUrl) ? activeTypeFromUrl - : integrationTypesInfo[0].type; + : integrationTypesInfo?.[0].type ?? IntegrationType.EntryApi; const initialFormValues = { integrationType: activeType, From c755a123b4b85e4032b7e77d7dc991724d32f4f5 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 4 Jul 2024 13:52:43 +0200 Subject: [PATCH 03/20] Render keycloakClients --- app/Domain/Integrations/Controllers/IntegrationController.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index 72cd433ac..d146c3a51 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -40,6 +40,7 @@ use App\Domain\Subscriptions\Repositories\SubscriptionRepository; use App\Domain\KeyVisibilityUpgrades\Repositories\KeyVisibilityUpgradeRepository; use App\Http\Controllers\Controller; +use App\Keycloak\Repositories\KeycloakClientRepository; use App\ProjectAanvraag\ProjectAanvraagUrl; use App\Router\TranslatedRoute; use App\UiTiDv1\Repositories\UiTiDv1ConsumerRepository; @@ -69,6 +70,7 @@ public function __construct( private readonly CouponRepository $couponRepository, private readonly Auth0ClientRepository $auth0ClientRepository, private readonly UiTiDv1ConsumerRepository $uitidV1ConsumerRepository, + private readonly KeycloakClientRepository $keycloakClientRepository, private readonly KeyVisibilityUpgradeRepository $keyVisibilityUpgradeRepository, private readonly CurrentUser $currentUser ) { @@ -87,12 +89,14 @@ public function index(Request $request): Response $auth0Clients = $this->auth0ClientRepository->getByIntegrationIds($integrationIds); $uitidV1Consumers = $this->uitidV1ConsumerRepository->getByIntegrationIds($integrationIds); + $keycloakClients = $this->keycloakClientRepository->getByIntegrationIds($integrationIds); return Inertia::render('Integrations/Index', [ 'integrations' => $integrationsData->collection->map(fn (Integration $integration) => $integration->toArray()), 'credentials' => [ 'auth0' => $auth0Clients, 'uitidV1' => $uitidV1Consumers, + 'keycloak' => $keycloakClients, ], 'paginationInfo' => $integrationsData->paginationInfo, ]); From fb64b13ca756d051bbf4094205569c1fccb4bee7 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 4 Jul 2024 13:54:02 +0200 Subject: [PATCH 04/20] Add config keycloak --- app/Http/Middleware/HandleInertiaRequests.php | 1 + config/keycloak.php | 2 +- resources/ts/Components/IntegrationCard.tsx | 3 +++ .../Components/Integrations/Detail/CredentialsAuthClients.tsx | 4 ++++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 7050fe92a..188aa5715 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -30,6 +30,7 @@ public function share(Request $request): array 'sentryDsn' => config('sentry.dsn'), 'sentryEnabled' => config('app.sentry.enabled'), 'uitpasEnabled' => config('uitpas.enabled'), + 'keycloakEnabled' => config('keycloak.enabled'), ], 'widgetConfig' => [ 'url' => config('uitidwidget.url'), diff --git a/config/keycloak.php b/config/keycloak.php index f23ad83f5..1980acebc 100644 --- a/config/keycloak.php +++ b/config/keycloak.php @@ -5,7 +5,7 @@ use Auth0\SDK\Configuration\SdkConfiguration; return [ - + 'enabled' => env('KEYCLOAK_ENABLED', false), 'loginEnabled' => env('KEYCLOAK_LOGIN_ENABLED', false), 'creationEnabled' => env('KEYCLOAK_CREATION_ENABLED', false), 'login' => [ diff --git a/resources/ts/Components/IntegrationCard.tsx b/resources/ts/Components/IntegrationCard.tsx index 38205cf80..35aab9af3 100644 --- a/resources/ts/Components/IntegrationCard.tsx +++ b/resources/ts/Components/IntegrationCard.tsx @@ -22,6 +22,7 @@ import { Alert } from "./Alert"; import { classNames } from "../utils/classNames"; import { usePolling } from "../hooks/usePolling"; import { ButtonSecondary } from "./ButtonSecondary"; +import { usePageProps } from "../hooks/usePageProps"; type Props = Integration & Credentials & { @@ -71,6 +72,8 @@ export const IntegrationCard = ({ onEdit, }: Props) => { const { t } = useTranslation(); + const { config } = usePageProps(); + const keycloakEnabled = config.keycloakEnabled; const integrationTypesInfo = useIntegrationTypesInfo(); diff --git a/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx b/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx index 1fd4323d1..508bb04c3 100644 --- a/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx +++ b/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx @@ -12,6 +12,7 @@ import { KeyVisibility } from "../../../types/KeyVisibility"; import { router } from "@inertiajs/react"; import { Link } from "../../Link"; import { Alert } from "../../Alert"; +import { usePageProps } from "../../../hooks/usePageProps"; type Props = Pick< Integration, @@ -36,6 +37,9 @@ export const CredentialsAuthClients = ({ keyVisibilityUpgrade, }: Props) => { const { t } = useTranslation(); + const { config } = usePageProps(); + const keycloakEnabled = config.keycloakEnabled; + const isKeyVisibilityV1 = keyVisibility === KeyVisibility.v1; const auth0TestClientWithLabels = [ From 89f8a50d75958a6f0975b61a7caaccc19cbb0027 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 4 Jul 2024 13:54:52 +0200 Subject: [PATCH 05/20] Create type KeycloakEnvironment --- resources/ts/types/KeycloakEnvironment.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 resources/ts/types/KeycloakEnvironment.ts diff --git a/resources/ts/types/KeycloakEnvironment.ts b/resources/ts/types/KeycloakEnvironment.ts new file mode 100644 index 000000000..3190a8878 --- /dev/null +++ b/resources/ts/types/KeycloakEnvironment.ts @@ -0,0 +1,9 @@ +import type { Values } from "./Values"; + +export const KeycloakEnvironment = { + Acceptance: "acc", + Testing: "test", + Production: "prod", +} as const; + +export type KeycloakEnvironment = Values; From 29ee8ad2ff60427db993ff1fdb0d5c03b567e237 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 4 Jul 2024 13:55:18 +0200 Subject: [PATCH 06/20] Create type KeycloakClient --- resources/ts/types/Credentials.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/resources/ts/types/Credentials.ts b/resources/ts/types/Credentials.ts index 05df6c8a1..1483b3d49 100644 --- a/resources/ts/types/Credentials.ts +++ b/resources/ts/types/Credentials.ts @@ -1,4 +1,5 @@ import type { Auth0Tenant } from "./Auth0Tenant"; +import type { KeycloakEnvironment } from "./KeycloakEnvironment"; import type { UiTiDv1Environment } from "./UiTiDv1Environment"; export type LegacyAuthConsumer = { @@ -17,7 +18,15 @@ export type AuthClient = { integrationId: string; tenant: Auth0Tenant; }; +export type KeycloakClient = { + clientId: string; + clientSecret: string; + environment: KeycloakEnvironment; + id: string; + integrationId: string; +}; export type Credentials = { auth0: AuthClient[]; uitidV1: LegacyAuthConsumer[]; + keycloak: KeycloakClient[]; }; From 0e7d2a123b3b1d2017a91960a4fb9e5753fe9e89 Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 4 Jul 2024 13:56:41 +0200 Subject: [PATCH 07/20] Implement keycloak client --- resources/ts/Components/IntegrationCard.tsx | 75 +++++++++++++------ .../Integrations/Detail/Credentials.tsx | 27 +++++-- .../Detail/CredentialsAuthClients.tsx | 68 +++++++++++------ resources/ts/Pages/Integrations/Index.tsx | 13 +++- resources/ts/types/Integration.ts | 7 +- 5 files changed, 138 insertions(+), 52 deletions(-) diff --git a/resources/ts/Components/IntegrationCard.tsx b/resources/ts/Components/IntegrationCard.tsx index 35aab9af3..19057da6a 100644 --- a/resources/ts/Components/IntegrationCard.tsx +++ b/resources/ts/Components/IntegrationCard.tsx @@ -68,6 +68,8 @@ export const IntegrationCard = ({ legacyProdConsumer, testClient, prodClient, + keycloakTestClient, + keycloakProdClient, keyVisibility, onEdit, }: Props) => { @@ -77,32 +79,59 @@ export const IntegrationCard = ({ const integrationTypesInfo = useIntegrationTypesInfo(); - const auth0TestClientWithLabels = [ - { - label: "details.credentials.client_id", - value: testClient?.clientId, - }, - { - label: "details.credentials.client_secret", - value: testClient?.clientSecret, - }, - ]; + const testClientWithLabels = keycloakEnabled + ? [ + { + label: "details.credentials.client_id", + value: keycloakTestClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: keycloakTestClient?.clientSecret, + }, + ] + : [ + { + label: "details.credentials.client_id", + value: testClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: testClient?.clientSecret, + }, + ]; - const auth0ProdClientWithLabels = [ - { - label: "details.credentials.client_id", - value: prodClient?.clientId, - }, - { - label: "details.credentials.client_secret", - value: prodClient?.clientSecret, - }, - ]; + const prodClientWithLabels = keycloakEnabled + ? [ + { + label: "details.credentials.client_id", + value: keycloakProdClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: keycloakProdClient?.clientSecret, + }, + ] + : [ + { + label: "details.credentials.client_id", + value: prodClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: prodClient?.clientSecret, + }, + ]; const clientSecretLabel = t("details.credentials.client_secret"); const hasAnyCredentials = Boolean( - legacyTestConsumer || legacyProdConsumer || testClient || prodClient + legacyTestConsumer || + legacyProdConsumer || + testClient || + prodClient || + keycloakProdClient || + keycloakProdClient ); usePolling(!hasAnyCredentials, { only: ["credentials"] }); @@ -123,7 +152,7 @@ export const IntegrationCard = ({
- {auth0TestClientWithLabels.map((client) => ( + {testClientWithLabels.map((client) => (
- {auth0ProdClientWithLabels.map((client) => ( + {prodClientWithLabels.map((client) => (
{ const { t } = useTranslation(); @@ -47,15 +54,25 @@ export const Credentials = ({ const credentials = useMemo( () => ({ legacyTestConsumer: legacyAuthConsumers.find( - (consumer) => consumer.environment === "test" + (consumer) => consumer.environment === UiTiDv1Environment.Testing ), legacyProdConsumer: legacyAuthConsumers.find( - (consumer) => consumer.environment === "prod" + (consumer) => consumer.environment === UiTiDv1Environment.Production + ), + testClient: authClients.find( + (client) => client.tenant === Auth0Tenant.Testing + ), + prodClient: authClients.find( + (client) => client.tenant === Auth0Tenant.Production + ), + keycloakTestClient: keycloakClients.find( + (client) => client.environment === KeycloakEnvironment.Testing + ), + keycloakProdClient: keycloakClients.find( + (client) => client.environment === KeycloakEnvironment.Production ), - testClient: authClients.find((client) => client.tenant === "test"), - prodClient: authClients.find((client) => client.tenant === "prod"), }), - [legacyAuthConsumers, authClients] + [legacyAuthConsumers, authClients, keycloakClients] ); if (!hasAnyCredentials) { diff --git a/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx b/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx index 508bb04c3..00908b4b4 100644 --- a/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx +++ b/resources/ts/Components/Integrations/Detail/CredentialsAuthClients.tsx @@ -28,6 +28,8 @@ type Props = Pick< export const CredentialsAuthClients = ({ testClient, prodClient, + keycloakTestClient, + keycloakProdClient, id, status, email, @@ -42,27 +44,49 @@ export const CredentialsAuthClients = ({ const isKeyVisibilityV1 = keyVisibility === KeyVisibility.v1; - const auth0TestClientWithLabels = [ - { - label: "details.credentials.client_id", - value: testClient?.clientId, - }, - { - label: "details.credentials.client_secret", - value: testClient?.clientSecret, - }, - ]; + const testClientWithLabels = keycloakEnabled + ? [ + { + label: "details.credentials.client_id", + value: keycloakTestClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: keycloakTestClient?.clientSecret, + }, + ] + : [ + { + label: "details.credentials.client_id", + value: testClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: testClient?.clientSecret, + }, + ]; - const auth0ProdClientWithLabels = [ - { - label: "details.credentials.client_id", - value: prodClient?.clientId, - }, - { - label: "details.credentials.client_secret", - value: prodClient?.clientSecret, - }, - ]; + const prodClientWithLabels = keycloakEnabled + ? [ + { + label: "details.credentials.client_id", + value: keycloakProdClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: keycloakProdClient?.clientSecret, + }, + ] + : [ + { + label: "details.credentials.client_id", + value: prodClient?.clientId, + }, + { + label: "details.credentials.client_secret", + value: prodClient?.clientSecret, + }, + ]; const clientSecretLabel = t("details.credentials.client_secret"); @@ -108,7 +132,7 @@ export const CredentialsAuthClients = ({ {t("details.credentials.test")} - {auth0TestClientWithLabels.map((client) => ( + {testClientWithLabels.map((client) => (
{status === IntegrationStatus.Active && (
- {auth0ProdClientWithLabels.map((client) => ( + {prodClientWithLabels.map((client) => (
{ client.integrationId === integration.id && client.environment === UiTiDv1Environment.Production ), + keycloakTestClient: credentials.keycloak.find( + (client) => + client.integrationId === integration.id && + client.environment === KeycloakEnvironment.Testing + ), + keycloakProdClient: credentials.keycloak.find( + (client) => + client.integrationId === integration.id && + client.environment === KeycloakEnvironment.Testing + ), }, })), - [integrations, credentials.auth0, credentials.uitidV1] + [integrations, credentials.auth0, credentials.uitidV1, credentials.keycloak] ); const handleDeleteIntegration = () => { diff --git a/resources/ts/types/Integration.ts b/resources/ts/types/Integration.ts index fffd9da49..1ad7b0a0d 100644 --- a/resources/ts/types/Integration.ts +++ b/resources/ts/types/Integration.ts @@ -5,7 +5,11 @@ import type { Contact } from "./Contact"; import type { Organization } from "./Organization"; import type { Subscription } from "./Subscription"; import type { IntegrationUrl } from "./IntegrationUrl"; -import type { AuthClient, LegacyAuthConsumer } from "./Credentials"; +import type { + AuthClient, + KeycloakClient, + LegacyAuthConsumer, +} from "./Credentials"; import type { KeyVisibility } from "./KeyVisibility"; export type Coupon = { @@ -36,6 +40,7 @@ export type Integration = { urls: IntegrationUrl[]; authClients: AuthClient[]; legacyAuthConsumers: LegacyAuthConsumer[]; + keycloakClients: KeycloakClient[]; keyVisibility: KeyVisibility; keyVisibilityUpgrade: KeyVisibilityUpgrade | null; }; From b3f0a541a805d89d5679cb032051c92b417263cf Mon Sep 17 00:00:00 2001 From: vhande Date: Thu, 4 Jul 2024 14:30:29 +0200 Subject: [PATCH 08/20] Eeplace asterisk with dot --- resources/ts/Components/CopyText.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ts/Components/CopyText.tsx b/resources/ts/Components/CopyText.tsx index d7a456f71..47f4e487b 100644 --- a/resources/ts/Components/CopyText.tsx +++ b/resources/ts/Components/CopyText.tsx @@ -30,7 +30,7 @@ export const CopyText = ({ text, isSecret }: Props) => { className="font-mono whitespace-pre text-ellipsis overflow-hidden text-sm text-publiq-orange max-md:max-w-[15rem] max-xl:max-w-[30rem]" ref={codeFieldRef} > - {!isSecret || isSecretVisible ? text : "*".repeat(text?.length ?? 36)} + {!isSecret || isSecretVisible ? text : "•".repeat(text?.length ?? 36)} Date: Tue, 9 Jul 2024 11:59:27 +0200 Subject: [PATCH 09/20] BUGFIX Organizers gives 409 in admin panel --- app/Domain/Integrations/Models/IntegrationModel.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Domain/Integrations/Models/IntegrationModel.php b/app/Domain/Integrations/Models/IntegrationModel.php index f9305ab58..84fad0712 100644 --- a/app/Domain/Integrations/Models/IntegrationModel.php +++ b/app/Domain/Integrations/Models/IntegrationModel.php @@ -67,6 +67,7 @@ final class IntegrationModel extends UuidModel protected $attributes = [ 'status' => IntegrationStatus::Draft, 'partner_status' => IntegrationPartnerStatus::THIRD_PARTY, + 'type' => IntegrationType::UiTPAS->value, ]; public function canBeActivated(): bool From 517cc008b19075fbd8e51d5af27b94c54ef0dca8 Mon Sep 17 00:00:00 2001 From: Koen Eelen Date: Tue, 9 Jul 2024 14:08:01 +0200 Subject: [PATCH 10/20] A better fix --- app/Domain/Integrations/Models/IntegrationModel.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Domain/Integrations/Models/IntegrationModel.php b/app/Domain/Integrations/Models/IntegrationModel.php index 84fad0712..bb4486f33 100644 --- a/app/Domain/Integrations/Models/IntegrationModel.php +++ b/app/Domain/Integrations/Models/IntegrationModel.php @@ -67,7 +67,6 @@ final class IntegrationModel extends UuidModel protected $attributes = [ 'status' => IntegrationStatus::Draft, 'partner_status' => IntegrationPartnerStatus::THIRD_PARTY, - 'type' => IntegrationType::UiTPAS->value, ]; public function canBeActivated(): bool @@ -98,7 +97,7 @@ public function isWidgets(): bool public function isUiTPAS(): bool { - return $this->type === IntegrationType::UiTPAS->value; + return $this->type === IntegrationType::UiTPAS->value || $this->type === null; } protected static function booted(): void From 7d4838f1808b786bc82197f38cab14438dcc6f00 Mon Sep 17 00:00:00 2001 From: Koen Eelen Date: Tue, 9 Jul 2024 15:19:50 +0200 Subject: [PATCH 11/20] For uitpas integration always use key visibility v2 && git push --- .../Repositories/EloquentIntegrationRepository.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/Domain/Integrations/Repositories/EloquentIntegrationRepository.php b/app/Domain/Integrations/Repositories/EloquentIntegrationRepository.php index e560d7a6e..592e99f49 100644 --- a/app/Domain/Integrations/Repositories/EloquentIntegrationRepository.php +++ b/app/Domain/Integrations/Repositories/EloquentIntegrationRepository.php @@ -7,6 +7,8 @@ use App\Domain\Contacts\Models\ContactModel; use App\Domain\Coupons\Models\CouponModel; use App\Domain\Integrations\Integration; +use App\Domain\Integrations\IntegrationType; +use App\Domain\Integrations\KeyVisibility; use App\Domain\Integrations\Models\IntegrationModel; use App\Pagination\PaginatedCollection; use App\Pagination\PaginationInfo; @@ -150,6 +152,11 @@ private function saveTransaction(Integration $integration, ?string $couponCode): $this->useCouponOnIntegration($integration->id, $couponCode); } + // https://jira.publiq.be/browse/PPF-555 + if($integration->type === IntegrationType::UiTPAS) { + $integration = $integration->withKeyVisibility(KeyVisibility::v2); + } + IntegrationModel::query()->create([ 'id' => $integration->id->toString(), 'type' => $integration->type, From f7af2fbf0d99595ebee401d6bfbc1e77935d6c02 Mon Sep 17 00:00:00 2001 From: Koen Eelen Date: Tue, 9 Jul 2024 15:26:22 +0200 Subject: [PATCH 12/20] add test --- .../EloquentIntegrationRepositoryTest.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/Domain/Integrations/Repositories/EloquentIntegrationRepositoryTest.php b/tests/Domain/Integrations/Repositories/EloquentIntegrationRepositoryTest.php index 65010abec..a30d4b936 100644 --- a/tests/Domain/Integrations/Repositories/EloquentIntegrationRepositoryTest.php +++ b/tests/Domain/Integrations/Repositories/EloquentIntegrationRepositoryTest.php @@ -561,4 +561,28 @@ public function test_it_can_save_partner_status(): void 'partner_status' => IntegrationPartnerStatus::FIRST_PARTY, ]); } + + // https://jira.publiq.be/browse/PPF-555 + public function test_it_can_save_integration_uitpas_always_with_key_visibility_v2(): void + { + $integrationId = Uuid::uuid4(); + + $searchIntegration = new Integration( + $integrationId, + IntegrationType::UiTPAS, + 'First party integration', + 'First party integration', + Uuid::uuid4(), + IntegrationStatus::Draft, + IntegrationPartnerStatus::FIRST_PARTY, + ); + $searchIntegration = $searchIntegration->withKeyVisibility(KeyVisibility::v1); + + $this->integrationRepository->save($searchIntegration); + + $this->assertDatabaseHas('integrations', [ + 'id' => $integrationId, + 'key_visibility' => 'v2', + ]); + } } From 0ac7d4315e3aa18e798071553f2946f84c732ebe Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Tue, 9 Jul 2024 17:27:56 +0200 Subject: [PATCH 13/20] Tweak styling of organizer cards --- .../Integrations/Detail/OrganizersInfo.tsx | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx b/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx index 352db094e..ae52009c7 100644 --- a/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx +++ b/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx @@ -42,26 +42,33 @@ const OrganizersSection = ({ {sectionName} - {organizers.map((organizer) => ( - -
-

{organizer.name[i18n.language]}

-
- -
- {sectionName === "Live" && ( +
+ {organizers.map((organizer) => ( + +
+

{organizer.name[i18n.language]}

- - setToBeDeletedId(organizer.id)} - /> +
- )} -
-
- ))} + {sectionName === "Live" && ( +
+ + setToBeDeletedId(organizer.id)} + /> +
+ )} +
+ + ))} +
{sectionName === "Live" && ( From 34e8af71760c453fabc79242dc5b5338132b5bd5 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 10 Jul 2024 10:55:37 +0200 Subject: [PATCH 14/20] Add actual test organizer and fix Live/Test split --- .../Controllers/IntegrationController.php | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index cff6d2b7a..c1127b279 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -174,17 +174,7 @@ public function show(string $id): Response $integration = $this->integrationRepository->getById(Uuid::fromString($id)); $oldCredentialsExpirationDate = $this->getExpirationDateForOldCredentials($integration->getKeyVisibilityUpgrade()); - $organizerIds = collect($integration->organizers())->map(fn (Organizer $organizer) => $organizer->organizerId->toString()); - $uitpasOrganizers = $this->searchClient->findUiTPASOrganizers(...$organizerIds)->getMember()?->getItems(); - $organizers = collect($uitpasOrganizers)->map(function (SapiOrganizer $organizer) { - $id = explode('/', $organizer->getId() ?? ''); - - return [ - 'id' => $id[count($id) - 1], - 'name' => $organizer->getName()?->getValues() ?? $id, - 'status' => $organizer->getWorkflowStatus() === 'ACTIVE' ? 'Live' : 'Test', - ]; - }); + $organizers = $this->getIntegrationOrganizersWithTestOrganizer($integration); return Inertia::render('Integrations/Detail', [ 'integration' => $integration->toArray(), @@ -390,4 +380,33 @@ private function guardUserIsContact(Request $request, string $integrationId): ?R return null; } + + /** + * @param Integration $integration + * @return Collection + */ + public function getIntegrationOrganizersWithTestOrganizer(Integration $integration): Collection + { + $organizerIds = collect($integration->organizers())->map(fn(Organizer $organizer) => $organizer->organizerId->toString()); + $uitpasOrganizers = $this->searchClient->findUiTPASOrganizers(...$organizerIds)->getMember()?->getItems(); + + $organizers = collect($uitpasOrganizers)->map(function (SapiOrganizer $organizer) { + $id = explode('/', $organizer->getId() ?? ''); + $id = $id[count($id) - 1]; + + return [ + 'id' => $id, + 'name' => $organizer->getName()?->getValues() ?? [], + 'status' => 'Live', + ]; + }); + + $organizers->push([ + 'id' => '0ce87cbc-9299-4528-8d35-92225dc9489f', + 'name' => ['nl' => 'UiTPAS Organisatie (Regio Gent + Paspartoe)'], + 'status' => 'Test', + ]); + + return $organizers; + } } From 804ae3e8130a80eb2edd4e5f0fbc6cf4dcf200c2 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 10 Jul 2024 10:55:44 +0200 Subject: [PATCH 15/20] Tweak layout of organizer rows --- .../ts/Components/Integrations/Detail/OrganizersInfo.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx b/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx index ae52009c7..b7050f87c 100644 --- a/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx +++ b/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx @@ -50,8 +50,10 @@ const OrganizersSection = ({ "m-0 drop-shadow-none border border-gray-200 border-t-0 first:border-t" } > -
-

{organizer.name[i18n.language]}

+
+

+ {organizer.name[i18n.language]} +

From acb4fa0fbb98bd68c696e24201188531e5da4759 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 10 Jul 2024 10:56:42 +0200 Subject: [PATCH 16/20] Linting --- .../Integrations/Controllers/IntegrationController.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/Domain/Integrations/Controllers/IntegrationController.php b/app/Domain/Integrations/Controllers/IntegrationController.php index c1127b279..c36f5fc66 100644 --- a/app/Domain/Integrations/Controllers/IntegrationController.php +++ b/app/Domain/Integrations/Controllers/IntegrationController.php @@ -381,13 +381,10 @@ private function guardUserIsContact(Request $request, string $integrationId): ?R return null; } - /** - * @param Integration $integration - * @return Collection - */ + public function getIntegrationOrganizersWithTestOrganizer(Integration $integration): Collection { - $organizerIds = collect($integration->organizers())->map(fn(Organizer $organizer) => $organizer->organizerId->toString()); + $organizerIds = collect($integration->organizers())->map(fn (Organizer $organizer) => $organizer->organizerId->toString()); $uitpasOrganizers = $this->searchClient->findUiTPASOrganizers(...$organizerIds)->getMember()?->getItems(); $organizers = collect($uitpasOrganizers)->map(function (SapiOrganizer $organizer) { From 5ea1de3c8a968a009c76bd14e7e552c8e62e6d71 Mon Sep 17 00:00:00 2001 From: Emma Fabre Date: Wed, 10 Jul 2024 11:01:32 +0200 Subject: [PATCH 17/20] Tweak color --- .../ts/Components/Integrations/Detail/OrganizersInfo.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx b/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx index b7050f87c..85ad0437a 100644 --- a/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx +++ b/resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx @@ -51,9 +51,12 @@ const OrganizersSection = ({ } >
-

+ {organizer.name[i18n.language]} -

+
From bfd0cd8dae47b70b8f9a16476cbfc10e19a6720b Mon Sep 17 00:00:00 2001 From: JonasVHG <4658984+JonasVHG@users.noreply.github.com> Date: Wed, 10 Jul 2024 14:15:03 +0200 Subject: [PATCH 18/20] Add action to Activate Uitpas Integration --- .../Actions/ActivateUitpasIntegration.php | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 app/Nova/Actions/ActivateUitpasIntegration.php diff --git a/app/Nova/Actions/ActivateUitpasIntegration.php b/app/Nova/Actions/ActivateUitpasIntegration.php new file mode 100644 index 000000000..016218e45 --- /dev/null +++ b/app/Nova/Actions/ActivateUitpasIntegration.php @@ -0,0 +1,85 @@ +first(); + + /** @var string $organizationIdAsString */ + $organizationIdAsString = $fields->get('organization'); + $organizationId = Uuid::fromString($organizationIdAsString); + + /** @var string $organizers */ + $organizers = $fields->get('organizers'); + $organizerArray = array_map('trim', explode(',', $organizers)); + + foreach ($organizerArray as $organizer) { + $organizerId = Uuid::fromString($organizer); + $this->organizerRepository->create( + new Organizer( + Uuid::uuid4(), + Uuid::fromString($integration->id), + $organizerId + ) + ); + } + + $this->integrationRepository->activateWithOrganization( + Uuid::fromString($integration->id), + $organizationId, + null + ); + + return Action::message('Integration "' . $integration->name . '" activated.'); + } + + public function fields(NovaRequest $request): array + { + return [ + Select::make('Organization', 'organization') + ->options( + OrganizationModel::query()->pluck('name', 'id') + ) + ->rules( + 'required', + 'exists:organizations,id' + ), + Text::make('Organizer(s)', 'organizers') + ->rules( + 'nullable', + 'string' + ), + ]; + } +} From 1bf7751eaffa845edc5fddfe032246264164ac6d Mon Sep 17 00:00:00 2001 From: JonasVHG <4658984+JonasVHG@users.noreply.github.com> Date: Wed, 10 Jul 2024 14:15:23 +0200 Subject: [PATCH 19/20] Integrate ActivateUitpasIntegration into Integration. --- app/Nova/Resources/Integration.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/Nova/Resources/Integration.php b/app/Nova/Resources/Integration.php index f6ac92260..11461355e 100644 --- a/app/Nova/Resources/Integration.php +++ b/app/Nova/Resources/Integration.php @@ -14,6 +14,7 @@ use App\Domain\Integrations\Repositories\OrganizerRepository; use App\Keycloak\KeycloakConfig; use App\Nova\Actions\ActivateIntegration; +use App\Nova\Actions\ActivateUitpasIntegration; use App\Nova\Actions\AddOrganizer; use App\Nova\Actions\ApproveIntegration; use App\Nova\Actions\Auth0\CreateMissingAuth0Clients; @@ -227,7 +228,15 @@ public function actions(NovaRequest $request): array ->confirmText('Are you sure you want to activate this integration?') ->confirmButtonText('Activate') ->cancelButtonText('Cancel') - ->canSee(fn (Request $request) => $request instanceof ActionRequest || $this->canBeActivated()) + ->canSee(fn (Request $request) => $request instanceof ActionRequest || $this->canBeActivated() && !$this->isUiTPAS()) + ->canRun(fn (Request $request, IntegrationModel $model) => $model->canBeActivated() && !$this->isUiTPAS()), + + (new ActivateUitpasIntegration(App::make(IntegrationRepository::class), App::make(OrganizerRepository::class))) + ->exceptOnIndex() + ->confirmText('Are you sure you want to activate this integration?') + ->confirmButtonText('Activate') + ->cancelButtonText('Cancel') + ->canSee(fn (Request $request) => $request instanceof ActionRequest || $this->canBeActivated() && $this->isUiTPAS()) ->canRun(fn (Request $request, IntegrationModel $model) => $model->canBeActivated()), (new ApproveIntegration(App::make(IntegrationRepository::class))) From f7190f19fb4307409aeeff6d4ea4d562b32835c1 Mon Sep 17 00:00:00 2001 From: JonasVHG <4658984+JonasVHG@users.noreply.github.com> Date: Wed, 10 Jul 2024 14:32:13 +0200 Subject: [PATCH 20/20] typo --- app/Nova/Resources/Integration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Nova/Resources/Integration.php b/app/Nova/Resources/Integration.php index 11461355e..5eab9ff96 100644 --- a/app/Nova/Resources/Integration.php +++ b/app/Nova/Resources/Integration.php @@ -229,7 +229,7 @@ public function actions(NovaRequest $request): array ->confirmButtonText('Activate') ->cancelButtonText('Cancel') ->canSee(fn (Request $request) => $request instanceof ActionRequest || $this->canBeActivated() && !$this->isUiTPAS()) - ->canRun(fn (Request $request, IntegrationModel $model) => $model->canBeActivated() && !$this->isUiTPAS()), + ->canRun(fn (Request $request, IntegrationModel $model) => $model->canBeActivated()), (new ActivateUitpasIntegration(App::make(IntegrationRepository::class), App::make(OrganizerRepository::class))) ->exceptOnIndex()