mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'issue534_bulk_reassign' into 'master'
Bulk reassign parcours See merge request Chill-Projet/chill-bundles!398
This commit is contained in:
commit
a3c3834081
@ -51,9 +51,7 @@ function loadDynamicPicker(element) {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addNewEntity(entity) {
|
addNewEntity(entity) {
|
||||||
console.log('addNewEntity', entity);
|
|
||||||
if (this.multiple) {
|
if (this.multiple) {
|
||||||
console.log('adding multiple');
|
|
||||||
if (!this.picked.some(el => {
|
if (!this.picked.some(el => {
|
||||||
return el.type === entity.type && el.id === entity.id;
|
return el.type === entity.type && el.id === entity.id;
|
||||||
})) {
|
})) {
|
||||||
@ -71,7 +69,6 @@ function loadDynamicPicker(element) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeEntity(entity) {
|
removeEntity(entity) {
|
||||||
console.log('removeEntity', entity);
|
|
||||||
this.picked = this.picked.filter(e => !(e.type === entity.type && e.id === entity.id));
|
this.picked = this.picked.filter(e => !(e.type === entity.type && e.id === entity.id));
|
||||||
input.value = JSON.stringify(this.picked);
|
input.value = JSON.stringify(this.picked);
|
||||||
},
|
},
|
||||||
@ -86,7 +83,6 @@ function loadDynamicPicker(element) {
|
|||||||
|
|
||||||
|
|
||||||
document.addEventListener('show-hide-show', function(e) {
|
document.addEventListener('show-hide-show', function(e) {
|
||||||
console.log('creation event caught')
|
|
||||||
loadDynamicPicker(e.detail.container)
|
loadDynamicPicker(e.detail.container)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -94,17 +90,14 @@ document.addEventListener('show-hide-hide', function(e) {
|
|||||||
console.log('hiding event caught')
|
console.log('hiding event caught')
|
||||||
e.detail.container.querySelectorAll('[data-module="pick-dynamic"]').forEach((el) => {
|
e.detail.container.querySelectorAll('[data-module="pick-dynamic"]').forEach((el) => {
|
||||||
let uniqId = el.dataset.uniqid;
|
let uniqId = el.dataset.uniqid;
|
||||||
console.log(uniqId);
|
|
||||||
if (appsOnPage.has(uniqId)) {
|
if (appsOnPage.has(uniqId)) {
|
||||||
appsOnPage.get(uniqId).unmount();
|
appsOnPage.get(uniqId).unmount();
|
||||||
console.log('App has been unmounted')
|
|
||||||
appsOnPage.delete(uniqId);
|
appsOnPage.delete(uniqId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function(e) {
|
document.addEventListener('DOMContentLoaded', function(e) {
|
||||||
console.log('loaded event', e)
|
|
||||||
loadDynamicPicker(document)
|
loadDynamicPicker(document)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -66,9 +66,18 @@ export default {
|
|||||||
translatedListOfTypes() {
|
translatedListOfTypes() {
|
||||||
let trans = [];
|
let trans = [];
|
||||||
this.types.forEach(t => {
|
this.types.forEach(t => {
|
||||||
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
|
if (this.$props.multiple) {
|
||||||
|
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
|
||||||
|
} else {
|
||||||
|
trans.push(appMessages.fr.pick_entity[t + '_one'].toLowerCase());
|
||||||
|
}
|
||||||
})
|
})
|
||||||
return appMessages.fr.pick_entity.modal_title + trans.join(', ');
|
|
||||||
|
if (this.$props.multiple) {
|
||||||
|
return appMessages.fr.pick_entity.modal_title + trans.join(', ');
|
||||||
|
} else {
|
||||||
|
return appMessages.fr.pick_entity.modal_title_one + trans.join(', ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -79,15 +88,10 @@ export default {
|
|||||||
);
|
);
|
||||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||||
modal.showModal = false;
|
modal.showModal = false;
|
||||||
console.log(this.picked)
|
|
||||||
},
|
},
|
||||||
removeEntity(entity) {
|
removeEntity(entity) {
|
||||||
console.log('remove entity', entity);
|
|
||||||
this.$emit('removeEntity', entity);
|
this.$emit('removeEntity', entity);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
console.log(this.picked);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -11,6 +11,10 @@ const appMessages = {
|
|||||||
user: 'Utilisateurs',
|
user: 'Utilisateurs',
|
||||||
person: 'Usagers',
|
person: 'Usagers',
|
||||||
thirdparty: 'Tiers',
|
thirdparty: 'Tiers',
|
||||||
|
modal_title_one: 'Indiquer un ',
|
||||||
|
user_one: 'Utilisateur',
|
||||||
|
thirdparty_one: 'Tiers',
|
||||||
|
person_one: 'Usager',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block pick_entity_dynamic_widget %}
|
{% block pick_entity_dynamic_widget %}
|
||||||
|
{{ form_help(form)}}
|
||||||
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
|
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
|
||||||
<div data-module="pick-dynamic" data-types="{{ form.vars['types']|json_encode }}" data-multiple="{{ form.vars['multiple'] }}" data-uniqid="{{ form.vars['uniqid'] }}"></div>
|
<div data-module="pick-dynamic" data-types="{{ form.vars['types']|json_encode }}" data-multiple="{{ form.vars['multiple'] }}" data-uniqid="{{ form.vars['uniqid'] }}"></div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -12,13 +12,18 @@ declare(strict_types=1);
|
|||||||
namespace Chill\PersonBundle\Controller;
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
use Chill\MainBundle\Repository\UserRepository;
|
use Chill\MainBundle\Repository\UserRepository;
|
||||||
use Chill\MainBundle\Templating\Entity\UserRender;
|
use Chill\MainBundle\Templating\Entity\UserRender;
|
||||||
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface;
|
use Chill\PersonBundle\Repository\AccompanyingPeriodACLAwareRepositoryInterface;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\Form\CallbackTransformer;
|
||||||
|
use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
|
||||||
use Symfony\Component\Form\FormFactoryInterface;
|
use Symfony\Component\Form\FormFactoryInterface;
|
||||||
use Symfony\Component\Form\FormInterface;
|
use Symfony\Component\Form\FormInterface;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
@ -27,11 +32,18 @@ use Symfony\Component\Routing\Annotation\Route;
|
|||||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Component\Templating\EngineInterface;
|
use Symfony\Component\Templating\EngineInterface;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotIdenticalTo;
|
||||||
|
use Symfony\Component\Validator\Constraints\NotNull;
|
||||||
|
use function is_int;
|
||||||
|
|
||||||
class ReassignAccompanyingPeriodController extends AbstractController
|
class ReassignAccompanyingPeriodController extends AbstractController
|
||||||
{
|
{
|
||||||
private AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository;
|
private AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository;
|
||||||
|
|
||||||
|
private AccompanyingPeriodRepository $courseRepository;
|
||||||
|
|
||||||
|
private EntityManagerInterface $em;
|
||||||
|
|
||||||
private EngineInterface $engine;
|
private EngineInterface $engine;
|
||||||
|
|
||||||
private FormFactoryInterface $formFactory;
|
private FormFactoryInterface $formFactory;
|
||||||
@ -44,8 +56,17 @@ class ReassignAccompanyingPeriodController extends AbstractController
|
|||||||
|
|
||||||
private UserRepository $userRepository;
|
private UserRepository $userRepository;
|
||||||
|
|
||||||
public function __construct(AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository, UserRepository $userRepository, EngineInterface $engine, FormFactoryInterface $formFactory, PaginatorFactory $paginatorFactory, Security $security, UserRender $userRender)
|
public function __construct(
|
||||||
{
|
AccompanyingPeriodACLAwareRepositoryInterface $accompanyingPeriodACLAwareRepository,
|
||||||
|
UserRepository $userRepository,
|
||||||
|
AccompanyingPeriodRepository $courseRepository,
|
||||||
|
EngineInterface $engine,
|
||||||
|
FormFactoryInterface $formFactory,
|
||||||
|
PaginatorFactory $paginatorFactory,
|
||||||
|
Security $security,
|
||||||
|
UserRender $userRender,
|
||||||
|
EntityManagerInterface $em
|
||||||
|
) {
|
||||||
$this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository;
|
$this->accompanyingPeriodACLAwareRepository = $accompanyingPeriodACLAwareRepository;
|
||||||
$this->engine = $engine;
|
$this->engine = $engine;
|
||||||
$this->formFactory = $formFactory;
|
$this->formFactory = $formFactory;
|
||||||
@ -53,6 +74,8 @@ class ReassignAccompanyingPeriodController extends AbstractController
|
|||||||
$this->security = $security;
|
$this->security = $security;
|
||||||
$this->userRepository = $userRepository;
|
$this->userRepository = $userRepository;
|
||||||
$this->userRender = $userRender;
|
$this->userRender = $userRender;
|
||||||
|
$this->courseRepository = $courseRepository;
|
||||||
|
$this->em = $em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,23 +91,55 @@ class ReassignAccompanyingPeriodController extends AbstractController
|
|||||||
|
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
$total = $this->accompanyingPeriodACLAwareRepository->countByUserOpenedAccompanyingPeriod(
|
$userFrom = $form['user']->getData();
|
||||||
$form['user']->getData()
|
|
||||||
);
|
$total = $this->accompanyingPeriodACLAwareRepository->countByUserOpenedAccompanyingPeriod($userFrom);
|
||||||
$paginator = $this->paginatorFactory->create($total);
|
$paginator = $this->paginatorFactory->create($total);
|
||||||
$periods = $this->accompanyingPeriodACLAwareRepository
|
$periods = $this->accompanyingPeriodACLAwareRepository
|
||||||
->findByUserOpenedAccompanyingPeriod(
|
->findByUserOpenedAccompanyingPeriod(
|
||||||
$form['user']->getData(),
|
$userFrom,
|
||||||
['openingDate' => 'ASC'],
|
['openingDate' => 'ASC'],
|
||||||
$paginator->getItemsPerPage(),
|
$paginator->getItemsPerPage(),
|
||||||
$paginator->getCurrentPageFirstItemNumber()
|
$paginator->getCurrentPageFirstItemNumber()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$periodIds = [];
|
||||||
|
|
||||||
|
foreach ($periods as $period) {
|
||||||
|
$periodIds[] = $period->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an array of period id's to pass into assignForm hiddenfield
|
||||||
|
$assignForm = $this->buildReassignForm($periodIds, $userFrom);
|
||||||
|
|
||||||
|
$assignForm->handleRequest($request);
|
||||||
|
|
||||||
|
if ($assignForm->isSubmitted() && $assignForm->isValid()) {
|
||||||
|
$assignPeriodIds = json_decode($assignForm->get('periods')->getData(), true);
|
||||||
|
$userTo = $assignForm->get('userTo')->getData();
|
||||||
|
$userFrom = $assignForm->get('userFrom')->getData();
|
||||||
|
|
||||||
|
foreach ($assignPeriodIds as $periodId) {
|
||||||
|
$period = $this->courseRepository->find($periodId);
|
||||||
|
|
||||||
|
if ($period->getUser() === $userFrom) {
|
||||||
|
$period->setUser($userTo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
// redirect to the first page
|
||||||
|
return $this->redirectToRoute('chill_course_list_reassign', $request->query->all());
|
||||||
|
}
|
||||||
|
|
||||||
return new Response(
|
return new Response(
|
||||||
$this->engine->render('@ChillPerson/AccompanyingPeriod/reassign_list.html.twig', [
|
$this->engine->render('@ChillPerson/AccompanyingPeriod/reassign_list.html.twig', [
|
||||||
|
'assignForm' => $assignForm->createView(),
|
||||||
|
'form' => $form->createView(),
|
||||||
'paginator' => $paginator,
|
'paginator' => $paginator,
|
||||||
'periods' => $periods,
|
'periods' => $periods,
|
||||||
'form' => $form->createView(),
|
'userFrom' => $userFrom,
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -98,17 +153,63 @@ class ReassignAccompanyingPeriodController extends AbstractController
|
|||||||
'method' => 'get', 'csrf_protection' => false, ]);
|
'method' => 'get', 'csrf_protection' => false, ]);
|
||||||
|
|
||||||
$builder
|
$builder
|
||||||
->add('user', EntityType::class, [
|
->add('user', PickUserDynamicType::class, [
|
||||||
'class' => User::class,
|
|
||||||
'choices' => $this->userRepository->findByActive(['username' => 'ASC']),
|
|
||||||
'choice_label' => function (User $u) {
|
|
||||||
return $this->userRender->renderString($u, []);
|
|
||||||
},
|
|
||||||
'multiple' => false,
|
'multiple' => false,
|
||||||
'label' => 'User',
|
'label' => 'reassign.Current user',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
|
'help' => 'reassign.Choose a user and click on "Filter" to apply',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return $builder->getForm();
|
return $builder->getForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildReassignForm(array $periodIds, ?User $userFrom): FormInterface
|
||||||
|
{
|
||||||
|
$defaultData = [
|
||||||
|
'userFrom' => $userFrom,
|
||||||
|
'periods' => json_encode($periodIds),
|
||||||
|
];
|
||||||
|
|
||||||
|
$builder = $this->formFactory->createNamedBuilder('reassign', FormType::class, $defaultData);
|
||||||
|
|
||||||
|
if (null !== $userFrom) {
|
||||||
|
$constraints = [new NotIdenticalTo(['value' => $userFrom])];
|
||||||
|
} else {
|
||||||
|
$constraints = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder
|
||||||
|
->add('periods', HiddenType::class)
|
||||||
|
->add('userFrom', HiddenType::class)
|
||||||
|
->add('userTo', PickUserDynamicType::class, [
|
||||||
|
'multiple' => false,
|
||||||
|
'label' => 'reassign.Next user',
|
||||||
|
'required' => true,
|
||||||
|
'help' => 'reassign.All periods on this list will be reassigned to this user, excepted the one you manually reassigned before',
|
||||||
|
'constraints' => [new NotNull()],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$builder->get('userFrom')->addModelTransformer(new CallbackTransformer(
|
||||||
|
static function (?User $user) {
|
||||||
|
if (null === $user) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user->getId();
|
||||||
|
},
|
||||||
|
function (?string $id) {
|
||||||
|
if (null === $id) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_int((int) $id)) {
|
||||||
|
throw new TransformationFailedException('the user id is not a numeric');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->userRepository->find((int) $id);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
return $builder->getForm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use Doctrine\Common\DataFixtures\DependentFixtureInterface;
|
|||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\Persistence\ObjectManager;
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
|
||||||
|
use function array_key_exists;
|
||||||
use function count;
|
use function count;
|
||||||
|
|
||||||
class LoadRelationships extends Fixture implements DependentFixtureInterface
|
class LoadRelationships extends Fixture implements DependentFixtureInterface
|
||||||
@ -34,7 +35,7 @@ class LoadRelationships extends Fixture implements DependentFixtureInterface
|
|||||||
$this->em = $em;
|
$this->em = $em;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDependencies()
|
public function getDependencies(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
LoadPeople::class,
|
LoadPeople::class,
|
||||||
@ -42,9 +43,11 @@ class LoadRelationships extends Fixture implements DependentFixtureInterface
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function load(ObjectManager $manager)
|
public function load(ObjectManager $manager): void
|
||||||
{
|
{
|
||||||
for ($i = 0; 15 > $i; ++$i) {
|
$existing = [];
|
||||||
|
|
||||||
|
for ($i = 0; 20 > $i; ++$i) {
|
||||||
$user = $this->getRandomUser();
|
$user = $this->getRandomUser();
|
||||||
$date = new DateTimeImmutable();
|
$date = new DateTimeImmutable();
|
||||||
$relationship = (new Relationship())
|
$relationship = (new Relationship())
|
||||||
@ -57,6 +60,17 @@ class LoadRelationships extends Fixture implements DependentFixtureInterface
|
|||||||
->setUpdatedBy($user)
|
->setUpdatedBy($user)
|
||||||
->setCreatedAt($date)
|
->setCreatedAt($date)
|
||||||
->setUpdatedAt($date);
|
->setUpdatedAt($date);
|
||||||
|
|
||||||
|
// remove the potential duplicates
|
||||||
|
$set = $relationship->getFromPerson()->getId() < $relationship->getToPerson()->getId() ?
|
||||||
|
[$relationship->getFromPerson()->getId(), $relationship->getToPerson()->getId()] :
|
||||||
|
[$relationship->getToPerson()->getId(), $relationship->getFromPerson()->getId()];
|
||||||
|
|
||||||
|
if (array_key_exists($set[0], $existing) && array_key_exists($set[1], $existing[$set[0]])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$existing[$set[0]][$existing[$set[1]]] = 1;
|
||||||
$manager->persist($relationship);
|
$manager->persist($relationship);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -873,6 +873,12 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
|||||||
AccompanyingPeriodVoter::EDIT,
|
AccompanyingPeriodVoter::EDIT,
|
||||||
AccompanyingPeriodVoter::DELETE,
|
AccompanyingPeriodVoter::DELETE,
|
||||||
],
|
],
|
||||||
|
AccompanyingPeriodVoter::REASSIGN_BULK => [
|
||||||
|
AccompanyingPeriodVoter::CONFIDENTIAL_CRUD,
|
||||||
|
],
|
||||||
|
AccompanyingPeriodVoter::TOGGLE_CONFIDENTIAL => [
|
||||||
|
AccompanyingPeriodVoter::CONFIDENTIAL_CRUD,
|
||||||
|
],
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\PersonBundle\Menu;
|
namespace Chill\PersonBundle\Menu;
|
||||||
|
|
||||||
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
use Chill\MainBundle\Routing\LocalMenuBuilderInterface;
|
||||||
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
use Knp\Menu\MenuItem;
|
use Knp\Menu\MenuItem;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
@ -64,13 +65,15 @@ class SectionMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$menu->addChild($this->translator->trans('Accompanying courses of users'), [
|
if ($this->authorizationChecker->isGranted(AccompanyingPeriodVoter::REASSIGN_BULK, null)) {
|
||||||
'route' => 'chill_course_list_reassign',
|
$menu->addChild($this->translator->trans('reassign.Bulk reassign'), [
|
||||||
])
|
'route' => 'chill_course_list_reassign',
|
||||||
->setExtras([
|
])
|
||||||
'order' => 12,
|
->setExtras([
|
||||||
'icons' => ['task'],
|
'order' => 40,
|
||||||
]);
|
'icons' => [],
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getMenuIds(): array
|
public static function getMenuIds(): array
|
||||||
|
@ -4,17 +4,19 @@
|
|||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_set_referrer') }}
|
{{ encore_entry_script_tags('mod_set_referrer') }}
|
||||||
|
{{ encore_entry_script_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('mod_set_referrer') }}
|
{{ encore_entry_link_tags('mod_set_referrer') }}
|
||||||
|
{{ encore_entry_link_tags('mod_pickentity_type') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% macro period_meta(period) %}
|
{% macro period_meta(period) %}
|
||||||
{% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_UPDATE', period) %}
|
{% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_UPDATE', period) %}
|
||||||
<div class="item-col item-meta">
|
<div class="item-col item-meta">
|
||||||
{% set job_id = null %}
|
{% set job_id = null %}
|
||||||
{% if period.job is defined %}
|
{% if period.job is defined and period.job is not null %}
|
||||||
{% set job_id = period.job.id %}
|
{% set job_id = period.job.id %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span
|
<span
|
||||||
@ -28,9 +30,9 @@
|
|||||||
|
|
||||||
|
|
||||||
{% macro period_actions(period) %}
|
{% macro period_actions(period) %}
|
||||||
{% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', period) %}
|
{% if is_granted('CHILL_PERSON_ACCOMPANYING_PERIOD_UPDATE', period) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': period.id}) }}" class="btn btn-show"></a>
|
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_edit', {'accompanying_period_id': period.id}) }}" class="btn btn-edit"></a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
@ -38,45 +40,66 @@
|
|||||||
{% import _self as m %}
|
{% import _self as m %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-10">
|
<div class="row col-10">
|
||||||
<h1>{{ block('title') }}</h1>
|
<h1>{{ block('title') }}</h1>
|
||||||
|
|
||||||
{{ form_start(form) }}
|
|
||||||
<div class="row filter-box">
|
<div class="row filter-box">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
{{ form_start(form) }}
|
||||||
{{ form_label(form.user ) }}
|
{{ form_label(form.user ) }}
|
||||||
{{ form_widget(form.user, {'attr': {'class': 'select2'}}) }}
|
{{ form_widget(form.user, {'attr': {'class': 'select2'}}) }}
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<button type="submit" class="btn btn-misc">
|
||||||
|
<i class="fa fa-filter"></i> {{ 'Filter'|trans }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{ form_end(form) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
{% if userFrom is not null %}
|
||||||
|
<div>
|
||||||
|
{{ form_start(assignForm) }}
|
||||||
|
{{ form_label(assignForm.userTo ) }}
|
||||||
|
{{ form_widget(assignForm.userTo, {'attr': {'class': 'select2'}}) }}
|
||||||
|
</div>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<button type="submit" class="btn btn-update change-icon">
|
||||||
|
{{ 'reassign.Reassign'|trans }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{ form_end(assignForm) }}
|
||||||
|
{% else %}
|
||||||
|
<div class="alert alert-info">{{ 'reassign.List periods to be able to reassign them'|trans }}</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="record_actions">
|
{% if userFrom is not null %}
|
||||||
<li>
|
|
||||||
<button type="submit" class="btn btn-save change-icon">
|
|
||||||
<i class="fa fa-filter"></i> Filtrer
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{{ form_end(form) }}
|
|
||||||
|
|
||||||
{% if form.user.vars.value is empty %}
|
|
||||||
<p class="chill-no-data-statement">{{ 'period_by_user_list.Pick a user'|trans }}</p>
|
|
||||||
{% elseif periods|length == 0 and form.user.vars.value is not empty %}
|
|
||||||
<p class="chill-no-data-statement">{{ 'period_by_user_list.Any course or no authorization to see them'|trans }}</p>
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
<p><span class="badge rounded-pill bg-primary">{{ paginator.totalItems }}</span> parcours à réassigner (calculé ce jour à {{ null|format_time('medium') }})</p>
|
<p><span class="badge rounded-pill bg-primary">{{ paginator.totalItems }}</span> parcours à réassigner (calculé ce jour à {{ null|format_time('medium') }})</p>
|
||||||
|
|
||||||
<div class="flex-table">
|
|
||||||
{% for period in periods %}
|
|
||||||
{% include '@ChillPerson/AccompanyingPeriod/_list_item.html.twig' with {'period': period,
|
|
||||||
'recordAction': m.period_actions(period), 'itemMeta': m.period_meta(period) } %}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{{ chill_pagination(paginator) }}
|
<div class="flex-table">
|
||||||
|
{% for period in periods %}
|
||||||
|
{% include '@ChillPerson/AccompanyingPeriod/_list_item.html.twig' with {'period': period,
|
||||||
|
'recordAction': m.period_actions(period), 'itemMeta': m.period_meta(period) } %}
|
||||||
|
{% else %}
|
||||||
|
{% if userFrom is same as(null) %}
|
||||||
|
<p class="chill-no-data-statement">{{ 'period_by_user_list.Pick a user'|trans }}</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="chill-no-data-statement">{{ 'period_by_user_list.Any course or no authorization to see them'|trans }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if paginator is defined %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
@ -25,6 +25,9 @@ use function in_array;
|
|||||||
|
|
||||||
class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* all the roles that are linked to an accompanying period.
|
||||||
|
*/
|
||||||
public const ALL = [
|
public const ALL = [
|
||||||
self::SEE,
|
self::SEE,
|
||||||
self::SEE_DETAILS,
|
self::SEE_DETAILS,
|
||||||
@ -37,6 +40,11 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
self::RE_OPEN_COURSE,
|
self::RE_OPEN_COURSE,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give the ability to see all confidential courses.
|
||||||
|
*/
|
||||||
|
public const CONFIDENTIAL_CRUD = 'CHILL_PERSON_ACCOMPANYING_PERIOD_CRUD_CONFIDENTIAL';
|
||||||
|
|
||||||
public const CREATE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_CREATE';
|
public const CREATE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_CREATE';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +74,11 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
*/
|
*/
|
||||||
public const RE_OPEN_COURSE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_REOPEN';
|
public const RE_OPEN_COURSE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_REOPEN';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow user to bulk reassign the courses.
|
||||||
|
*/
|
||||||
|
public const REASSIGN_BULK = 'CHILL_PERSON_ACCOMPANYING_COURSE_REASSIGN_BULK';
|
||||||
|
|
||||||
public const SEE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_SEE';
|
public const SEE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_SEE';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,7 +111,7 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
$this->security = $security;
|
$this->security = $security;
|
||||||
$this->voterHelper = $voterHelperFactory
|
$this->voterHelper = $voterHelperFactory
|
||||||
->generate(self::class)
|
->generate(self::class)
|
||||||
->addCheckFor(null, [self::CREATE])
|
->addCheckFor(null, [self::CREATE, self::REASSIGN_BULK])
|
||||||
->addCheckFor(AccompanyingPeriod::class, [self::TOGGLE_CONFIDENTIAL, ...self::ALL])
|
->addCheckFor(AccompanyingPeriod::class, [self::TOGGLE_CONFIDENTIAL, ...self::ALL])
|
||||||
->addCheckFor(Person::class, [self::SEE])
|
->addCheckFor(Person::class, [self::SEE])
|
||||||
->build();
|
->build();
|
||||||
@ -106,7 +119,17 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
|
|
||||||
public function getRoles(): array
|
public function getRoles(): array
|
||||||
{
|
{
|
||||||
return self::ALL;
|
return [
|
||||||
|
self::SEE,
|
||||||
|
self::SEE_DETAILS,
|
||||||
|
self::CONFIDENTIAL_CRUD,
|
||||||
|
self::CREATE,
|
||||||
|
self::EDIT,
|
||||||
|
self::DELETE,
|
||||||
|
self::FULL,
|
||||||
|
self::TOGGLE_CONFIDENTIAL_ALL,
|
||||||
|
self::REASSIGN_BULK,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRolesWithHierarchy(): array
|
public function getRolesWithHierarchy(): array
|
||||||
@ -116,7 +139,7 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
|
|
||||||
public function getRolesWithoutScope(): array
|
public function getRolesWithoutScope(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [self::REASSIGN_BULK];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function supports($attribute, $subject)
|
protected function supports($attribute, $subject)
|
||||||
@ -166,8 +189,11 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->voterHelper->voteOnAttribute(self::TOGGLE_CONFIDENTIAL_ALL, $subject, $token)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
// return $this->voterHelper->voteOnAttribute(self::TOGGLE_CONFIDENTIAL_ALL, $subject, $token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self::TOGGLE_INTENSITY === $attribute) {
|
if (self::TOGGLE_INTENSITY === $attribute) {
|
||||||
@ -180,6 +206,10 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
|
|
||||||
// if confidential, only the referent can see it
|
// if confidential, only the referent can see it
|
||||||
if ($subject->isConfidential()) {
|
if ($subject->isConfidential()) {
|
||||||
|
if ($this->voterHelper->voteOnAttribute(self::CONFIDENTIAL_CRUD, $subject, $token)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return $token->getUser() === $subject->getUser();
|
return $token->getUser() === $subject->getUser();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,7 +301,16 @@ CHILL_PERSON_CREATE: Ajouter des personnes
|
|||||||
CHILL_PERSON_STATS: Statistiques sur les personnes
|
CHILL_PERSON_STATS: Statistiques sur les personnes
|
||||||
CHILL_PERSON_LISTS: Liste des personnes
|
CHILL_PERSON_LISTS: Liste des personnes
|
||||||
CHILL_PERSON_DUPLICATE: Gérer les doublons de personnes
|
CHILL_PERSON_DUPLICATE: Gérer les doublons de personnes
|
||||||
CHILL_PERSON_ACCOMPANYING_PERIOD_SEE: Voir les périodes d'accompagnement
|
CHILL_PERSON_ACCOMPANYING_PERIOD_SEE: Vision simplifiée d'une période d'accompagnement
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_CONFIDENTIAL: Voir et modifier les périodes d'accompagnement confidentielles
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_DELETE: Supprimer une période d'accompagnement
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_RE_OPEN: Ré-ouvrir un parcours clotûré
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL_ALL: Modifier la confidentialité de tous les parcours
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_CREATE: Créer une période d'accompagnement
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_UPDATE: Modifier une période d'accompagnement
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_FULL: Voir les détails, créer, supprimer et mettre à jour une période d'accompagnement
|
||||||
|
CHILL_PERSON_ACCOMPANYING_COURSE_REASSIGN_BULK: Réassigner les parcours en lot
|
||||||
|
CHILL_PERSON_ACCOMPANYING_PERIOD_SEE_DETAILS: Voir les détails d'une période d'accompagnement
|
||||||
|
|
||||||
#period
|
#period
|
||||||
Period closed!: Période clôturée!
|
Period closed!: Période clôturée!
|
||||||
@ -596,3 +605,12 @@ period_by_user_list:
|
|||||||
Period by user: Parcours d'accompagnement par utilisateur
|
Period by user: Parcours d'accompagnement par utilisateur
|
||||||
Pick a user: Choisissez un utilisateur pour obtenir la liste de ses parcours
|
Pick a user: Choisissez un utilisateur pour obtenir la liste de ses parcours
|
||||||
Any course or no authorization to see them: Aucun parcours pour ce référent, ou aucun droit pour visualiser les parcours de ce référent.
|
Any course or no authorization to see them: Aucun parcours pour ce référent, ou aucun droit pour visualiser les parcours de ce référent.
|
||||||
|
|
||||||
|
reassign:
|
||||||
|
Bulk reassign: Réassigner les parcours
|
||||||
|
Current user: Parcours par référent
|
||||||
|
Next user: Nouveau référent
|
||||||
|
Choose a user and click on "Filter" to apply: Choisissez un utilisateur et cliquez sur "Filtrer" pour visualiser ses parcours
|
||||||
|
All periods on this list will be reassigned to this user, excepted the one you manually reassigned before: Tous les parcours visibles sur cette page seront assignés à cet utilisateur, sauf ceux que vous aurez assigné à un utilisateur manuellement.
|
||||||
|
Reassign: Assigner le référent
|
||||||
|
List periods to be able to reassign them: Choisissez un utilisateur et cliquez sur "Filtrer" pour visualiser ses parcours. Vous pourrez ensuite les réassigner.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user