Skip to content

Commit

Permalink
Merge branch 'main' into PPF-506-fix-e2e-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vhande authored Jul 5, 2024
2 parents 1e8f765 + 6cd7cd2 commit 76fe28e
Show file tree
Hide file tree
Showing 13 changed files with 168 additions and 13 deletions.
2 changes: 1 addition & 1 deletion .env.ci
Original file line number Diff line number Diff line change
Expand Up @@ -195,4 +195,4 @@ KEYCLOAK_PROD_SCOPE_ENTRY_API_ID='d8a54568-26da-412b-a441-d5e2fad84478' #publiq-
KEYCLOAK_PROD_SCOPE_UITPAS_ID='bcfb28cc-454f-488a-b080-6a29d9c0158e'#uitpas-scope

SEARCH_BASE_URI=https://search-acc.uitdatabank.be/
SEARCH_API_KEY=
SEARCH_API_KEY=deb306a6-6f46-4c98-89ce-b03ec4fd11e2
12 changes: 5 additions & 7 deletions app/Auth0/Auth0ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace App\Auth0;

use App\Auth0\Jobs\UnblockClient;
use App\Auth0\Jobs\UnblockClientHandler;
use App\Auth0\Jobs\BlockClient;
use App\Auth0\Jobs\BlockClientHandler;
use App\Auth0\Jobs\CreateMissingClients;
use App\Auth0\Jobs\CreateMissingClientsHandler;
use App\Auth0\Jobs\UnblockClient;
use App\Auth0\Jobs\UnblockClientHandler;
use App\Auth0\Listeners\BlockClients;
use App\Auth0\Listeners\CreateClients;
use App\Auth0\Listeners\UnblockClients;
Expand All @@ -26,7 +26,6 @@
use App\Domain\Integrations\Events\IntegrationUrlCreated;
use App\Domain\Integrations\Events\IntegrationUrlDeleted;
use App\Domain\Integrations\Events\IntegrationUrlUpdated;
use App\Keycloak\KeycloakConfig;
use Auth0\SDK\Configuration\SdkConfiguration;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Event;
Expand Down Expand Up @@ -56,15 +55,14 @@ public function register(): void
// Filter out tenants with missing config (consider them disabled)
$tenantsConfig = array_filter(
config('auth0.tenants'),
static fn (array $tenantConfig) =>
$tenantConfig['domain'] !== '' &&
static fn (array $tenantConfig) => $tenantConfig['domain'] !== '' &&
$tenantConfig['clientId'] !== '' &&
$tenantConfig['clientSecret'] !== ''
);

// Create Auth0Tenant objects based on the tenants config keys
$tenants = array_map(
static fn (string|int $tenant) => Auth0Tenant::from((string) $tenant),
static fn (string|int $tenant) => Auth0Tenant::from((string)$tenant),
array_keys($tenantsConfig)
);

Expand Down Expand Up @@ -93,7 +91,7 @@ public function register(): void
);
});

