Compare commits
11 Commits
683766259c
...
0a4cb375e9
| Author | SHA1 | Date |
|---|---|---|
|
|
0a4cb375e9 | |
|
|
2dae055ae9 | |
|
|
91304d95dc | |
|
|
edf91ae01d | |
|
|
3200d05ed6 | |
|
|
5fea79cafa | |
|
|
32b42beb37 | |
|
|
afc1b16dea | |
|
|
6a4f1f662e | |
|
|
d603328585 | |
|
|
195f841f8c |
|
|
@ -19,6 +19,8 @@
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/rate-limiter" />
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/rate-limiter" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/remote-event" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/webhook" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,10 @@
|
||||||
<path value="$PROJECT_DIR$/vendor/twig/extra-bundle" />
|
<path value="$PROJECT_DIR$/vendor/twig/extra-bundle" />
|
||||||
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||||
<path value="$PROJECT_DIR$/vendor/symfony/rate-limiter" />
|
<path value="$PROJECT_DIR$/vendor/symfony/rate-limiter" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/dama/doctrine-test-bundle" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/remote-event" />
|
||||||
|
<path value="$PROJECT_DIR$/vendor/symfony/webhook" />
|
||||||
</include_path>
|
</include_path>
|
||||||
</component>
|
</component>
|
||||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
|
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ export default class extends Controller {
|
||||||
this.modalTitleTarget.textContent = "Modifier l'organisation";
|
this.modalTitleTarget.textContent = "Modifier l'organisation";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/organization/${this.currentOrgId}`);
|
const response = await fetch(`/organization/editModal/${this.currentOrgId}`);
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
// Fill targets
|
// Fill targets
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
"symfony/ux-turbo": "^2.24",
|
"symfony/ux-turbo": "^2.24",
|
||||||
"symfony/validator": "7.4.*",
|
"symfony/validator": "7.4.*",
|
||||||
"symfony/web-link": "7.4.*",
|
"symfony/web-link": "7.4.*",
|
||||||
|
"symfony/webhook": "7.4.*",
|
||||||
"symfony/yaml": "7.4.*",
|
"symfony/yaml": "7.4.*",
|
||||||
"twig/twig": "^2.12|^3.0"
|
"twig/twig": "^2.12|^3.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ league_oauth2_server:
|
||||||
private_key_passphrase: '%env(resolve:OAUTH_PASSPHRASE)%'
|
private_key_passphrase: '%env(resolve:OAUTH_PASSPHRASE)%'
|
||||||
encryption_key: '%env(resolve:OAUTH_ENCRYPTION_KEY)%'
|
encryption_key: '%env(resolve:OAUTH_ENCRYPTION_KEY)%'
|
||||||
access_token_ttl: PT15M # 15 minutes
|
access_token_ttl: PT15M # 15 minutes
|
||||||
refresh_token_ttl: PT7D # 7 days
|
refresh_token_ttl: P7D # 7 days
|
||||||
auth_code_ttl: PT30M # 30 minutes
|
auth_code_ttl: PT30M # 30 minutes
|
||||||
require_code_challenge_for_public_clients: false
|
require_code_challenge_for_public_clients: false
|
||||||
resource_server:
|
resource_server:
|
||||||
|
|
|
||||||
|
|
@ -676,7 +676,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||||
* }>,
|
* }>,
|
||||||
* },
|
* },
|
||||||
* webhook?: bool|array{ // Webhook configuration
|
* webhook?: bool|array{ // Webhook configuration
|
||||||
* enabled?: bool|Param, // Default: false
|
* enabled?: bool|Param, // Default: true
|
||||||
* message_bus?: scalar|Param|null, // The message bus to use. // Default: "messenger.default_bus"
|
* message_bus?: scalar|Param|null, // The message bus to use. // Default: "messenger.default_bus"
|
||||||
* routing?: array<string, array{ // Default: []
|
* routing?: array<string, array{ // Default: []
|
||||||
* service: scalar|Param|null,
|
* service: scalar|Param|null,
|
||||||
|
|
@ -684,7 +684,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
|
||||||
* }>,
|
* }>,
|
||||||
* },
|
* },
|
||||||
* remote-event?: bool|array{ // RemoteEvent configuration
|
* remote-event?: bool|array{ // RemoteEvent configuration
|
||||||
* enabled?: bool|Param, // Default: false
|
* enabled?: bool|Param, // Default: true
|
||||||
* },
|
* },
|
||||||
* json_streamer?: bool|array{ // JSON streamer configuration
|
* json_streamer?: bool|array{ // JSON streamer configuration
|
||||||
* enabled?: bool|Param, // Default: false
|
* enabled?: bool|Param, // Default: false
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ parameters:
|
||||||
oauth_sso_identifier: '%env(OAUTH_SSO_IDENTIFIER)%'
|
oauth_sso_identifier: '%env(OAUTH_SSO_IDENTIFIER)%'
|
||||||
oauth_sso_identifier_login: '%env(OAUTH_SSO_IDENTIFIER_LOGIN)%'
|
oauth_sso_identifier_login: '%env(OAUTH_SSO_IDENTIFIER_LOGIN)%'
|
||||||
easycheck_url: '%env(EASYCHECK_URL)%'
|
easycheck_url: '%env(EASYCHECK_URL)%'
|
||||||
|
webhook_secret: '%env(WEBHOOK_SECRET)%'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
# default configuration for services in *this* file
|
# default configuration for services in *this* file
|
||||||
|
|
@ -59,11 +60,12 @@ services:
|
||||||
arguments:
|
arguments:
|
||||||
$environment: '%kernel.environment%'
|
$environment: '%kernel.environment%'
|
||||||
|
|
||||||
# add more service definitions when explicit configuration is needed
|
|
||||||
# please note that last definitions always *replace* previous ones
|
|
||||||
|
|
||||||
App\EventListener\LogoutSubscriber:
|
App\EventListener\LogoutSubscriber:
|
||||||
arguments:
|
arguments:
|
||||||
$easycheckUrl: '%env(EASYCHECK_URL)%'
|
$easycheckUrl: '%env(EASYCHECK_URL)%'
|
||||||
tags:
|
tags:
|
||||||
- { name: kernel.event_subscriber }
|
- { name: kernel.event_subscriber }
|
||||||
|
App\Webhook\OrganizationNotifier:
|
||||||
|
arguments:
|
||||||
|
$easycheckUrl: '%easycheck_url%'
|
||||||
|
$webhookSecret: '%webhook_secret%'
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ use App\Form\OrganizationForm;
|
||||||
use App\Repository\OrganizationsRepository;
|
use App\Repository\OrganizationsRepository;
|
||||||
use App\Repository\UsersOrganizationsRepository;
|
use App\Repository\UsersOrganizationsRepository;
|
||||||
use App\Service\ActionService;
|
use App\Service\ActionService;
|
||||||
use App\Service\AwsService;
|
|
||||||
use App\Service\LoggerService;
|
use App\Service\LoggerService;
|
||||||
|
use App\Webhook\OrganizationNotifier;
|
||||||
use App\Service\OrganizationsService;
|
use App\Service\OrganizationsService;
|
||||||
use App\Service\UserOrganizationService;
|
use App\Service\UserOrganizationService;
|
||||||
use App\Service\UserService;
|
use App\Service\UserService;
|
||||||
|
|
@ -37,7 +37,9 @@ class OrganizationController extends AbstractController
|
||||||
private readonly ActionService $actionService,
|
private readonly ActionService $actionService,
|
||||||
private readonly UserOrganizationService $userOrganizationService,
|
private readonly UserOrganizationService $userOrganizationService,
|
||||||
private readonly OrganizationsRepository $organizationsRepository,
|
private readonly OrganizationsRepository $organizationsRepository,
|
||||||
private readonly LoggerService $loggerService, private readonly UsersOrganizationsRepository $usersOrganizationsRepository)
|
private readonly LoggerService $loggerService,
|
||||||
|
private readonly UsersOrganizationsRepository $usersOrganizationsRepository,
|
||||||
|
private readonly OrganizationNotifier $organizationNotifier)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,6 +113,8 @@ class OrganizationController extends AbstractController
|
||||||
$this->entityManager->persist($organization);
|
$this->entityManager->persist($organization);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
//webhook notify
|
||||||
|
$this->organizationNotifier->notifyOrganizationCreated($organization);
|
||||||
// Loggers...
|
// Loggers...
|
||||||
$this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getUserIdentifier(), "Organization Created via ajax");
|
$this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getUserIdentifier(), "Organization Created via ajax");
|
||||||
|
|
||||||
|
|
@ -375,7 +379,7 @@ class OrganizationController extends AbstractController
|
||||||
/*
|
/*
|
||||||
* Path used to get data on an organization for the edit modal
|
* Path used to get data on an organization for the edit modal
|
||||||
*/
|
*/
|
||||||
#[Route(path: '/{id}', name: 'get', methods: ['GET'])]
|
#[Route(path: '/editModal/{id}', name: 'get', methods: ['GET'])]
|
||||||
public function get(int $id): JsonResponse{
|
public function get(int $id): JsonResponse{
|
||||||
$this->denyAccessUnlessGranted('ROLE_USER');
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
$actingUser = $this->getUser();
|
$actingUser = $this->getUser();
|
||||||
|
|
|
||||||
|
|
@ -872,11 +872,12 @@ class UserController extends AbstractController
|
||||||
$email = $user->getEmail();
|
$email = $user->getEmail();
|
||||||
$existingUser = $this->userRepository->findOneBy(['email' => $email]);
|
$existingUser = $this->userRepository->findOneBy(['email' => $email]);
|
||||||
|
|
||||||
if($this->userService->checkUserOrganizationLinkExists($existingUser, $org)){
|
|
||||||
return $this->json(['error' => "L'utilisateur existe déjà dans votre organisation"], 400);
|
|
||||||
}
|
|
||||||
// CASE A: User exists -> Add to org
|
// CASE A: User exists -> Add to org
|
||||||
if ($existingUser) {
|
if ($existingUser) {
|
||||||
|
if($this->userService->checkUserOrganizationLinkExists($existingUser, $org)){
|
||||||
|
return $this->json(['error' => "L'utilisateur existe déjà dans votre organisation"], 400);
|
||||||
|
}
|
||||||
// Check if already in org to avoid logic errors or duplicate logs
|
// Check if already in org to avoid logic errors or duplicate logs
|
||||||
$this->userService->addExistingUserToOrganization($existingUser, $org, $selectedApps);
|
$this->userService->addExistingUserToOrganization($existingUser, $org, $selectedApps);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ class LogoutSubscriber implements EventSubscriberInterface
|
||||||
$params['redirect_app'] = $redirectApp;
|
$params['redirect_app'] = $redirectApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
$easycheckLogoutUrl = $this->easycheckUrl . '/logout?' . http_build_query($params);
|
$easycheckLogoutUrl = rtrim($this->easycheckUrl, '/'). '/logout?' . http_build_query($params);
|
||||||
|
|
||||||
$this->logger->info('Redirecting to EasyCheck logout', [
|
$this->logger->info('Redirecting to EasyCheck logout', [
|
||||||
'url' => $easycheckLogoutUrl,
|
'url' => $easycheckLogoutUrl,
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class LoginSubscriber implements EventSubscriberInterface
|
||||||
$user->setLastConnection(new \DateTime('now', new \DateTimeZone('Europe/Paris')));
|
$user->setLastConnection(new \DateTime('now', new \DateTimeZone('Europe/Paris')));
|
||||||
|
|
||||||
$easySolution = $this->entityManager->getRepository(Client::class)->findOneBy(['identifier' => $this->clientIdentifier]);
|
$easySolution = $this->entityManager->getRepository(Client::class)->findOneBy(['identifier' => $this->clientIdentifier]);
|
||||||
/*if ($easySolution) {
|
if ($easySolution) {
|
||||||
$accessToken = new AccessToken(
|
$accessToken = new AccessToken(
|
||||||
identifier: bin2hex(random_bytes(40)),
|
identifier: bin2hex(random_bytes(40)),
|
||||||
expiry: new \DateTimeImmutable('+1 hour', new \DateTimeZone('Europe/Paris')),
|
expiry: new \DateTimeImmutable('+1 hour', new \DateTimeZone('Europe/Paris')),
|
||||||
|
|
@ -70,7 +70,7 @@ class LoginSubscriber implements EventSubscriberInterface
|
||||||
$this->entityManager->persist($user);
|
$this->entityManager->persist($user);
|
||||||
$this->entityManager->persist($accessToken);
|
$this->entityManager->persist($accessToken);
|
||||||
$this->entityManager->flush();
|
$this->entityManager->flush();
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vérifier si un paramètre redirect_app est présent dans l'URL
|
// Vérifier si un paramètre redirect_app est présent dans l'URL
|
||||||
|
|
|
||||||
|
|
@ -181,12 +181,11 @@ readonly class LoggerService
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function logUOALinkDeactivated(int $uoaId, int $appId, int $roleId): void
|
public function logUOALinkDeactivated(int $uoaId, int $appId): void
|
||||||
{
|
{
|
||||||
$this->organizationManagementLogger->notice('UOA link deactivated', [
|
$this->organizationManagementLogger->notice('UOA link deactivated', [
|
||||||
'uoa_id' => $uoaId,
|
'uoa_id' => $uoaId,
|
||||||
'app_id' => $appId,
|
'app_id' => $appId,
|
||||||
'role_id' => $roleId,
|
|
||||||
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
|
||||||
'timestamp' => $this->now(),
|
'timestamp' => $this->now(),
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -94,14 +94,13 @@ class UserOrganizationAppService
|
||||||
try{
|
try{
|
||||||
$uoa->setIsActive(false);
|
$uoa->setIsActive(false);
|
||||||
$this->actionService->createAction("Deactivate UOA link", $userOrganization->getUsers(),
|
$this->actionService->createAction("Deactivate UOA link", $userOrganization->getUsers(),
|
||||||
$userOrganization->getOrganization(), "App: " . $uoa->getApplication()->getName() . ", Role: " . $uoa->getRole()->getName());
|
$userOrganization->getOrganization(), "App: " . $uoa->getApplication()->getName());
|
||||||
$this->entityManager->persist($uoa);
|
$this->entityManager->persist($uoa);
|
||||||
$this->loggerService->logUOALinkDeactivated($uoa->getId(), $uoa->getApplication()->getId(), $uoa->getRole()->getId());
|
$this->loggerService->logUOALinkDeactivated($uoa->getId(), $uoa->getApplication()->getId());
|
||||||
}catch (\Exception $exception){
|
}catch (\Exception $exception){
|
||||||
$this->loggerService->logCritical("Error deactivating UOA link", [
|
$this->loggerService->logCritical("Error deactivating UOA link", [
|
||||||
'uoa_id' => $uoa->getId(),
|
'uoa_id' => $uoa->getId(),
|
||||||
'app_id' => $uoa->getApplication()->getId(),
|
'app_id' => $uoa->getApplication()->getId(),
|
||||||
'role_id' => $uoa->getRole()->getId(),
|
|
||||||
'exception_message' => $exception->getMessage(),
|
'exception_message' => $exception->getMessage(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Webhook;
|
||||||
|
|
||||||
|
use App\Entity\Organizations;
|
||||||
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
|
use Symfony\Component\RemoteEvent\RemoteEvent;
|
||||||
|
use Symfony\Component\Webhook\Messenger\SendWebhookMessage;
|
||||||
|
use Symfony\Component\Webhook\Subscriber;
|
||||||
|
|
||||||
|
class OrganizationNotifier
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly MessageBusInterface $messageBus,
|
||||||
|
private readonly string $easycheckUrl,
|
||||||
|
private readonly string $webhookSecret
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notifyOrganizationCreated(Organizations $organizations): void
|
||||||
|
{
|
||||||
|
$subscriber = new Subscriber(
|
||||||
|
url: rtrim($this->easycheckUrl, '/'). '/webhook/organization_created',
|
||||||
|
secret: $this->webhookSecret,
|
||||||
|
);
|
||||||
|
|
||||||
|
$event = new RemoteEvent(
|
||||||
|
name: 'organization_created',
|
||||||
|
id: uniqid('', true),
|
||||||
|
payload: [
|
||||||
|
'orgId' => $organizations->getId(),
|
||||||
|
'orgName' => $organizations->getName(),
|
||||||
|
'orgEmail' => $organizations->getEmail(),
|
||||||
|
'orgNumber' => $organizations->getNumber(),
|
||||||
|
'orgAddress' => $organizations->getAddress(),
|
||||||
|
'orgLogo' => $organizations->getLogoUrl(),
|
||||||
|
'created_at' => time(),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->messageBus->dispatch(
|
||||||
|
new SendWebhookMessage($subscriber, $event)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -414,5 +414,11 @@
|
||||||
"files": [
|
"files": [
|
||||||
"config/packages/messenger.yaml"
|
"config/packages/messenger.yaml"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"symfony/webhook": {
|
||||||
|
"version": "7.4",
|
||||||
|
"recipe": {
|
||||||
|
"version": "7.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,49 +26,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{# New organization modal #}
|
{# New organization modal #}
|
||||||
<div class="modal fade" id="createOrganizationModal" tabindex="-1" aria-labelledby="createOrganizationModalLabel"
|
{{ include('organization/organizationModal.html.twig') }}
|
||||||
aria-hidden="true"
|
|
||||||
data-organization-target="modal">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="createOrganizationModalLabel">Créer une organisation</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form data-action="submit->organization#createOrganization">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="organizationName" class="form-label">Nom de l'organisation</label>
|
|
||||||
<input type="text" class="form-control" id="organizationName" name="name" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="organizationEmail" class="form-label">Email</label>
|
|
||||||
<input class="form-control" id="organizationEmail" type="email" name="email" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="organizationPhone" class="form-label">Téléphone</label>
|
|
||||||
<input class="form-control" type="number" id="organizationPhone" name="phone">
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="organizationAddress" class="form-label">Adresse</label>
|
|
||||||
<input class="form-control" id="organizationAddress" name="address">
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label" for="organizationLogo">Logo de l'organisation</label>
|
|
||||||
<input type="file" name="logoUrl" id="organizationLogo" class="form-control"
|
|
||||||
accept="image/*">
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
|
||||||
Annuler
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="btn btn-primary">Créer l'organisation</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if is_granted('ROLE_SUPER_ADMIN') and not hasOrganizations %}
|
{% if is_granted('ROLE_SUPER_ADMIN') and not hasOrganizations %}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue