Création d'organisation
This commit is contained in:
parent
c55e9fa039
commit
7021b28163
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
|
|
@ -6,6 +6,7 @@
|
|||
parameters:
|
||||
aws_url: '%env(AWS_ENDPOINT)%'
|
||||
aws_public_url: '%env(AWS_ENDPOINT)%'
|
||||
logos_directory: '%kernel.project_dir%/public/uploads/logos'
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
|
|
@ -5,35 +5,36 @@ namespace App\Controller;
|
|||
use App\Entity\Apps;
|
||||
use App\Entity\Roles;
|
||||
use App\Entity\UsersOrganizations;
|
||||
use App\Form\OrganizationForm;
|
||||
use App\Service\ActionService;
|
||||
use App\Service\OrganizationsService;
|
||||
use App\Service\UserOrganizationService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use App\Entity\Organizations;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Contracts\Service\Attribute\Required;
|
||||
|
||||
#[Route(path: '/organization', name: 'organization_')]
|
||||
|
||||
class OrganizationController extends AbstractController
|
||||
{
|
||||
private const NOT_FOUND = 'Entity not found';
|
||||
private const ACCESS_DENIED = 'Access denied';
|
||||
|
||||
public function __construct(private readonly EntityManagerInterface $entityManager,
|
||||
private readonly OrganizationsService $organizationsService,
|
||||
private readonly UserOrganizationService $usersOrganizationService)
|
||||
public function __construct(private readonly EntityManagerInterface $entityManager,
|
||||
private readonly OrganizationsService $organizationsService,
|
||||
private readonly UserOrganizationService $usersOrganizationService)
|
||||
{
|
||||
}
|
||||
|
||||
#[Route(path: '/' , name: 'index', methods: ['GET'])]
|
||||
public function index():Response
|
||||
#[Route('/', name: 'index', methods: ['GET'])]
|
||||
public function index(): Response
|
||||
{
|
||||
if($this->isGranted('ROLE_SUPER_ADMIN'))
|
||||
{
|
||||
if ($this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
$organizations = $this->entityManager->getRepository(Organizations::class)->findBy(['isActive' => true]);
|
||||
} else{
|
||||
} else {
|
||||
$user = $this->getUser();
|
||||
if (!$user) {
|
||||
return $this->redirectToRoute('app_login');
|
||||
|
|
@ -41,7 +42,7 @@ class OrganizationController extends AbstractController
|
|||
$userIdentifier = $user->getUserIdentifier();
|
||||
|
||||
$organizations = $this->entityManager->getRepository(UsersOrganizations::class)->findOrganizationsByUserEmailAndRoleName($userIdentifier, 'ADMIN');
|
||||
if(!$organizations) {
|
||||
if (!$organizations) {
|
||||
// if user is not admin in any organization, throw access denied
|
||||
throw $this->createNotFoundException(self::ACCESS_DENIED);
|
||||
}
|
||||
|
|
@ -52,7 +53,44 @@ class OrganizationController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/{id}', name: 'show', methods: ['GET'])]
|
||||
#[Route('/new', name: 'new', methods: ['GET', 'POST'])]
|
||||
public function new(Request $request): Response
|
||||
{
|
||||
if (!$this->isGranted('ROLE_SUPER_ADMIN')) {
|
||||
throw $this->createNotFoundException(self::ACCESS_DENIED);
|
||||
}
|
||||
$form = $this->createForm(OrganizationForm::class);
|
||||
$form->handleRequest($request);
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$organization = $form->getData();
|
||||
// dd($form);
|
||||
$logoFile = $form->get('logoUrl')->getData();
|
||||
|
||||
if ($logoFile) {
|
||||
$currentDate = (new \DateTime())->format('Y-m-d');
|
||||
$organizationName = preg_replace('/[^a-zA-Z0-9]/', '_', $organization->getName());
|
||||
$extension = $logoFile->guessExtension();
|
||||
$newFilename = $currentDate . '_' . $organizationName . $extension;
|
||||
// Move the file to the directory where logos are stored
|
||||
$logoFile->move(
|
||||
$this->getParameter('logos_directory'),
|
||||
$newFilename
|
||||
);
|
||||
|
||||
// Update the 'logoUrl' property to store the file name
|
||||
$organization->setLogoUrl($newFilename);
|
||||
}
|
||||
$this->entityManager->persist($organization);
|
||||
$this->entityManager->flush();
|
||||
$this->addFlash('success', 'Organization created successfully');
|
||||
return $this->redirectToRoute('organization_index');
|
||||
}
|
||||
return $this->render('organization/new.html.twig', [
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/{id}', name: 'show',requirements: ['id' => '\d+'], methods: ['GET'])]
|
||||
public function show(int $id, ActionService $actionService): Response
|
||||
{
|
||||
if ($this->isGranted('ROLE_ADMIN')) {
|
||||
|
|
@ -60,15 +98,7 @@ class OrganizationController extends AbstractController
|
|||
if (!$user) {
|
||||
return $this->redirectToRoute('app_login');
|
||||
}
|
||||
$roleAdmin = $this->entityManager->getRepository(Roles::class)->findOneBy(['name' => 'ADMIN']);
|
||||
$uo = $this->entityManager->getRepository(UsersOrganizations::class)->findOneBy([
|
||||
'users' => $user,
|
||||
'organization' => $id,
|
||||
'role' => $roleAdmin
|
||||
]);
|
||||
if (!$uo) {
|
||||
throw $this->createNotFoundException(self::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
//Don't care about the null pointer because if no UO found, it won't pass the previous check
|
||||
$organization = $this->entityManager->getRepository(Organizations::class)->find($id);
|
||||
$newUsers = $this->entityManager->getRepository(UsersOrganizations::class)->getLastNewActiveUsersByOrganization($organization);
|
||||
|
|
@ -80,12 +110,12 @@ class OrganizationController extends AbstractController
|
|||
$applications = $this->organizationsService->getApplicationsWithAccessStatus($organization);
|
||||
|
||||
$actions = $organization->getActions()->toArray();
|
||||
usort($actions, static function($a, $b) {
|
||||
usort($actions, static function ($a, $b) {
|
||||
return $b->getDate() <=> $a->getDate();
|
||||
});
|
||||
//get the last 10 activities
|
||||
$actions = array_slice($actions, 0, 10);
|
||||
$activities = array_map(static function($activity) use ($actionService) {
|
||||
$activities = array_map(static function ($activity) use ($actionService) {
|
||||
return [
|
||||
'date' => $activity->getDate(), // or however you access the date
|
||||
'actionType' => $activity->getActionType(),
|
||||
|
|
@ -93,7 +123,7 @@ class OrganizationController extends AbstractController
|
|||
'color' => $actionService->getActivityColor($activity->getDate())
|
||||
];
|
||||
}, $actions);
|
||||
}else{
|
||||
} else {
|
||||
throw $this->createNotFoundException(self::ACCESS_DENIED);
|
||||
}
|
||||
|
||||
|
|
@ -101,10 +131,12 @@ class OrganizationController extends AbstractController
|
|||
'organization' => $organization,
|
||||
'adminUsers' => $adminUsers,
|
||||
'newUsers' => $newUsers,
|
||||
'org' => $org[0],
|
||||
'org' => !empty($org) ? $org[0] : null,
|
||||
'applications' => $applications,
|
||||
'activities' => $activities
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ class Organizations
|
|||
private ?\DateTimeImmutable $createdAt = null;
|
||||
|
||||
#[ORM\Column(options: ['default' => false])]
|
||||
private ?bool $isDeleted = null;
|
||||
private ?bool $isDeleted = false;
|
||||
|
||||
#[ORM\Column(options: ['default' => true])]
|
||||
private ?bool $isActive = null;
|
||||
private ?bool $isActive = true;
|
||||
|
||||
/**
|
||||
* @var Collection<int, Apps>
|
||||
|
|
@ -55,6 +55,7 @@ class Organizations
|
|||
{
|
||||
$this->apps = new ArrayCollection();
|
||||
$this->actions = new ArrayCollection();
|
||||
$this->createdAt = new \DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Organizations;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class OrganizationForm extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('email', EmailType::class, ['required' => true, 'label' => 'Email*'])
|
||||
->add('name', TextType::class, ['required' => true, 'label' => 'Nom de l\'organisation*'])
|
||||
->add('address', TextType::class, ['required' => false, 'label' => 'Adresse'])
|
||||
->add('number', TextType::class, ['required' => false, 'label' => 'Numéro de téléphone'])
|
||||
->add('logoUrl', FileType::class, [
|
||||
'required' => false,
|
||||
'label' => 'Logo',
|
||||
'mapped' => true, // Important if the entity property is not directly mapped
|
||||
'attr' => ['accept' => 'image/*'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Organizations::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -408,12 +408,12 @@ readonly class UserOrganizationService
|
|||
*/
|
||||
public function findActiveUsersByOrganizations(array $organizations): array
|
||||
{
|
||||
|
||||
if (empty($organizations)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$userOrgs = $this->entityManager->getRepository(UsersOrganizations::class)->getAllActiveUserOrganizationLinks($organizations);
|
||||
|
||||
$usersByOrg = [];
|
||||
foreach ($userOrgs as $uo) {
|
||||
$org = $uo->getOrganization();
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@
|
|||
<div class="w-100 h-100 p-5 m-auto" data-controller="organization">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1>Gestion des organisations</h1>
|
||||
{# <a href="{{ path('organization_new') }}" class="btn btn-primary">Ajouter une organisation</a>#}
|
||||
<a href="{{ path('organization_new') }}" class="btn btn-primary">Ajouter une organisation</a>
|
||||
</div>
|
||||
{% if organizations|length == 0 %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center">Aucune organisation trouvée.</td>
|
||||
<td colspan="4" class="text-center">
|
||||
<a href="{{ path('organization_new') }}" class="btn btn-primary">Créer une organisation</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<table class="table align-middle shadow">
|
||||
|
|
@ -27,7 +30,7 @@
|
|||
<tr>
|
||||
<td>
|
||||
{% if organization.logoUrl %}
|
||||
<img src="{{ asset(organization.logoUrl) }}" alt="Organization logo" class="rounded-circle" style="width:40px; height:40px;">
|
||||
<img src="{{ asset('uploads/logos/' ~ organization.logoUrl) }}" alt="Organization logo" class="rounded-circle" style="width:40px; height:40px;">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ organization.name }}</td>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Ajouter une organisation{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class=" col-md-10 m-auto p-5">
|
||||
<div class="card">
|
||||
<div class="card-title shadow-sm p-3 d-flex justify-content-between align-items-center">
|
||||
<h1>Ajouter une organisation</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ path('organization_new') }}" enctype="multipart/form-data">
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form) }}
|
||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
||||
{{ form_end(form) }}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -31,7 +31,8 @@
|
|||
<div class="m-auto">
|
||||
{% include 'user/userList.html.twig' with {
|
||||
title: 'Mes utilisateurs',
|
||||
organizationId: organization.id
|
||||
organizationId: organization.id,
|
||||
empty_message: 'Aucun utilisateurs trouvé.'
|
||||
} %}
|
||||
</div>
|
||||
{# APPLICATION ROW #}
|
||||
|
|
|
|||
|
|
@ -22,45 +22,50 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if org.users|length == 0 %}
|
||||
{% if org|length == 0 %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">Aucun utilisateur trouvé.</td>
|
||||
</tr>
|
||||
{% elseif org.users|length == 0 %}
|
||||
<tr>
|
||||
<td colspan="6" class="text-center">Aucun utilisateur trouvé.</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
{% for user in org.users %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if user.users.pictureUrl %}
|
||||
<img src="{{ asset(user.users.pictureUrl) }}" alt="User profile pic"
|
||||
class="rounded-circle"
|
||||
style="width:40px; height:40px;">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ user.users.surname }}</td>
|
||||
<td>{{ user.users.name }}</td>
|
||||
<td>{{ user.users.email }}</td>
|
||||
<td>
|
||||
{% if user.is_connected %}
|
||||
<span class="badge bg-success">Actif</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">Inactif</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if organizationId is defined %}
|
||||
<a href="{{ path('user_show', {'id': user.users.id, 'organizationId': organizationId}) }}"
|
||||
class="p-3 align-middle color-primary">
|
||||
{{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ path('user_show', {'id': user.users.id}) }}"
|
||||
class="p-3 align-middle color-primary">
|
||||
{{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% for user in org.users %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if user.users.pictureUrl %}
|
||||
<img src="{{ asset(user.users.pictureUrl) }}" alt="User profile pic"
|
||||
class="rounded-circle"
|
||||
style="width:40px; height:40px;">
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ user.users.surname }}</td>
|
||||
<td>{{ user.users.name }}</td>
|
||||
<td>{{ user.users.email }}</td>
|
||||
<td>
|
||||
{% if user.is_connected %}
|
||||
<span class="badge bg-success">Actif</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">Inactif</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if organizationId is defined %}
|
||||
<a href="{{ path('user_show', {'id': user.users.id, 'organizationId': organizationId}) }}"
|
||||
class="p-3 align-middle color-primary">
|
||||
{{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }}
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{{ path('user_show', {'id': user.users.id}) }}"
|
||||
class="p-3 align-middle color-primary">
|
||||
{{ ux_icon('fa6-regular:eye', {height: '30px', width: '30px'}) }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
Loading…
Reference in New Issue