if (config(KeycloakConfig::KEYCLOAK_CREATION_ENABLED)) {
if (config('auth0.enabled')) {
// By default, the Auth0 integration is enabled. For testing purposes this can be disabled inside the .env file.

// May always be registered even if there are no configured tenants, because in that case the cluster SDK will
Expand Down
24 changes: 20 additions & 4 deletions app/Domain/Integrations/Controllers/IntegrationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
use App\Domain\Contacts\Repositories\ContactKeyVisibilityRepository;
use App\Domain\Contacts\Repositories\ContactRepository;
use App\Domain\Coupons\Repositories\CouponRepository;
use App\Domain\Integrations\FormRequests\KeyVisibilityUpgradeRequest;
use App\Domain\Integrations\FormRequests\RequestActivationRequest;
use App\Domain\Integrations\FormRequests\StoreContactRequest;
use App\Domain\Integrations\FormRequests\StoreIntegrationRequest;
use App\Domain\Integrations\FormRequests\StoreIntegrationUrlRequest;
use App\Domain\Integrations\FormRequests\KeyVisibilityUpgradeRequest;
use App\Domain\Integrations\FormRequests\UpdateContactInfoRequest;
use App\Domain\Integrations\FormRequests\UpdateIntegrationRequest;
use App\Domain\Integrations\FormRequests\UpdateIntegrationUrlsRequest;
Expand All @@ -23,27 +23,30 @@
use App\Domain\Integrations\IntegrationType;
use App\Domain\Integrations\IntegrationUrl;
use App\Domain\Integrations\KeyVisibility;
use App\Domain\Integrations\Mappers\KeyVisibilityUpgradeMapper;
use App\Domain\Integrations\Mappers\OrganizationMapper;
use App\Domain\Integrations\Mappers\OrganizerMapper;
use App\Domain\Integrations\Mappers\StoreContactMapper;
use App\Domain\Integrations\Mappers\StoreIntegrationMapper;
use App\Domain\Integrations\Mappers\StoreIntegrationUrlMapper;
use App\Domain\Integrations\Mappers\KeyVisibilityUpgradeMapper;
use App\Domain\Integrations\Mappers\UpdateContactInfoMapper;
use App\Domain\Integrations\Mappers\UpdateIntegrationMapper;
use App\Domain\Integrations\Mappers\UpdateIntegrationUrlsMapper;
use App\Domain\Integrations\Organizer;
use App\Domain\Integrations\Repositories\IntegrationRepository;
use App\Domain\Integrations\Repositories\IntegrationUrlRepository;
use App\Domain\Integrations\Repositories\OrganizerRepository;
use App\Domain\KeyVisibilityUpgrades\KeyVisibilityUpgrade;
use App\Domain\KeyVisibilityUpgrades\Repositories\KeyVisibilityUpgradeRepository;
use App\Domain\Organizations\Repositories\OrganizationRepository;
use App\Domain\Subscriptions\Repositories\SubscriptionRepository;
use App\Domain\KeyVisibilityUpgrades\Repositories\KeyVisibilityUpgradeRepository;
use App\Http\Controllers\Controller;
use App\ProjectAanvraag\ProjectAanvraagUrl;
use App\Router\TranslatedRoute;
use App\Search\Sapi3\SearchService;
use App\UiTiDv1\Repositories\UiTiDv1ConsumerRepository;
use Carbon\Carbon;
use CultuurNet\SearchV3\ValueObjects\Organizer as SapiOrganizer;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\UniqueConstraintViolationException;
use Illuminate\Http\RedirectResponse;
Expand All @@ -70,6 +73,7 @@ public function __construct(
private readonly Auth0ClientRepository $auth0ClientRepository,
private readonly UiTiDv1ConsumerRepository $uitidV1ConsumerRepository,
private readonly KeyVisibilityUpgradeRepository $keyVisibilityUpgradeRepository,
private readonly SearchService $searchClient,
private readonly CurrentUser $currentUser
) {
}
Expand Down Expand Up @@ -170,12 +174,24 @@ 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',
];
});

return Inertia::render('Integrations/Detail', [
'integration' => $integration->toArray(),
'oldCredentialsExpirationDate' => $oldCredentialsExpirationDate,
'email' => Auth::user()?->email,
'subscriptions' => $this->subscriptionRepository->all(),
'organizers' => session('organizers'),
'organizers' => $organizers,
]);
}

Expand Down
20 changes: 20 additions & 0 deletions app/Domain/Integrations/Integration.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ final class Integration

private ?Organization $organization;

/** @var array<Organizer> */
private array $organizers;

/** @var array<UiTiDv1Consumer> */
private array $uiTiDv1Consumers;

Expand All @@ -57,6 +60,7 @@ public function __construct(
$this->uiTiDv1Consumers = [];
$this->auth0Clients = [];
$this->keycloakClients = [];
$this->organizers = [];
$this->organization = null;
$this->keyVisibility = KeyVisibility::v2;
$this->keyVisibilityUpgrade = null;
Expand Down Expand Up @@ -122,6 +126,13 @@ public function withKeycloakClients(KeycloakClient ...$keycloakClients): self
return $clone;
}

public function withOrganizers(Organizer ...$organizers): self
{
$clone = clone $this;
$clone->organizers = $organizers;
return $clone;
}

public function withSubscription(Subscription $subscription): self
{
$clone = clone $this;
Expand Down Expand Up @@ -166,6 +177,14 @@ public function organization(): ?Organization
return $this->organization;
}

/**
* @return array<Organizer>
*/
public function organizers(): array
{
return $this->organizers;
}

/** @return array<UiTiDv1Consumer> */
public function uiTiDv1Consumers(): array
{
Expand Down Expand Up @@ -226,6 +245,7 @@ public function toArray(): array
'contacts' => $this->contacts,
'urls' => $this->urls,
'organization' => $this->organization,
'organizers' => $this->organizers,
'authClients' => $this->auth0Clients,
'legacyAuthConsumers' => $this->uiTiDv1Consumers,
'keycloakClients' => $this->keycloakClients,
Expand Down
5 changes: 5 additions & 0 deletions app/Domain/Integrations/Models/IntegrationModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,11 @@ public function toDomain(): Integration
->get()
->map(fn (KeycloakClientModel $keycloakClientModel) => $keycloakClientModel->toDomain())
->toArray()
)->withOrganizers(
...$this->organizers()
->get()
->map(fn (OrganizerModel $organizerModel) => $organizerModel->toDomain())
->toArray()
);

if ($this->keyVisibilityUpgrade) {
Expand Down
16 changes: 16 additions & 0 deletions app/Search/Sapi3/Sapi3SearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace App\Search\Sapi3;

use CultuurNet\SearchV3\Parameter\Id;
use CultuurNet\SearchV3\Parameter\Query;
use CultuurNet\SearchV3\SearchClientInterface;
use CultuurNet\SearchV3\SearchQuery;
Expand All @@ -25,4 +26,19 @@ public function searchUiTPASOrganizer(string $name): PagedCollection

return $this->searchClient->searchOrganizers($searchQuery);
}

