Compare commits

..

No commits in common. "0a4cb375e954616746ce4c42b6b1bdd99f325f89" and "683766259cc28b64d6c47d0d58256816c061e2d0" have entirely different histories.

16 changed files with 64 additions and 85 deletions

View File

@ -19,8 +19,6 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/http-client" />
<excludeFolder url="file://$MODULE_DIR$/vendor/ralouphie/getallheaders" />
<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>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View File

@ -181,10 +181,6 @@
<path value="$PROJECT_DIR$/vendor/twig/extra-bundle" />
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
<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>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.2" />

View File

@ -171,7 +171,7 @@ export default class extends Controller {
this.modalTitleTarget.textContent = "Modifier l'organisation";
try {
const response = await fetch(`/organization/editModal/${this.currentOrgId}`);
const response = await fetch(`/organization/${this.currentOrgId}`);
const data = await response.json();
// Fill targets

View File

@ -52,7 +52,6 @@
"symfony/ux-turbo": "^2.24",
"symfony/validator": "7.4.*",
"symfony/web-link": "7.4.*",
"symfony/webhook": "7.4.*",
"symfony/yaml": "7.4.*",
"twig/twig": "^2.12|^3.0"
},

View File

@ -4,7 +4,7 @@ league_oauth2_server:
private_key_passphrase: '%env(resolve:OAUTH_PASSPHRASE)%'
encryption_key: '%env(resolve:OAUTH_ENCRYPTION_KEY)%'
access_token_ttl: PT15M # 15 minutes
refresh_token_ttl: P7D # 7 days
refresh_token_ttl: PT7D # 7 days
auth_code_ttl: PT30M # 30 minutes
require_code_challenge_for_public_clients: false
resource_server:

View File

@ -676,7 +676,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* }>,
* },
* webhook?: bool|array{ // Webhook configuration
* enabled?: bool|Param, // Default: true
* enabled?: bool|Param, // Default: false
* message_bus?: scalar|Param|null, // The message bus to use. // Default: "messenger.default_bus"
* routing?: array<string, array{ // Default: []
* service: scalar|Param|null,
@ -684,7 +684,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* }>,
* },
* remote-event?: bool|array{ // RemoteEvent configuration
* enabled?: bool|Param, // Default: true
* enabled?: bool|Param, // Default: false
* },
* json_streamer?: bool|array{ // JSON streamer configuration
* enabled?: bool|Param, // Default: false

View File

@ -14,7 +14,6 @@ parameters:
oauth_sso_identifier: '%env(OAUTH_SSO_IDENTIFIER)%'
oauth_sso_identifier_login: '%env(OAUTH_SSO_IDENTIFIER_LOGIN)%'
easycheck_url: '%env(EASYCHECK_URL)%'
webhook_secret: '%env(WEBHOOK_SECRET)%'
services:
# default configuration for services in *this* file
@ -59,13 +58,12 @@ services:
App\Command\CreateSuperAdminCommand:
arguments:
$environment: '%kernel.environment%'
# add more service definitions when explicit configuration is needed
# please note that last definitions always *replace* previous ones
App\EventListener\LogoutSubscriber:
arguments:
$easycheckUrl: '%env(EASYCHECK_URL)%'
tags:
- { name: kernel.event_subscriber }
App\Webhook\OrganizationNotifier:
arguments:
$easycheckUrl: '%easycheck_url%'
$webhookSecret: '%webhook_secret%'

View File

@ -9,8 +9,8 @@ use App\Form\OrganizationForm;
use App\Repository\OrganizationsRepository;
use App\Repository\UsersOrganizationsRepository;
use App\Service\ActionService;
use App\Service\AwsService;
use App\Service\LoggerService;
use App\Webhook\OrganizationNotifier;
use App\Service\OrganizationsService;
use App\Service\UserOrganizationService;
use App\Service\UserService;
@ -37,9 +37,7 @@ class OrganizationController extends AbstractController
private readonly ActionService $actionService,
private readonly UserOrganizationService $userOrganizationService,
private readonly OrganizationsRepository $organizationsRepository,
private readonly LoggerService $loggerService,
private readonly UsersOrganizationsRepository $usersOrganizationsRepository,
private readonly OrganizationNotifier $organizationNotifier)
private readonly LoggerService $loggerService, private readonly UsersOrganizationsRepository $usersOrganizationsRepository)
{
}
@ -113,8 +111,6 @@ class OrganizationController extends AbstractController
$this->entityManager->persist($organization);
$this->entityManager->flush();
//webhook notify
$this->organizationNotifier->notifyOrganizationCreated($organization);
// Loggers...
$this->loggerService->logOrganizationInformation($organization->getId(), $actingUser->getUserIdentifier(), "Organization Created via ajax");
@ -379,7 +375,7 @@ class OrganizationController extends AbstractController
/*
* Path used to get data on an organization for the edit modal
*/
#[Route(path: '/editModal/{id}', name: 'get', methods: ['GET'])]
#[Route(path: '/{id}', name: 'get', methods: ['GET'])]
public function get(int $id): JsonResponse{
$this->denyAccessUnlessGranted('ROLE_USER');
$actingUser = $this->getUser();

View File

@ -872,12 +872,11 @@ class UserController extends AbstractController
$email = $user->getEmail();
$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
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
$this->userService->addExistingUserToOrganization($existingUser, $org, $selectedApps);

View File

@ -43,7 +43,7 @@ class LogoutSubscriber implements EventSubscriberInterface
$params['redirect_app'] = $redirectApp;
}
$easycheckLogoutUrl = rtrim($this->easycheckUrl, '/'). '/logout?' . http_build_query($params);
$easycheckLogoutUrl = $this->easycheckUrl . '/logout?' . http_build_query($params);
$this->logger->info('Redirecting to EasyCheck logout', [
'url' => $easycheckLogoutUrl,

View File

@ -59,7 +59,7 @@ class LoginSubscriber implements EventSubscriberInterface
$user->setLastConnection(new \DateTime('now', new \DateTimeZone('Europe/Paris')));
$easySolution = $this->entityManager->getRepository(Client::class)->findOneBy(['identifier' => $this->clientIdentifier]);
if ($easySolution) {
/*if ($easySolution) {
$accessToken = new AccessToken(
identifier: bin2hex(random_bytes(40)),
expiry: new \DateTimeImmutable('+1 hour', new \DateTimeZone('Europe/Paris')),
@ -70,7 +70,7 @@ class LoginSubscriber implements EventSubscriberInterface
$this->entityManager->persist($user);
$this->entityManager->persist($accessToken);
$this->entityManager->flush();
}
}*/
}
// Vérifier si un paramètre redirect_app est présent dans l'URL

View File

@ -181,11 +181,12 @@ readonly class LoggerService
]));
}
public function logUOALinkDeactivated(int $uoaId, int $appId): void
public function logUOALinkDeactivated(int $uoaId, int $appId, int $roleId): void
{
$this->organizationManagementLogger->notice('UOA link deactivated', [
'uoa_id' => $uoaId,
'app_id' => $appId,
'role_id' => $roleId,
'ip' => $this->requestStack->getCurrentRequest()?->getClientIp() ?? 'unknown',
'timestamp' => $this->now(),
]);

View File

@ -94,13 +94,14 @@ class UserOrganizationAppService
try{
$uoa->setIsActive(false);
$this->actionService->createAction("Deactivate UOA link", $userOrganization->getUsers(),
$userOrganization->getOrganization(), "App: " . $uoa->getApplication()->getName());
$userOrganization->getOrganization(), "App: " . $uoa->getApplication()->getName() . ", Role: " . $uoa->getRole()->getName());
$this->entityManager->persist($uoa);
$this->loggerService->logUOALinkDeactivated($uoa->getId(), $uoa->getApplication()->getId());
$this->loggerService->logUOALinkDeactivated($uoa->getId(), $uoa->getApplication()->getId(), $uoa->getRole()->getId());
}catch (\Exception $exception){
$this->loggerService->logCritical("Error deactivating UOA link", [
'uoa_id' => $uoa->getId(),
'app_id' => $uoa->getApplication()->getId(),
'role_id' => $uoa->getRole()->getId(),
'exception_message' => $exception->getMessage(),
]);
}

View File

@ -1,45 +0,0 @@
<?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)
);
}
}

View File

@ -414,11 +414,5 @@
"files": [
"config/packages/messenger.yaml"
]
},
"symfony/webhook": {
"version": "7.4",
"recipe": {
"version": "7.3"
}
}
}

View File

@ -26,7 +26,49 @@
{% endif %}
{# New organization modal #}
{{ include('organization/organizationModal.html.twig') }}
<div class="modal fade" id="createOrganizationModal" tabindex="-1" aria-labelledby="createOrganizationModalLabel"
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 class="card-body">
{% if is_granted('ROLE_SUPER_ADMIN') and not hasOrganizations %}