public function findUiTPASOrganizers(string ...$ids): PagedCollection
{
$searchQuery = new SearchQuery();
$searchQuery->setEmbed(true);
if (empty($ids)) {
return new PagedCollection();
}

foreach ($ids as $id) {
$searchQuery->addParameter(new Id($id));
}

return $this->searchClient->searchOrganizers($searchQuery);
}
}
1 change: 1 addition & 0 deletions app/Search/Sapi3/SearchService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
interface SearchService
{
public function searchUiTPASOrganizer(string $name): PagedCollection;
public function findUiTPASOrganizers(string ...$ids): PagedCollection;
}
5 changes: 5 additions & 0 deletions resources/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@
"description": "Contacts can edit, activate, and delete the integration. Once deleted, a contact no longer has access to the integration."
}
},
"organizers_info": {
"title": "Organizers",
"description": "Below you see an overview of the UiTdatabank organizers for which you can execute actions in the UiTPAS API.",
"add": "Add organizer"
},
"billing_info": {
"title": {
"billing": "Billing information",
Expand Down
5 changes: 5 additions & 0 deletions resources/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@
"description": "Contacten kunnen de integratie aanpassen, activeren en verwijderen. Eens verwijderd heeft een contact geen toegang meer tot de integratie."
}
},
"organizers_info": {
"title": "Organisaties",
"description": "Hieronder vind je een overzicht van de UiTdatabank organisaties waarvoor je acties kan uitvoeren in de UiTPAS API.",
"add": "Organisatie toevoegen"
},
"billing_info": {
"title": {
"billing": "Facturatiegegevens",
Expand Down
2 changes: 1 addition & 1 deletion resources/ts/Components/CopyText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const CopyText = ({ text, isSecret }: Props) => {
};

return (
<div className="inline-flex self-start gap-2 items-center bg-[#fdf3ef] rounded px-3 p-1">
<div className="inline-flex gap-2 items-center bg-[#fdf3ef] rounded px-3 p-1">
<span
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}
Expand Down
73 changes: 73 additions & 0 deletions resources/ts/Components/Integrations/Detail/OrganizersInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React from "react";
import { Heading } from "../../Heading";
import { useTranslation } from "react-i18next";
import type { Integration } from "../../../types/Integration";
import { Card } from "../../Card";
import { CopyText } from "../../CopyText";
import { ButtonIcon } from "../../ButtonIcon";
import { faPencil, faTrash } from "@fortawesome/free-solid-svg-icons";
import type { Organizer } from "../../../types/Organizer";
import { groupBy } from "lodash";
import { ButtonPrimary } from "../../ButtonPrimary";

type Props = Integration & { organizers: Organizer[] };

const OrganizersSection = ({
sectionName,
organizers,
}: {
organizers: Organizer[];
sectionName: Organizer["status"];
}) => {
const { t, i18n } = useTranslation();
if (!organizers?.length) {
return null;
}

return (
<>
<Heading level={4} className="font-semibold">
{sectionName}
</Heading>
{organizers.map((organizer) => (
<Card key={organizer.id}>
<div className="grid grid-cols-[1fr,2fr,auto] gap-x-4 items-center">
<h1 className={"font-bold"}>{organizer.name[i18n.language]}</h1>
<div>
<CopyText text={organizer.id} />
</div>
{sectionName === "Live" && (
<div>
<ButtonIcon icon={faPencil} className="text-icon-gray" />
<ButtonIcon icon={faTrash} className="text-icon-gray" />
</div>
)}
</div>
</Card>
))}
<div className="grid lg:grid-cols-3">
{sectionName === "Live" && (
<ButtonPrimary className="col-span-1">
{t("details.organizers_info.add")}
</ButtonPrimary>
)}
</div>
</>
);
};

export const OrganizersInfo = ({ organizers }: Props) => {
const { t } = useTranslation();
const byStatus = groupBy(organizers, "status");

return (
<>
<Heading level={4} className="font-semibold">
{t("details.organizers_info.title")}
</Heading>
<p>{t("details.organizers_info.description")}</p>
<OrganizersSection sectionName="Test" organizers={byStatus["Test"]} />
<OrganizersSection sectionName="Live" organizers={byStatus["Live"]} />
</>
);
};
10 changes: 10 additions & 0 deletions resources/ts/Pages/Integrations/Detail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,24 @@ import { PricingPlanProvider } from "../../Context/PricingPlan";
import { useIsMobile } from "../../hooks/useIsMobile";
import { CouponInfoProvider } from "../../Context/CouponInfo";
import type { Integration } from "../../types/Integration";
import { OrganizersInfo } from "../../Components/Integrations/Detail/OrganizersInfo";
import type { Organizer } from "../../types/Organizer";

type Props = {
integration: Integration;
email: string;
subscriptions: Subscription[];
oldCredentialsExpirationDate: string;
errors: Record<string, string | undefined>;
organizers: Organizer[];
};

const Detail = ({
integration,
email,
subscriptions,
oldCredentialsExpirationDate,
organizers,
errors,
}: Props) => {
const { t } = useTranslation();
Expand Down Expand Up @@ -175,6 +179,12 @@ const Detail = ({
duplicateContactErrorMessage={duplicateContactErrorMessage}
/>
</Tabs.Item>
<Tabs.Item
type="organisations"
label={t("details.organizers_info.title")}
>
<OrganizersInfo {...integration} organizers={organizers} />
</Tabs.Item>
<Tabs.Item
type="billing"
label={t("details.billing_info.title.billing")}
Expand Down
6 changes: 6 additions & 0 deletions resources/ts/types/Organizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export type Organizer = {
id: string;
name: { [key: string]: string };
description: string;
status: "Live" | "Test";
};

0 comments on commit 76fe28e

Please sign in to comment.