mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-13 11:19:51 +00:00
Merge conflicts in translations.yaml resolved.
# Conflicts: # src/Bundle/ChillAsideActivityBundle/src/translations/messages.fr.yml # src/Bundle/ChillMainBundle/translations/messages.fr.yml
This commit is contained in:
commit
4c55631297
@ -7,6 +7,7 @@ charset = utf-8
|
|||||||
end_of_line = LF
|
end_of_line = LF
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
[*.{php,html,twig}]
|
[*.{php,html,twig}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
|
39
CHANGELOG.md
Normal file
39
CHANGELOG.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to
|
||||||
|
|
||||||
|
* [Semantic Versioning](https://semver.org/spec/v2.0.0.html) for stable releases;
|
||||||
|
* date versioning for test releases
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Test releases
|
||||||
|
|
||||||
|
### test release 2021-10-04
|
||||||
|
|
||||||
|
* [Household editor][UI] Update how household suggestion and addresses are picked;
|
||||||
|
* [AddAddress] Handle address suggestion;
|
||||||
|
* [CenterType][Create a person] when overriding the ACL rules, allow to show a PickCenterType
|
||||||
|
when no centers are reachable by the default ACL.
|
||||||
|
* [Household] Show comment event if no address are associated with the household;
|
||||||
|
* [Person results] Add requestor into search results:
|
||||||
|
|
||||||
|
* a badge "requestor" is shown into search results;
|
||||||
|
* periods where the person is only requestor (without participating) are also shown;
|
||||||
|
|
||||||
|
Issues:
|
||||||
|
|
||||||
|
* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/13
|
||||||
|
* https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/199
|
||||||
|
* [Person form] "accept sms" not required:
|
||||||
|
|
||||||
|
https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/37
|
||||||
|
https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/221
|
||||||
|
* On-The-Fly modale works for showing, editing and creating person and thirdparty ;
|
||||||
|
* AccompanyingCourse Resume page: list associated persons by household, see household when hover, and show on-the-fly modale when clicking on person ;
|
@ -22,6 +22,7 @@
|
|||||||
"league/csv": "^9.7.1",
|
"league/csv": "^9.7.1",
|
||||||
"nyholm/psr7": "^1.4",
|
"nyholm/psr7": "^1.4",
|
||||||
"phpoffice/phpspreadsheet": "^1.16",
|
"phpoffice/phpspreadsheet": "^1.16",
|
||||||
|
"ramsey/uuid-doctrine": "^1.7",
|
||||||
"sensio/framework-extra-bundle": "^5.5",
|
"sensio/framework-extra-bundle": "^5.5",
|
||||||
"symfony/asset": "4.*",
|
"symfony/asset": "4.*",
|
||||||
"symfony/browser-kit": "^5.2",
|
"symfony/browser-kit": "^5.2",
|
||||||
@ -29,6 +30,7 @@
|
|||||||
"symfony/expression-language": "4.*",
|
"symfony/expression-language": "4.*",
|
||||||
"symfony/form": "4.*",
|
"symfony/form": "4.*",
|
||||||
"symfony/intl": "4.*",
|
"symfony/intl": "4.*",
|
||||||
|
"symfony/mime": "^4 || ^5",
|
||||||
"symfony/monolog-bundle": "^3.5",
|
"symfony/monolog-bundle": "^3.5",
|
||||||
"symfony/security-bundle": "4.*",
|
"symfony/security-bundle": "4.*",
|
||||||
"symfony/serializer": "^5.2",
|
"symfony/serializer": "^5.2",
|
||||||
|
@ -32,7 +32,10 @@
|
|||||||
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
|
<exclude>src/Bundle/ChillPersonBundle/Tests/Controller/PersonDuplicateControllerViewTest.php</exclude>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
<testsuite name="AsideActivityBundle">
|
<testsuite name="AsideActivityBundle">
|
||||||
<directory suffix="Test.php">src/Bundle/ChillAsideActivityBundle/src/Tests/</directory>
|
<directory suffix="Test.php">src/Bundle/ChillAsideActivityBundle/src/Tests/</directory>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite name="CalendarBundle">
|
||||||
|
<directory suffix="Test.php">src/Bundle/ChillCalendarBundle/Tests/</directory>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
|
||||||
|
Binary file not shown.
@ -43,7 +43,7 @@ crud:
|
|||||||
Create a new aside activity type: Nouvelle categorie d'activité annexe
|
Create a new aside activity type: Nouvelle categorie d'activité annexe
|
||||||
Back to the list: Retour à la liste
|
Back to the list: Retour à la liste
|
||||||
Choose the duration: Choisir la durée
|
Choose the duration: Choisir la durée
|
||||||
Choose a category: Choisir un categorie
|
Choose a category: Choisir une catégorie
|
||||||
Is active: Actif
|
Is active: Actif
|
||||||
Agent: Utilisateur
|
Agent: Utilisateur
|
||||||
date: Date
|
date: Date
|
||||||
@ -153,7 +153,7 @@ Are you sure you want to remove the aside activity concerning "%name%" ?: Êtes-
|
|||||||
The activity has been successfully removed.: L'activité a été supprimée.
|
The activity has been successfully removed.: L'activité a été supprimée.
|
||||||
|
|
||||||
#Menu
|
#Menu
|
||||||
Create an aside activity: "Creér une activité annexe"
|
Create an aside activity: "Créer une activité annexe"
|
||||||
Aside activity configuration menu: "Menu de configuration des activités annexes"
|
Aside activity configuration menu: "Menu de configuration des activités annexes"
|
||||||
Aside activity configuration: "Configuration des activités annexes"
|
Aside activity configuration: "Configuration des activités annexes"
|
||||||
Phonecall: "Appel téléphonique"
|
Phonecall: "Appel téléphonique"
|
||||||
|
@ -29,17 +29,19 @@ class ListenToActivityCreate
|
|||||||
$activityData = $request->query->get('activityData');
|
$activityData = $request->query->get('activityData');
|
||||||
if (array_key_exists('calendarId', $activityData)) {
|
if (array_key_exists('calendarId', $activityData)) {
|
||||||
$calendarId = $activityData['calendarId'];
|
$calendarId = $activityData['calendarId'];
|
||||||
|
|
||||||
|
// Attach the activity to the calendar
|
||||||
|
$em = $event->getObjectManager();
|
||||||
|
|
||||||
|
$calendar = $em->getRepository(\Chill\CalendarBundle\Entity\Calendar::class)->find($calendarId);
|
||||||
|
$calendar->setActivity($activity);
|
||||||
|
|
||||||
|
$em->persist($calendar);
|
||||||
|
$em->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach the activity to the calendar
|
|
||||||
$em = $event->getObjectManager();
|
|
||||||
|
|
||||||
$calendar = $em->getRepository(\Chill\CalendarBundle\Entity\Calendar::class)->find($calendarId);
|
|
||||||
$calendar->setActivity($activity);
|
|
||||||
|
|
||||||
$em->persist($calendar);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class AccompanyingCourseMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
'routeParameters' => [
|
'routeParameters' => [
|
||||||
'accompanying_period_id' => $period->getId(),
|
'accompanying_period_id' => $period->getId(),
|
||||||
]])
|
]])
|
||||||
->setExtras(['order' => 41]);
|
->setExtras(['order' => 35]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Chill\CalendarBundle\Tests\Controller;
|
namespace Chill\CalendarBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
@ -9,58 +11,63 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|||||||
class CalendarControllerTest extends WebTestCase
|
class CalendarControllerTest extends WebTestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
|
||||||
* Setup before the first test of this class (see phpunit doc)
|
|
||||||
*/
|
|
||||||
public static function setUpBeforeClass()
|
|
||||||
{
|
|
||||||
static::bootKernel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup before each test method (see phpunit doc)
|
* Setup before each test method (see phpunit doc)
|
||||||
*/
|
*/
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
|
static::bootKernel();
|
||||||
$this->client = static::createClient(array(), array(
|
$this->client = static::createClient(array(), array(
|
||||||
'PHP_AUTH_USER' => 'center a_social',
|
'PHP_AUTH_USER' => 'center a_social',
|
||||||
'PHP_AUTH_PW' => 'password',
|
'PHP_AUTH_PW' => 'password',
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getAccompanyingPeriodFromFixtures(): AccompanyingPeriod
|
public function provideAccompanyingPeriod(): iterable
|
||||||
{
|
{
|
||||||
$em = static::$kernel->getContainer()
|
static::bootKernel();
|
||||||
->get('doctrine.orm.entity_manager');
|
$em= static::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
$accompanying_period = $em->getRepository('ChillPersonBundle:AccompanyingPeriod')->find(1);
|
$nb = $em->createQueryBuilder()
|
||||||
|
->from(AccompanyingPeriod::class, 'ac')
|
||||||
|
->select('COUNT(ac) AS nb')
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
;
|
||||||
|
|
||||||
if ($accompanying_period === NULL) {
|
yield [ $em->createQueryBuilder()
|
||||||
throw new \RuntimeException("We need an accompanying course with id = 1. Did you add fixtures ?");
|
->from(AccompanyingPeriod::class, 'ac')
|
||||||
}
|
->select('ac.id')
|
||||||
|
->setFirstResult(\random_int(0, $nb))
|
||||||
return $accompanying_period;
|
->setMaxResults(1)
|
||||||
|
->getQuery()
|
||||||
|
->getSingleScalarResult()
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testList()
|
/**
|
||||||
|
* @dataProvider provideAccompanyingPeriod
|
||||||
|
*/
|
||||||
|
public function testList(int $accompanyingPeriodId)
|
||||||
{
|
{
|
||||||
$this->client->request(
|
$this->client->request(
|
||||||
Request::METHOD_GET,
|
Request::METHOD_GET,
|
||||||
sprintf('/fr/calendar/?accompanying_period_id=%d', $this->getAccompanyingPeriodFromFixtures()->getId())
|
sprintf('/fr/calendar/calendar/?accompanying_period_id=%d', $accompanyingPeriodId)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
public function testNew()
|
* @dataProvider provideAccompanyingPeriod
|
||||||
|
*/
|
||||||
|
public function testNew(int $accompanyingPeriodId)
|
||||||
{
|
{
|
||||||
$this->client->request(
|
$this->client->request(
|
||||||
Request::METHOD_GET,
|
Request::METHOD_GET,
|
||||||
sprintf('/fr/calendar/new?accompanying_period_id=%d', $this->getAccompanyingPeriodFromFixtures()->getId())
|
sprintf('/fr/calendar/calendar/new?accompanying_period_id=%d', $accompanyingPeriodId)
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ class DocGeneratorTemplateController extends AbstractController
|
|||||||
$em->flush();
|
$em->flush();
|
||||||
|
|
||||||
return $this->redirectToRoute('chill_wopi_file_edit', [
|
return $this->redirectToRoute('chill_wopi_file_edit', [
|
||||||
'fileId' => $genDocName,
|
'fileId' => $storedObject->getUuid(),
|
||||||
'returnPath' => $request->query->get('returnPath', "/")
|
'returnPath' => $request->query->get('returnPath', "/")
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,199 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
|
||||||
|
use Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Privacy\PrivacyEvent;
|
||||||
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class DocumentAccompanyingCourseController
|
||||||
|
*
|
||||||
|
* @package Chill\DocStoreBundle\Controller
|
||||||
|
* @Route("/{_locale}/parcours/{course}/document")
|
||||||
|
*
|
||||||
|
* TODO faire un controller abstrait ?
|
||||||
|
*/
|
||||||
|
class DocumentAccompanyingCourseController extends AbstractController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var TranslatorInterface
|
||||||
|
*/
|
||||||
|
protected $translator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var EventDispatcherInterface
|
||||||
|
*/
|
||||||
|
protected $eventDispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AuthorizationHelper
|
||||||
|
*/
|
||||||
|
protected $authorizationHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DocumentAccompanyingCourseController constructor.
|
||||||
|
|
||||||
|
* @param TranslatorInterface $translator
|
||||||
|
* @param EventDispatcherInterface $eventDispatcher
|
||||||
|
* @param AuthorizationHelper $authorizationHelper
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
EventDispatcherInterface $eventDispatcher,
|
||||||
|
AuthorizationHelper $authorizationHelper
|
||||||
|
) {
|
||||||
|
$this->translator = $translator;
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/", name="accompanying_course_document_index", methods="GET")
|
||||||
|
*/
|
||||||
|
public function index(AccompanyingPeriod $course): Response
|
||||||
|
{
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
if ($course === NULL) {
|
||||||
|
throw $this->createNotFoundException('Accompanying period not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $course);
|
||||||
|
|
||||||
|
$documents = $em
|
||||||
|
->getRepository("ChillDocStoreBundle:AccompanyingCourseDocument")
|
||||||
|
->findBy(
|
||||||
|
['course' => $course],
|
||||||
|
['date' => 'DESC']
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->render(
|
||||||
|
'ChillDocStoreBundle:AccompanyingCourseDocument:index.html.twig',
|
||||||
|
[
|
||||||
|
'documents' => $documents,
|
||||||
|
'accompanyingCourse' => $course
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/new", name="accompanying_course_document_new", methods="GET|POST")
|
||||||
|
*/
|
||||||
|
public function new(Request $request, AccompanyingPeriod $course): Response
|
||||||
|
{
|
||||||
|
if ($course === NULL) {
|
||||||
|
throw $this->createNotFoundException('Accompanying period not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $course);
|
||||||
|
|
||||||
|
$document = new AccompanyingCourseDocument();
|
||||||
|
$document->setUser($this->getUser());
|
||||||
|
$document->setCourse($course);
|
||||||
|
$document->setDate(new \DateTime('Now'));
|
||||||
|
|
||||||
|
$form = $this->createForm(AccompanyingCourseDocumentType::class, $document);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$this->denyAccessUnlessGranted(
|
||||||
|
'CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', $document,
|
||||||
|
'creation of this activity not allowed');
|
||||||
|
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$em->persist($document);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator->trans("The document is successfully registered"));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('accompanying_course_document_index', ['course' => $course->getId()]);
|
||||||
|
} elseif ($form->isSubmitted() and !$form->isValid()) {
|
||||||
|
$this->addFlash('error', $this->translator->trans("This form contains errors"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('ChillDocStoreBundle:AccompanyingCourseDocument:new.html.twig', [
|
||||||
|
'document' => $document,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'accompanyingCourse' => $course,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{id}", name="accompanying_course_document_show", methods="GET")
|
||||||
|
*/
|
||||||
|
public function show(AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', $course);
|
||||||
|
$this->denyAccessUnlessGranted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE', $document);
|
||||||
|
|
||||||
|
return $this->render(
|
||||||
|
'ChillDocStoreBundle:AccompanyingCourseDocument:show.html.twig',
|
||||||
|
['document' => $document, 'accompanyingCourse' => $course]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{id}/edit", name="accompanying_course_document_edit", methods="GET|POST")
|
||||||
|
*/
|
||||||
|
public function edit(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', $course);
|
||||||
|
$this->denyAccessUnlessGranted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', $document);
|
||||||
|
|
||||||
|
$document->setUser($this->getUser());
|
||||||
|
$document->setDate(new \DateTime('Now'));
|
||||||
|
|
||||||
|
$form = $this->createForm(
|
||||||
|
AccompanyingCourseDocumentType::class, $document);
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator->trans("The document is successfully updated"));
|
||||||
|
|
||||||
|
return $this->redirectToRoute(
|
||||||
|
'accompanying_course_document_edit',
|
||||||
|
['id' => $document->getId(), 'course' => $course->getId()]);
|
||||||
|
|
||||||
|
} elseif ($form->isSubmitted() and !$form->isValid()) {
|
||||||
|
$this->addFlash('error', $this->translator->trans("This form contains errors"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render(
|
||||||
|
'ChillDocStoreBundle:AccompanyingCourseDocument:edit.html.twig',
|
||||||
|
[
|
||||||
|
'document' => $document,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'accompanyingCourse' => $course,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/{id}", name="accompanying_course_document_delete", methods="DELETE")
|
||||||
|
*/
|
||||||
|
public function delete(Request $request, AccompanyingPeriod $course, AccompanyingCourseDocument $document): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('CHILL_PERSON_ACCOMPANYING_PERIOD_SEE', $course);
|
||||||
|
$this->denyAccessUnlessGranted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', $document);
|
||||||
|
|
||||||
|
if ($this->isCsrfTokenValid('delete'.$document->getId(), $request->request->get('_token'))) {
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
$em->remove($document);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->redirectToRoute(
|
||||||
|
'accompanying_course_document_index', ['accompanyingCourse' => $course->getId()]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Entity;
|
||||||
|
|
||||||
|
use Chill\DocStoreBundle\Entity\Document;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity()
|
||||||
|
* @ORM\Table("chill_doc.accompanyingcourse_document")
|
||||||
|
*/
|
||||||
|
class AccompanyingCourseDocument extends Document
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
|
||||||
|
* @ORM\JoinColumn(nullable=false)
|
||||||
|
*/
|
||||||
|
private ?AccompanyingPeriod $course = null;
|
||||||
|
|
||||||
|
public function getCourse(): ?AccompanyingPeriod
|
||||||
|
{
|
||||||
|
return $this->course;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCourse(?AccompanyingPeriod $course): self
|
||||||
|
{
|
||||||
|
$this->course = $course;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,10 @@ namespace Chill\DocStoreBundle\Entity;
|
|||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface;
|
use ChampsLibres\AsyncUploaderBundle\Model\AsyncFileInterface;
|
||||||
use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists;
|
use ChampsLibres\AsyncUploaderBundle\Validator\Constraints\AsyncFileExists;
|
||||||
|
use ChampsLibres\WopiLib\Contract\Entity\Document;
|
||||||
use DateTimeInterface;
|
use DateTimeInterface;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
use Ramsey\Uuid\UuidInterface;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,7 +22,7 @@ use Symfony\Component\Serializer\Annotation as Serializer;
|
|||||||
* message="The file is not stored properly"
|
* message="The file is not stored properly"
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
class StoredObject implements AsyncFileInterface
|
class StoredObject implements AsyncFileInterface, Document
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @ORM\Id()
|
* @ORM\Id()
|
||||||
@ -47,6 +50,12 @@ class StoredObject implements AsyncFileInterface
|
|||||||
*/
|
*/
|
||||||
private array $iv = [];
|
private array $iv = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="uuid", unique=true)
|
||||||
|
* @Serializer\Groups({"read"})
|
||||||
|
*/
|
||||||
|
private UuidInterface $uuid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="datetime", name="creation_date")
|
* @ORM\Column(type="datetime", name="creation_date")
|
||||||
* @Serializer\Groups({"read"})
|
* @Serializer\Groups({"read"})
|
||||||
@ -68,6 +77,7 @@ class StoredObject implements AsyncFileInterface
|
|||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->creationDate = new \DateTime();
|
$this->creationDate = new \DateTime();
|
||||||
|
$this->uuid = Uuid::uuid4();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getId()
|
public function getId()
|
||||||
@ -155,5 +165,13 @@ class StoredObject implements AsyncFileInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUuid(): UuidInterface
|
||||||
|
{
|
||||||
|
return $this->uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getWopiDocId(): string
|
||||||
|
{
|
||||||
|
return (string) $this->uuid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Repository;
|
||||||
|
|
||||||
|
use App\Entity\AccompanyingCourseDocument;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @method AccompanyingCourseDocument|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method AccompanyingCourseDocument|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method AccompanyingCourseDocument[] findAll()
|
||||||
|
* @method AccompanyingCourseDocument[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class AccompanyingCourseDocumentRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, AccompanyingCourseDocument::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return AccompanyingCourseDocument[] Returns an array of AccompanyingCourseDocument objects
|
||||||
|
// */
|
||||||
|
/*
|
||||||
|
public function findByExampleField($value)
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('a')
|
||||||
|
->andWhere('a.exampleField = :val')
|
||||||
|
->setParameter('val', $value)
|
||||||
|
->orderBy('a.id', 'ASC')
|
||||||
|
->setMaxResults(10)
|
||||||
|
->getQuery()
|
||||||
|
->getResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
public function findOneBySomeField($value): ?AccompanyingCourseDocument
|
||||||
|
{
|
||||||
|
return $this->createQueryBuilder('a')
|
||||||
|
->andWhere('a.exampleField = :val')
|
||||||
|
->setParameter('val', $value)
|
||||||
|
->getQuery()
|
||||||
|
->getOneOrNullResult()
|
||||||
|
;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Form;
|
||||||
|
|
||||||
|
|
||||||
|
use Chill\DocStoreBundle\Entity\Document;
|
||||||
|
use Chill\DocStoreBundle\Entity\PersonDocument;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
|
use Doctrine\Persistence\ObjectManager;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||||
|
use Chill\MainBundle\Form\Type\ChillDateType;
|
||||||
|
use Chill\MainBundle\Form\Type\ScopePickerType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||||
|
|
||||||
|
|
||||||
|
class AccompanyingCourseDocumentType extends AbstractType
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* the user running this form
|
||||||
|
*
|
||||||
|
* @var User
|
||||||
|
*/
|
||||||
|
protected $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var AuthorizationHelper
|
||||||
|
*/
|
||||||
|
protected $authorizationHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var ObjectManager
|
||||||
|
*/
|
||||||
|
protected $om;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @var TranslatableStringHelper
|
||||||
|
*/
|
||||||
|
protected $translatableStringHelper;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
TranslatableStringHelper $translatableStringHelper
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->add('title', TextType::class)
|
||||||
|
->add('description', ChillTextareaType::class, [
|
||||||
|
'required' => false
|
||||||
|
])
|
||||||
|
->add('object', StoredObjectType::class, [
|
||||||
|
'error_bubbling' => true
|
||||||
|
])
|
||||||
|
->add('date', ChillDateType::class)
|
||||||
|
//TODO : adapt to using AccompanyingCourseDocument categories. Currently there are none...
|
||||||
|
->add('category', EntityType::class, array(
|
||||||
|
'placeholder' => 'Choose a document category',
|
||||||
|
'class' => 'ChillDocStoreBundle:DocumentCategory',
|
||||||
|
'query_builder' => function (EntityRepository $er) {
|
||||||
|
return $er->createQueryBuilder('c')
|
||||||
|
->where('c.documentClass = :docClass')
|
||||||
|
->setParameter('docClass', PersonDocument::class);
|
||||||
|
},
|
||||||
|
'choice_label' => function ($entity = null) {
|
||||||
|
return $entity ? $this->translatableStringHelper->localize($entity->getName()) : '';
|
||||||
|
},
|
||||||
|
))
|
||||||
|
;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Document::class,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// $resolver->setRequired(['role', 'center'])
|
||||||
|
// ->setAllowedTypes('role', [ \Symfony\Component\Security\Core\Role\Role::class ])
|
||||||
|
// ->setAllowedTypes('center', [ \Chill\MainBundle\Entity\Center::class ])
|
||||||
|
// ;
|
||||||
|
}
|
||||||
|
}
|
@ -50,6 +50,9 @@ class MenuBuilder implements LocalMenuBuilderInterface
|
|||||||
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
{
|
{
|
||||||
switch($menuId) {
|
switch($menuId) {
|
||||||
|
case 'accompanyingCourse':
|
||||||
|
$this->buildMenuAccompanyingCourse($menu, $parameters);
|
||||||
|
break;
|
||||||
case 'person':
|
case 'person':
|
||||||
$this->buildMenuPerson($menu, $parameters);
|
$this->buildMenuPerson($menu, $parameters);
|
||||||
break;
|
break;
|
||||||
@ -80,8 +83,25 @@ class MenuBuilder implements LocalMenuBuilderInterface
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function buildMenuAccompanyingCourse(MenuItem $menu, array $parameters){
|
||||||
|
$course = $parameters['accompanyingCourse'];
|
||||||
|
// $user = $this->tokenStorage->getToken()->getUser();
|
||||||
|
|
||||||
|
//TODO : add condition to check user rights?
|
||||||
|
|
||||||
|
$menu->addChild($this->translator->trans('Documents'), [
|
||||||
|
'route' => 'accompanying_course_document_index',
|
||||||
|
'routeParameters' => [
|
||||||
|
'course' => $course->getId()
|
||||||
|
]
|
||||||
|
])
|
||||||
|
->setExtras([
|
||||||
|
'order'=> 400
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getMenuIds(): array
|
public static function getMenuIds(): array
|
||||||
{
|
{
|
||||||
return [ 'person' ];
|
return [ 'person', 'accompanyingCourse' ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
<form method="post" action="{{ path('accompanying_course_document_delete', {'id': document.id, 'course': course.id}) }}" onsubmit="return confirm('Are you sure you want to delete this item?');">
|
||||||
|
<input type="hidden" name="_method" value="DELETE">
|
||||||
|
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ document.id) }}">
|
||||||
|
<button class="btn btn-delete">{{ 'Delete' | trans }}</button>
|
||||||
|
</form>
|
@ -0,0 +1,45 @@
|
|||||||
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{# {{ 'Editing document for %name%'|trans({ '%name%': accompanyingCourse|chill_entity_render_string } ) }} #}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{{ 'Edit Document' | trans }}</h1>
|
||||||
|
|
||||||
|
{{ form_errors(form) }}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.title) }}
|
||||||
|
{{ form_row(form.date) }}
|
||||||
|
{{ form_row(form.category) }}
|
||||||
|
{{ form_row(form.description) }}
|
||||||
|
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="cancel">
|
||||||
|
<a href="{{ path('accompanying_course_document_index', {'course': accompanyingCourse.id}) }}" class="btn btn-cancel">
|
||||||
|
{{ 'Back to the list' | trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="edit">
|
||||||
|
<button class="btn btn-edit">{{ 'Edit'|trans }}</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_script_tags('mod_async_upload') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ encore_entry_link_tags('mod_async_upload') }}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,70 @@
|
|||||||
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
|
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{{ 'Documents' }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_script_tags('mod_async_upload') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ 'Documents' }}</h1>
|
||||||
|
|
||||||
|
<table class="table table-bordered border-dark table-striped">
|
||||||
|
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ 'Title' | trans }}</th>
|
||||||
|
<th>{{ 'Category'|trans }}</th>
|
||||||
|
<th>{{ 'Actions' | trans }}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for document in documents %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ document.title }}</td>
|
||||||
|
<td>{{ document.category.name|localize_translatable_string }}</td>
|
||||||
|
<td>
|
||||||
|
<ul class="record_actions">
|
||||||
|
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
|
||||||
|
<li>
|
||||||
|
{{ m.download_button(document.object, document.title) }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('accompanying_course_document_show', {'course': accompanyingCourse.id, 'id': document.id}) }}" class="btn btn-show"></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('accompanying_course_document_edit', {'course': accompanyingCourse.id, 'id': document.id }) }}" class="btn btn-update"></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="9" style="text-align:center;">
|
||||||
|
<span class="chill-no-data-statement">{{ 'Any document found'|trans }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', accompanyingCourse) %}
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="create">
|
||||||
|
<a href="{{ path('accompanying_course_document_new', {'course': accompanyingCourse.id}) }}" class="btn btn-create">
|
||||||
|
{{ 'Create new document' | trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,46 @@
|
|||||||
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{# {{ 'New document for %name%'|trans({ '%name%': accompanyingCourse|chill_entity_render_string } ) }} #}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{# <h1>{{ 'New document for %name%'|trans({ '%name%': accompanyingCourse|chill_entity_render_string } ) }}</h1> #}
|
||||||
|
|
||||||
|
|
||||||
|
{{ form_errors(form) }}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.title) }}
|
||||||
|
{{ form_row(form.date) }}
|
||||||
|
{{ form_row(form.category) }}
|
||||||
|
{# {{ form_row(form.scope) }} #}
|
||||||
|
{{ form_row(form.description) }}
|
||||||
|
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="cancel">
|
||||||
|
<a href="{{ path('accompanying_course_document_index', {'course': accompanyingCourse.id}) }}" class="btn btn-cancel">
|
||||||
|
{{ 'Back to the list' | trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="create">
|
||||||
|
<button class="btn btn-create">{{ 'Create'|trans }}</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{ form_end(form) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_script_tags('mod_async_upload') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{{ encore_entry_link_tags('mod_async_upload') }}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,59 @@
|
|||||||
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
|
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{# {{ 'Detail of document of %name%'|trans({ '%name%': accompanyingCourse|chill_entity_render_string } ) }} #}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block js %}
|
||||||
|
{{ parent() }}
|
||||||
|
{{ encore_entry_script_tags('mod_async_upload') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>{{ 'Document %title%' | trans({ '%title%': document.title }) }}</h1>
|
||||||
|
|
||||||
|
<dl class="chill_view_data">
|
||||||
|
<dt>{{ 'Title'|trans }}</dt>
|
||||||
|
<dd>{{ document.title }}</dd>
|
||||||
|
|
||||||
|
<dt>{{ 'Category'|trans }}</dt>
|
||||||
|
<dd>{{ document.category.name|localize_translatable_string }}</dd>
|
||||||
|
|
||||||
|
<dt>{{ 'Description' | trans }}</dt>
|
||||||
|
<dd>
|
||||||
|
{% if document.description is empty %}
|
||||||
|
<span class="chill-no-data-statement">{{ 'Any description'|trans }}</span>
|
||||||
|
{% else %}
|
||||||
|
<blockquote class="chill-user-quote">
|
||||||
|
{{ document.description|chill_markdown_to_html }}
|
||||||
|
</blockquote>
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="cancel">
|
||||||
|
<a href="{{ path('accompanying_course_document_index', {'course': accompanyingCourse.id}) }}" class="btn btn-cancel">
|
||||||
|
{{ 'Back to the list' | trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
{{ m.download_button(document.object, document.title) }}
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('accompanying_course_document_edit', {'id': document.id, 'course': accompanyingCourse.id}) }}" class="btn btn-edit">
|
||||||
|
{{ 'Edit' | trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -21,63 +21,68 @@
|
|||||||
|
|
||||||
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
|
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
|
||||||
|
|
||||||
{% block title %}{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %}
|
{% block title %}
|
||||||
|
{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ encore_entry_script_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block personcontent %}
|
{% block personcontent %}
|
||||||
<h1>{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}</h1>
|
<h1>{{ 'Documents for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}</h1>
|
||||||
|
|
||||||
<table class="table">
|
<table class="table table-bordered border-dark table-striped">
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{{ 'Title' | trans }}</th>
|
|
||||||
<th>{{ 'Category'|trans }}</th>
|
|
||||||
<th>{{ 'Circle' | trans }}</th>
|
|
||||||
<th>{{ 'Actions' | trans }}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for document in documents %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ document.title }}</td>
|
|
||||||
<td>{{ document.category.name|localize_translatable_string }}</td>
|
|
||||||
<td>{{ document.scope.name|localize_translatable_string }}</td>
|
|
||||||
<td>
|
|
||||||
<ul class="record_actions">
|
|
||||||
{% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
|
|
||||||
<li>
|
|
||||||
{{ m.download_button(document.object, document.title) }}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="9" style="text-align:center;"><span class="chill-no-data-statement">{{ 'Any document found'|trans }}</span></td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% if is_granted('CHILL_PERSON_DOCUMENT_CREATE', person) %}
|
<thead>
|
||||||
<ul class="record_actions">
|
<tr>
|
||||||
<li class="create">
|
<th>{{ 'Title' | trans }}</th>
|
||||||
<a href="{{ path('person_document_new', {'person': person.id}) }}" class="btn btn-create">
|
<th>{{ 'Category'|trans }}</th>
|
||||||
{{ 'Create new document' | trans }}
|
<th>{{ 'Circle' | trans }}</th>
|
||||||
</a>
|
<th>{{ 'Actions' | trans }}</th>
|
||||||
</li>
|
</tr>
|
||||||
</ul>
|
</thead>
|
||||||
{% endif %}
|
<tbody>
|
||||||
|
{% for document in documents %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ document.title }}</td>
|
||||||
|
<td>{{ document.category.name|localize_translatable_string }}</td>
|
||||||
|
<td>{{ document.scope.name|localize_translatable_string }}</td>
|
||||||
|
<td>
|
||||||
|
<ul class="record_actions">
|
||||||
|
{% if is_granted('CHILL_PERSON_DOCUMENT_SEE_DETAILS', document) %}
|
||||||
|
<li>
|
||||||
|
{{ m.download_button(document.object, document.title) }}
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('person_document_show', {'person': person.id, 'id': document.id}) }}" class="btn btn-show"></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if is_granted('CHILL_PERSON_DOCUMENT_UPDATE', document) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ path('person_document_edit', {'person': person.id, 'id': document.id}) }}" class="btn btn-update"></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="9" style="text-align:center;">
|
||||||
|
<span class="chill-no-data-statement">{{ 'Any document found'|trans }}</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% if is_granted('CHILL_PERSON_DOCUMENT_CREATE', person) %}
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="create">
|
||||||
|
<a href="{{ path('person_document_new', {'person': person.id}) }}" class="btn btn-create">
|
||||||
|
{{ 'Create new document' | trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -18,39 +18,41 @@
|
|||||||
|
|
||||||
{% set activeRouteKey = '' %}
|
{% set activeRouteKey = '' %}
|
||||||
|
|
||||||
{% block title %}{{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}{% endblock %}
|
{% block title %}
|
||||||
|
{{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block personcontent %}
|
{% block personcontent %}
|
||||||
<h1>{{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}</h1>
|
<h1>{{ 'New document for %name%'|trans({ '%name%': person|chill_entity_render_string } ) }}</h1>
|
||||||
|
|
||||||
{{ form_errors(form) }}
|
{{ form_errors(form) }}
|
||||||
|
|
||||||
{{ form_start(form) }}
|
{{ form_start(form) }}
|
||||||
|
|
||||||
{{ form_row(form.title) }}
|
{{ form_row(form.title) }}
|
||||||
{{ form_row(form.date) }}
|
{{ form_row(form.date) }}
|
||||||
{{ form_row(form.category) }}
|
{{ form_row(form.category) }}
|
||||||
{{ form_row(form.scope) }}
|
{{ form_row(form.scope) }}
|
||||||
{{ form_row(form.description) }}
|
{{ form_row(form.description) }}
|
||||||
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
|
{{ form_row(form.object, { 'label': 'Document', 'existing': document.object }) }}
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li class="cancel">
|
<li class="cancel">
|
||||||
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
|
<a href="{{ path('person_document_index', {'person': person.id}) }}" class="btn btn-cancel">
|
||||||
{{ 'Back to the list' | trans }}
|
{{ 'Back to the list' | trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="create">
|
<li class="create">
|
||||||
<button class="btn btn-create">{{ 'Create'|trans }}</button>
|
<button class="btn btn-create">{{ 'Create'|trans }}</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{{ form_end(form) }}
|
{{ form_end(form) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block js %}
|
{% block js %}
|
||||||
{{ encore_entry_script_tags('mod_async_upload') }}
|
{{ encore_entry_script_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{{ encore_entry_link_tags('mod_async_upload') }}
|
{{ encore_entry_link_tags('mod_async_upload') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\DocStoreBundle\Security\Authorization;
|
||||||
|
|
||||||
|
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AbstractChillVoter;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
|
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||||
|
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class AccompanyingCourseDocumentVoter extends AbstractChillVoter implements ProvideRoleHierarchyInterface
|
||||||
|
{
|
||||||
|
const CREATE = 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE';
|
||||||
|
const SEE = 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE';
|
||||||
|
const SEE_DETAILS = 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS';
|
||||||
|
const UPDATE = 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE';
|
||||||
|
const DELETE = 'CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AuthorizationHelper
|
||||||
|
*/
|
||||||
|
protected $authorizationHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var AccessDecisionManagerInterface
|
||||||
|
*/
|
||||||
|
protected $accessDecisionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
AccessDecisionManagerInterface $accessDecisionManager,
|
||||||
|
AuthorizationHelper $authorizationHelper,
|
||||||
|
LoggerInterface $logger
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->accessDecisionManager = $accessDecisionManager;
|
||||||
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getRoles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
self::CREATE,
|
||||||
|
self::SEE,
|
||||||
|
self::SEE_DETAILS,
|
||||||
|
self::UPDATE,
|
||||||
|
self::DELETE
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function supports($attribute, $subject)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (\in_array($attribute, $this->getRoles())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getRolesWithoutScope()
|
||||||
|
{
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getRolesWithHierarchy()
|
||||||
|
{
|
||||||
|
return ['accompanyingCourseDocument' => $this->getRoles() ];
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,12 @@
|
|||||||
"description": "A Chill bundle to store documents",
|
"description": "A Chill bundle to store documents",
|
||||||
"type": "symfony-bundle",
|
"type": "symfony-bundle",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": { "Chill\\DocStoreBundle\\" : "" }
|
"psr-4": {
|
||||||
|
"Chill\\DocStoreBundle\\": ""
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"symfony/mime": "^4 || ^5"
|
||||||
},
|
},
|
||||||
"license": "AGPL-3.0"
|
"license": "AGPL-3.0"
|
||||||
}
|
}
|
||||||
|
@ -2,31 +2,28 @@ parameters:
|
|||||||
# cl_chill_person.example.class: Chill\PersonBundle\Example
|
# cl_chill_person.example.class: Chill\PersonBundle\Example
|
||||||
|
|
||||||
services:
|
services:
|
||||||
Chill\DocStoreBundle\Repository\:
|
Chill\DocStoreBundle\Repository\:
|
||||||
autowire: true
|
autowire: true
|
||||||
autoconfigure: true
|
autoconfigure: true
|
||||||
resource: '../Repository/'
|
resource: "../Repository/"
|
||||||
tags: ['doctrine.repository_service']
|
tags: ["doctrine.repository_service"]
|
||||||
|
|
||||||
Chill\DocStoreBundle\Form\DocumentCategoryType:
|
Chill\DocStoreBundle\Form\DocumentCategoryType:
|
||||||
class: Chill\DocStoreBundle\Form\DocumentCategoryType
|
class: Chill\DocStoreBundle\Form\DocumentCategoryType
|
||||||
arguments: ['%kernel.bundles%']
|
arguments: ["%kernel.bundles%"]
|
||||||
tags:
|
tags:
|
||||||
- { name: form.type }
|
- { name: form.type }
|
||||||
|
|
||||||
Chill\DocStoreBundle\Form\PersonDocumentType:
|
Chill\DocStoreBundle\Form\PersonDocumentType:
|
||||||
class: Chill\DocStoreBundle\Form\PersonDocumentType
|
class: Chill\DocStoreBundle\Form\PersonDocumentType
|
||||||
arguments:
|
arguments:
|
||||||
- "@chill.main.helper.translatable_string"
|
- "@chill.main.helper.translatable_string"
|
||||||
tags:
|
tags:
|
||||||
- { name: form.type, alias: chill_docstorebundle_form_document }
|
- { name: form.type, alias: chill_docstorebundle_form_document }
|
||||||
|
|
||||||
Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter:
|
Chill\DocStoreBundle\Security\Authorization\:
|
||||||
class: Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter
|
resource: "./../Security/Authorization"
|
||||||
arguments:
|
autowire: true
|
||||||
- "@security.access.decision_manager"
|
autoconfigure: true
|
||||||
- "@chill.main.security.authorization.helper"
|
tags:
|
||||||
- "@logger"
|
- { name: chill.role }
|
||||||
tags:
|
|
||||||
- { name: security.voter }
|
|
||||||
- { name: chill.role }
|
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
services:
|
services:
|
||||||
Chill\DocStoreBundle\Controller\:
|
_defaults:
|
||||||
resource: '../../Controller'
|
autowire: true
|
||||||
tags: ['controller.service_arguments']
|
autoconfigure: true
|
||||||
|
|
||||||
Chill\DocStoreBundle\Controller\DocumentPersonController:
|
Chill\DocStoreBundle\Controller\:
|
||||||
arguments:
|
resource: "../../Controller"
|
||||||
$translator: '@Symfony\Component\Translation\TranslatorInterface'
|
tags: ["controller.service_arguments"]
|
||||||
$eventDispatcher: '@Symfony\Component\EventDispatcher\EventDispatcherInterface'
|
|
||||||
$authorizationHelper: '@Chill\MainBundle\Security\Authorization\AuthorizationHelper'
|
|
||||||
tags: ['controller.service_arguments']
|
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
services:
|
services:
|
||||||
Chill\DocStoreBundle\Form\StoredObjectType:
|
Chill\DocStoreBundle\Form\StoredObjectType:
|
||||||
arguments:
|
arguments:
|
||||||
$em: '@Doctrine\ORM\EntityManagerInterface'
|
$em: '@Doctrine\ORM\EntityManagerInterface'
|
||||||
tags:
|
tags:
|
||||||
- { name: form.type }
|
- { name: form.type }
|
||||||
|
|
||||||
|
Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType:
|
||||||
|
class: Chill\DocStoreBundle\Form\AccompanyingCourseDocumentType
|
||||||
|
arguments:
|
||||||
|
- "@chill.main.helper.translatable_string"
|
||||||
|
tags:
|
||||||
|
- { name: form.type, alias: chill_docstorebundle_form_document }
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\DocStore;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20210903091534 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('CREATE SEQUENCE chill_doc.accompanyingcourse_document_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
|
||||||
|
$this->addSql('CREATE TABLE chill_doc.accompanyingcourse_document (id INT NOT NULL, course_id INT NOT NULL, PRIMARY KEY(id))');
|
||||||
|
$this->addSql('CREATE INDEX IDX_A45098F6591CC992 ON chill_doc.accompanyingcourse_document (course_id)');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F6591CC992 FOREIGN KEY (course_id) REFERENCES chill_person_accompanying_period (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('DROP SEQUENCE chill_doc.accompanyingcourse_document_id_seq CASCADE');
|
||||||
|
$this->addSql('DROP TABLE chill_doc.accompanyingcourse_document');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\DocStore;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-generated Migration: Please modify to your needs!
|
||||||
|
*/
|
||||||
|
final class Version20210903123835 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD category_bundle_id VARCHAR(255) DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD category_id_inside_bundle INT DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD object_id INT DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD scope_id INT DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD user_id INT DEFAULT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD title TEXT NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD description TEXT NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD date TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F6369A0BE36EF62EFC FOREIGN KEY (category_bundle_id, category_id_inside_bundle) REFERENCES chill_doc.document_category (bundle_id, id_inside_bundle) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F6232D562B FOREIGN KEY (object_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F6682B5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT FK_A45098F6A76ED395 FOREIGN KEY (user_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||||
|
$this->addSql('CREATE INDEX IDX_A45098F6369A0BE36EF62EFC ON chill_doc.accompanyingcourse_document (category_bundle_id, category_id_inside_bundle)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_A45098F6232D562B ON chill_doc.accompanyingcourse_document (object_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_A45098F6682B5931 ON chill_doc.accompanyingcourse_document (scope_id)');
|
||||||
|
$this->addSql('CREATE INDEX IDX_A45098F6A76ED395 ON chill_doc.accompanyingcourse_document (user_id)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6369A0BE36EF62EFC');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6232D562B');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6682B5931');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP CONSTRAINT FK_A45098F6A76ED395');
|
||||||
|
$this->addSql('DROP INDEX IDX_A45098F6369A0BE36EF62EFC');
|
||||||
|
$this->addSql('DROP INDEX IDX_A45098F6232D562B');
|
||||||
|
$this->addSql('DROP INDEX IDX_A45098F6682B5931');
|
||||||
|
$this->addSql('DROP INDEX IDX_A45098F6A76ED395');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP category_bundle_id');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP category_id_inside_bundle');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP object_id');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP scope_id');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP user_id');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP title');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP description');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP date');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Chill\Migrations\DocStore;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
final class Version20210928182542 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Create UUID column on StoredObject table.';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object ADD uuid UUID DEFAULT NULL');
|
||||||
|
$this->addSql('UPDATE chill_doc.stored_object SET uuid=uuid_generate_v4()');
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object ALTER uuid SET NOT NULL');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_49604E36D17F50A6 ON chill_doc.stored_object (uuid)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_doc.stored_object DROP uuid');
|
||||||
|
}
|
||||||
|
}
|
@ -118,7 +118,7 @@ class CRUDController extends AbstractController
|
|||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$this->onFormValid($entity, $form, $request);
|
$this->onFormValid($action, $entity, $form, $request);
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
$this->onPreRemove($action, $entity, $form, $request);
|
$this->onPreRemove($action, $entity, $form, $request);
|
||||||
@ -607,7 +607,7 @@ class CRUDController extends AbstractController
|
|||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$this->onFormValid($entity, $form, $request);
|
$this->onFormValid($action, $entity, $form, $request);
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
$this->onPreFlush($action, $entity, $form, $request);
|
$this->onPreFlush($action, $entity, $form, $request);
|
||||||
@ -706,7 +706,7 @@ class CRUDController extends AbstractController
|
|||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$this->onFormValid($entity, $form, $request);
|
$this->onFormValid($action, $entity, $form, $request);
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
$this->onPrePersist($action, $entity, $form, $request);
|
$this->onPrePersist($action, $entity, $form, $request);
|
||||||
@ -716,7 +716,7 @@ class CRUDController extends AbstractController
|
|||||||
$this->onPreFlush($action, $entity, $form, $request);
|
$this->onPreFlush($action, $entity, $form, $request);
|
||||||
$em->flush();
|
$em->flush();
|
||||||
$this->onPostFlush($action, $entity, $form, $request);
|
$this->onPostFlush($action, $entity, $form, $request);
|
||||||
$this->getPaginatorFactory();
|
|
||||||
$this->addFlash('success', $this->generateFormSuccessMessage($action, $entity));
|
$this->addFlash('success', $this->generateFormSuccessMessage($action, $entity));
|
||||||
|
|
||||||
$result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request);
|
$result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request);
|
||||||
@ -1084,12 +1084,7 @@ class CRUDController extends AbstractController
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function onFormValid(string $action, object $entity, FormInterface $form, Request $request)
|
||||||
* @param object $entity
|
|
||||||
* @param FormInterface $form
|
|
||||||
* @param Request $request
|
|
||||||
*/
|
|
||||||
protected function onFormValid(object $entity, FormInterface $form, Request $request)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
|
use Chill\MainBundle\Entity\Address;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||||
|
|
||||||
|
class AddressApiController extends ApiController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Duplicate an existing address
|
||||||
|
*
|
||||||
|
* @Route("/api/1.0/main/address/{id}/duplicate.json", name="chill_api_main_address_duplicate",
|
||||||
|
* methods={"POST"})
|
||||||
|
*
|
||||||
|
* @param Address $address
|
||||||
|
*/
|
||||||
|
public function duplicate(Address $address): JsonResponse
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
|
$new = Address::createFromAddress($address);
|
||||||
|
|
||||||
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
|
$em->persist($new);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
return $this->json($new, Response::HTTP_OK, [], [
|
||||||
|
AbstractNormalizer::GROUPS => ['read']
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -23,20 +23,17 @@ namespace Chill\MainBundle\Controller;
|
|||||||
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
|
||||||
/**
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
* Class AdminController
|
|
||||||
*
|
|
||||||
* @package Chill\MainBundle\Controller
|
|
||||||
* @author julien.fastre@champs-libres.coop
|
|
||||||
* @author marc@champs-libres.coop
|
|
||||||
*/
|
|
||||||
class AdminController extends AbstractController
|
class AdminController extends AbstractController
|
||||||
{
|
{
|
||||||
|
|
||||||
public function indexAction($menu = 'admin',
|
/**
|
||||||
$header_title = 'views.Main.admin.index.header_title',
|
* @Route("/{_locale}/admin", name="chill_main_admin_central")
|
||||||
$page_title = 'views.Main.admin.index.page_title') {
|
*/
|
||||||
return $this->render('@ChillMain/Admin/layout.html.twig');
|
public function indexAction()
|
||||||
|
{
|
||||||
|
return $this->render('@ChillMain/Admin/index.html.twig');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function indexPermissionsAction()
|
public function indexPermissionsAction()
|
||||||
@ -44,11 +41,4 @@ class AdminController extends AbstractController
|
|||||||
return $this->render('@ChillMain/Admin/layout_permissions.html.twig');
|
return $this->render('@ChillMain/Admin/layout_permissions.html.twig');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configurationWarningsAction()
|
|
||||||
{
|
|
||||||
$alertManager = $this->get('chill_main.configuration_alert_manager');
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,13 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Controller;
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\CRUD\Controller\AbstractCRUDController;
|
||||||
|
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||||
|
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
@ -11,7 +16,10 @@ use Chill\MainBundle\Form\UserType;
|
|||||||
use Chill\MainBundle\Entity\GroupCenter;
|
use Chill\MainBundle\Entity\GroupCenter;
|
||||||
use Chill\MainBundle\Form\Type\ComposedGroupCenterType;
|
use Chill\MainBundle\Form\Type\ComposedGroupCenterType;
|
||||||
use Chill\MainBundle\Form\UserPasswordType;
|
use Chill\MainBundle\Form\UserPasswordType;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,7 +27,7 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
|
|||||||
*
|
*
|
||||||
* @package Chill\MainBundle\Controller
|
* @package Chill\MainBundle\Controller
|
||||||
*/
|
*/
|
||||||
class UserController extends AbstractController
|
class UserController extends CRUDController
|
||||||
{
|
{
|
||||||
|
|
||||||
const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter';
|
const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter';
|
||||||
@ -34,165 +42,112 @@ class UserController extends AbstractController
|
|||||||
*/
|
*/
|
||||||
private $validator;
|
private $validator;
|
||||||
|
|
||||||
|
private UserPasswordEncoderInterface $passwordEncoder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UserController constructor.
|
* UserController constructor.
|
||||||
*
|
*
|
||||||
* @param LoggerInterface $logger
|
* @param LoggerInterface $logger
|
||||||
* @param ValidatorInterface $validator
|
* @param ValidatorInterface $validator
|
||||||
*/
|
*/
|
||||||
public function __construct(LoggerInterface $logger, ValidatorInterface $validator)
|
public function __construct(
|
||||||
{
|
LoggerInterface $chillLogger,
|
||||||
$this->logger = $logger;
|
ValidatorInterface $validator,
|
||||||
|
UserPasswordEncoderInterface $passwordEncoder
|
||||||
|
) {
|
||||||
|
$this->logger = $chillLogger;
|
||||||
$this->validator = $validator;
|
$this->validator = $validator;
|
||||||
|
$this->passwordEncoder = $passwordEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function createFormFor(string $action, $entity, string $formClass = null, array $formOptions = []): FormInterface
|
||||||
* Lists all User entities.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function indexAction()
|
|
||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
// for "new", add special config
|
||||||
|
if ('new' === $action) {
|
||||||
$entities = $em->createQuery('SELECT u FROM ChillMainBundle:User u '
|
return $this->createForm(UserType::class, $entity, array(
|
||||||
. 'ORDER BY u.username')
|
'is_creation' => true
|
||||||
->getResult();
|
));
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/index.html.twig', array(
|
|
||||||
'entities' => $entities,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Creates a new User entity.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function createAction(Request $request)
|
|
||||||
{
|
|
||||||
$user = new User();
|
|
||||||
$form = $this->createCreateForm($user);
|
|
||||||
$form->handleRequest($request);
|
|
||||||
|
|
||||||
if ($form->isValid()) {
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
|
|
||||||
$user->setPassword($this->get('security.password_encoder')
|
|
||||||
->encodePassword($user, $form['plainPassword']->getData()));
|
|
||||||
|
|
||||||
$em->persist($user);
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('admin_user_show', array('id' => $user->getId())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/new.html.twig', array(
|
// default behaviour
|
||||||
'entity' => $user,
|
return parent::createFormFor($action, $entity, $formClass, $formOptions);
|
||||||
'form' => $form->createView(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request)
|
||||||
* Creates a form to create a User entity.
|
|
||||||
*
|
|
||||||
* @param User $entity The entity
|
|
||||||
*
|
|
||||||
* @return \Symfony\Component\Form\Form The form
|
|
||||||
*/
|
|
||||||
private function createCreateForm(User $entity)
|
|
||||||
{
|
{
|
||||||
$form = $this->createForm(UserType::class, $entity, array(
|
// for "new", encode the password
|
||||||
'action' => $this->generateUrl('admin_user_create'),
|
if ('new' === $action) {
|
||||||
'method' => 'POST',
|
$entity->setPassword($this->passwordEncoder
|
||||||
'is_creation' => true
|
->encodePassword($entity, $form['plainPassword']->getData()));
|
||||||
));
|
|
||||||
|
|
||||||
$form->add('submit', SubmitType::class, array('label' => 'Create'));
|
|
||||||
|
|
||||||
return $form;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a form to create a new User entity.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function newAction()
|
|
||||||
{
|
|
||||||
$user = new User();
|
|
||||||
$form = $this->createCreateForm($user);
|
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/new.html.twig', array(
|
|
||||||
'entity' => $user,
|
|
||||||
'form' => $form->createView(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds and displays a User entity.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function showAction($id)
|
|
||||||
{
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
|
|
||||||
$user = $em->getRepository('ChillMainBundle:User')->find($id);
|
|
||||||
|
|
||||||
if (!$user) {
|
|
||||||
throw $this->createNotFoundException('Unable to find User entity.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/show.html.twig', array(
|
// default behaviour
|
||||||
'entity' => $user,
|
parent::onPrePersist($action, $entity, $form, $request);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||||
* Displays a form to edit an existing User entity.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function editAction($id)
|
|
||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
$query->addOrderBy('e.usernameCanonical', 'ASC');
|
||||||
|
|
||||||
$user = $em->getRepository('ChillMainBundle:User')->find($id);
|
return parent::orderQuery($action, $query, $request, $paginator);
|
||||||
|
}
|
||||||
|
|
||||||
if (!$user) {
|
protected function generateTemplateParameter(string $action, $entity, Request $request, array $defaultTemplateParameters = [])
|
||||||
throw $this->createNotFoundException('Unable to find User entity.');
|
{
|
||||||
|
// add mini-forms for edit action
|
||||||
|
if ("edit" === $action) {
|
||||||
|
return array_merge(
|
||||||
|
$defaultTemplateParameters,
|
||||||
|
[
|
||||||
|
'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($entity, $request)->createView(),
|
||||||
|
'delete_groupcenter_form' => array_map(
|
||||||
|
function(\Symfony\Component\Form\Form $form) {
|
||||||
|
return $form->createView();
|
||||||
|
},
|
||||||
|
iterator_to_array($this->getDeleteLinkGroupCenterByUser($entity, $request), true)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$editForm = $this->createEditForm($user);
|
// default behaviour
|
||||||
|
return parent::generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters);
|
||||||
return $this->render('@ChillMain/User/edit.html.twig', array(
|
|
||||||
'entity' => $user,
|
|
||||||
'edit_form' => $editForm->createView(),
|
|
||||||
'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user)->createView(),
|
|
||||||
'delete_groupcenter_form' => array_map(
|
|
||||||
function(\Symfony\Component\Form\Form $form) {
|
|
||||||
return $form->createView();
|
|
||||||
|
|
||||||
},
|
|
||||||
iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true))
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays a form to edit the user password.
|
* Displays a form to edit the user password.
|
||||||
*
|
*
|
||||||
|
* @Route("/{_locale}/admin/user/{id}/edit_password", name="admin_user_edit_password")
|
||||||
*/
|
*/
|
||||||
public function editPasswordAction($id)
|
public function editPasswordAction(User $user, Request $request)
|
||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
$editForm = $this->createEditPasswordForm($user, $request);
|
||||||
|
$editForm->handleRequest($request);
|
||||||
|
|
||||||
$user = $em->getRepository('ChillMainBundle:User')->find($id);
|
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||||
|
$password = $editForm->get('new_password')->getData();
|
||||||
|
|
||||||
if (!$user) {
|
// logging for prod
|
||||||
throw $this->createNotFoundException('Unable to find User entity.');
|
$this->logger->info('update password for an user', [
|
||||||
|
'by' => $this->getUser()->getUsername(),
|
||||||
|
'user' => $user->getUsername()
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->setPassword($this->passwordEncoder->encodePassword($user, $password));
|
||||||
|
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
$this->addFlash('success', $this->get('translator')->trans('Password successfully updated!'));
|
||||||
|
|
||||||
|
return $this->redirect(
|
||||||
|
$request->query->has('returnPath') ? $request->query->get('returnPath') :
|
||||||
|
$this->generateUrl('chill_crud_admin_user_edit', ['id' => $user->getId()])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$editForm = $this->createEditPasswordForm($user);
|
return $this->render('@ChillMain/User/edit_password.html.twig', [
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/edit_password.html.twig', array(
|
|
||||||
'entity' => $user,
|
'entity' => $user,
|
||||||
'edit_form' => $editForm->createView()
|
'edit_form' => $editForm->createView()
|
||||||
));
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -204,9 +159,6 @@ class UserController extends AbstractController
|
|||||||
private function createEditPasswordForm(User $user)
|
private function createEditPasswordForm(User $user)
|
||||||
{
|
{
|
||||||
return $this->createForm(UserPasswordType::class, null, array(
|
return $this->createForm(UserPasswordType::class, null, array(
|
||||||
'action' =>
|
|
||||||
$this->generateUrl('admin_user_update_password', array('id' => $user->getId())),
|
|
||||||
'method' => 'PUT',
|
|
||||||
'user' => $user
|
'user' => $user
|
||||||
))
|
))
|
||||||
->add('submit', SubmitType::class, array('label' => 'Change password'))
|
->add('submit', SubmitType::class, array('label' => 'Change password'))
|
||||||
@ -214,7 +166,11 @@ class UserController extends AbstractController
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function deleteLinkGroupCenterAction($uid, $gcid)
|
/**
|
||||||
|
* @Route("/{_locale}/admin/main/user/{uid}/delete_link_groupcenter/{gcid}",
|
||||||
|
* name="admin_user_delete_groupcenter")
|
||||||
|
*/
|
||||||
|
public function deleteLinkGroupCenterAction($uid, $gcid, Request $request): RedirectResponse
|
||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
@ -236,7 +192,7 @@ class UserController extends AbstractController
|
|||||||
} catch (\RuntimeException $ex) {
|
} catch (\RuntimeException $ex) {
|
||||||
$this->addFlash('error', $this->get('translator')->trans($ex->getMessage()));
|
$this->addFlash('error', $this->get('translator')->trans($ex->getMessage()));
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $uid)));
|
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', array('id' => $uid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
$em->flush();
|
$em->flush();
|
||||||
@ -244,11 +200,15 @@ class UserController extends AbstractController
|
|||||||
$this->addFlash('success', $this->get('translator')
|
$this->addFlash('success', $this->get('translator')
|
||||||
->trans('The permissions where removed.'));
|
->trans('The permissions where removed.'));
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $uid)));
|
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', array('id' => $uid)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addLinkGroupCenterAction(Request $request, $uid)
|
/**
|
||||||
|
* @Route("/{_locale}/admin/main/user/{uid}/add_link_groupcenter",
|
||||||
|
* name="admin_user_add_groupcenter")
|
||||||
|
*/
|
||||||
|
public function addLinkGroupCenterAction(Request $request, $uid): RedirectResponse
|
||||||
{
|
{
|
||||||
$em = $this->getDoctrine()->getManager();
|
$em = $this->getDoctrine()->getManager();
|
||||||
|
|
||||||
@ -258,7 +218,7 @@ class UserController extends AbstractController
|
|||||||
throw $this->createNotFoundException('Unable to find User entity.');
|
throw $this->createNotFoundException('Unable to find User entity.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$form = $this->createAddLinkGroupCenterForm($user);
|
$form = $this->createAddLinkGroupCenterForm($user, $request);
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isValid()) {
|
if ($form->isValid()) {
|
||||||
@ -272,8 +232,12 @@ class UserController extends AbstractController
|
|||||||
$this->addFlash('success', $this->get('translator')->trans('The '
|
$this->addFlash('success', $this->get('translator')->trans('The '
|
||||||
. 'permissions have been successfully added to the user'));
|
. 'permissions have been successfully added to the user'));
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('admin_user_edit',
|
$returnPathParams = $request->query->has('returnPath') ?
|
||||||
array('id' => $uid)));
|
['returnPath' => $request->query->get('returnPath')] : [];
|
||||||
|
|
||||||
|
return $this->redirect($this->generateUrl('chill_crud_admin_user_edit',
|
||||||
|
\array_merge(['id' => $uid], $returnPathParams)));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
foreach($this->validator->validate($user) as $error)
|
foreach($this->validator->validate($user) as $error)
|
||||||
$this->addFlash('error', $error->getMessage());
|
$this->addFlash('error', $error->getMessage());
|
||||||
@ -311,104 +275,6 @@ class UserController extends AbstractController
|
|||||||
return $groupCenterManaged;
|
return $groupCenterManaged;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a form to edit a User entity.
|
|
||||||
*
|
|
||||||
* @param User $user The entity
|
|
||||||
*
|
|
||||||
* @return \Symfony\Component\Form\Form The form
|
|
||||||
*/
|
|
||||||
private function createEditForm(User $user)
|
|
||||||
{
|
|
||||||
$form = $this->createForm(UserType::class, $user, array(
|
|
||||||
'action' => $this->generateUrl('admin_user_update', array('id' => $user->getId())),
|
|
||||||
'method' => 'PUT',
|
|
||||||
));
|
|
||||||
|
|
||||||
$form->add('submit', SubmitType::class, array('label' => 'Update'));
|
|
||||||
|
|
||||||
return $form;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edits an existing User entity.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function updateAction(Request $request, $id)
|
|
||||||
{
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
|
|
||||||
$user = $em->getRepository('ChillMainBundle:User')->find($id);
|
|
||||||
|
|
||||||
if (!$user) {
|
|
||||||
throw $this->createNotFoundException('Unable to find User entity.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$editForm = $this->createEditForm($user);
|
|
||||||
$editForm->handleRequest($request);
|
|
||||||
|
|
||||||
if ($editForm->isValid()) {
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $id)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/edit.html.twig', array(
|
|
||||||
'entity' => $user,
|
|
||||||
'edit_form' => $editForm->createView(),
|
|
||||||
'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user)->createView(),
|
|
||||||
'delete_groupcenter_form' => array_map(
|
|
||||||
function(\Symfony\Component\Form\Form $form) {
|
|
||||||
return $form->createView();
|
|
||||||
|
|
||||||
},
|
|
||||||
iterator_to_array($this->getDeleteLinkGroupCenterByUser($user), true))
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Edits the user password
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function updatePasswordAction(Request $request, $id)
|
|
||||||
{
|
|
||||||
$em = $this->getDoctrine()->getManager();
|
|
||||||
|
|
||||||
$user = $em->getRepository('ChillMainBundle:User')->find($id);
|
|
||||||
|
|
||||||
if (!$user) {
|
|
||||||
throw $this->createNotFoundException('Unable to find User entity.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$editForm = $this->createEditPasswordForm($user);
|
|
||||||
$editForm->handleRequest($request);
|
|
||||||
|
|
||||||
if ($editForm->isValid()) {
|
|
||||||
$password = $editForm->get('new_password')->getData();
|
|
||||||
|
|
||||||
// logging for prod
|
|
||||||
$this->logger->info('update password for an user', [
|
|
||||||
'by' => $this->getUser()->getUsername(),
|
|
||||||
'user' => $user->getUsername()
|
|
||||||
]);
|
|
||||||
|
|
||||||
$user->setPassword($this->get('security.password_encoder')
|
|
||||||
->encodePassword($user, $password));
|
|
||||||
|
|
||||||
$em->flush();
|
|
||||||
|
|
||||||
$this->addFlash('success', $this->get('translator')->trans('Password successfully updated!'));
|
|
||||||
|
|
||||||
return $this->redirect($this->generateUrl('admin_user_edit', array('id' => $id)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->render('@ChillMain/User/edit_password.html.twig', array(
|
|
||||||
'entity' => $user,
|
|
||||||
'edit_form' => $editForm->createView(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a form to delete a link to a GroupCenter
|
* Creates a form to delete a link to a GroupCenter
|
||||||
*
|
*
|
||||||
@ -416,11 +282,13 @@ class UserController extends AbstractController
|
|||||||
*
|
*
|
||||||
* @return \Symfony\Component\Form\Form The form
|
* @return \Symfony\Component\Form\Form The form
|
||||||
*/
|
*/
|
||||||
private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter)
|
private function createDeleteLinkGroupCenterForm(User $user, GroupCenter $groupCenter, $request)
|
||||||
{
|
{
|
||||||
|
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
|
||||||
|
|
||||||
return $this->createFormBuilder()
|
return $this->createFormBuilder()
|
||||||
->setAction($this->generateUrl('admin_user_delete_group_center',
|
->setAction($this->generateUrl('admin_user_delete_groupcenter',
|
||||||
array('uid' => $user->getId(), 'gcid' => $groupCenter->getId())))
|
array_merge($returnPathParams, ['uid' => $user->getId(), 'gcid' => $groupCenter->getId()])))
|
||||||
->setMethod('DELETE')
|
->setMethod('DELETE')
|
||||||
->add('submit', SubmitType::class, array('label' => 'Delete'))
|
->add('submit', SubmitType::class, array('label' => 'Delete'))
|
||||||
->getForm()
|
->getForm()
|
||||||
@ -433,11 +301,13 @@ class UserController extends AbstractController
|
|||||||
* @param User $user
|
* @param User $user
|
||||||
* @return \Symfony\Component\Form\Form
|
* @return \Symfony\Component\Form\Form
|
||||||
*/
|
*/
|
||||||
private function createAddLinkGroupCenterForm(User $user)
|
private function createAddLinkGroupCenterForm(User $user, Request $request)
|
||||||
{
|
{
|
||||||
|
$returnPathParams = $request->query->has('returnPath') ? ['returnPath' => $request->query->get('returnPath')] : [];
|
||||||
|
|
||||||
return $this->createFormBuilder()
|
return $this->createFormBuilder()
|
||||||
->setAction($this->generateUrl('admin_user_add_group_center',
|
->setAction($this->generateUrl('admin_user_add_groupcenter',
|
||||||
array('uid' => $user->getId())))
|
array_merge($returnPathParams, ['uid' => $user->getId()])))
|
||||||
->setMethod('POST')
|
->setMethod('POST')
|
||||||
->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class)
|
->add(self::FORM_GROUP_CENTER_COMPOSED, ComposedGroupCenterType::class)
|
||||||
->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter'))
|
->add('submit', SubmitType::class, array('label' => 'Add a new groupCenter'))
|
||||||
@ -449,11 +319,11 @@ class UserController extends AbstractController
|
|||||||
*
|
*
|
||||||
* @param User $user
|
* @param User $user
|
||||||
*/
|
*/
|
||||||
private function getDeleteLinkGroupCenterByUser(User $user)
|
private function getDeleteLinkGroupCenterByUser(User $user, Request $request)
|
||||||
{
|
{
|
||||||
foreach ($user->getGroupCenters() as $groupCenter) {
|
foreach ($user->getGroupCenters() as $groupCenter) {
|
||||||
yield $groupCenter->getId() => $this
|
yield $groupCenter->getId() => $this
|
||||||
->createDeleteLinkGroupCenterForm($user, $groupCenter);
|
->createDeleteLinkGroupCenterForm($user, $groupCenter, $request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,14 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle\DependencyInjection;
|
namespace Chill\MainBundle\DependencyInjection;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Controller\AddressApiController;
|
||||||
|
use Chill\MainBundle\Controller\UserController;
|
||||||
use Chill\MainBundle\Doctrine\DQL\STContains;
|
use Chill\MainBundle\Doctrine\DQL\STContains;
|
||||||
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
|
use Chill\MainBundle\Doctrine\DQL\StrictWordSimilarityOPS;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Entity\UserJob;
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
use Chill\MainBundle\Form\UserJobType;
|
use Chill\MainBundle\Form\UserJobType;
|
||||||
|
use Chill\MainBundle\Form\UserType;
|
||||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||||
@ -283,17 +287,40 @@ class ChillMainExtension extends Extension implements PrependExtensionInterface,
|
|||||||
'template' => '@ChillMain/UserJob/index.html.twig',
|
'template' => '@ChillMain/UserJob/index.html.twig',
|
||||||
],
|
],
|
||||||
'new' => [
|
'new' => [
|
||||||
'role' => 'ROLE_ADMIN'
|
'role' => 'ROLE_ADMIN'
|
||||||
],
|
],
|
||||||
'edit' => [
|
'edit' => [
|
||||||
'role' => 'ROLE_ADMIN'
|
'role' => 'ROLE_ADMIN'
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'class' => User::class,
|
||||||
|
'controller' => UserController::class,
|
||||||
|
'name' => 'admin_user',
|
||||||
|
'base_path' => '/admin/main/user',
|
||||||
|
'base_role' => 'ROLE_ADMIN',
|
||||||
|
'form_class' => UserType::class,
|
||||||
|
'actions' => [
|
||||||
|
'index' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillMain/User/index.html.twig'
|
||||||
|
],
|
||||||
|
'new' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillMain/User/new.html.twig'
|
||||||
|
],
|
||||||
|
'edit' => [
|
||||||
|
'role' => 'ROLE_ADMIN',
|
||||||
|
'template' => '@ChillMain/User/edit.html.twig'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
],
|
],
|
||||||
'apis' => [
|
'apis' => [
|
||||||
[
|
[
|
||||||
'class' => \Chill\MainBundle\Entity\Address::class,
|
'class' => \Chill\MainBundle\Entity\Address::class,
|
||||||
|
'controller' => AddressApiController::class,
|
||||||
'name' => 'address',
|
'name' => 'address',
|
||||||
'base_path' => '/api/1.0/main/address',
|
'base_path' => '/api/1.0/main/address',
|
||||||
'base_role' => 'ROLE_USER',
|
'base_role' => 'ROLE_USER',
|
||||||
|
@ -376,10 +376,22 @@ class Address
|
|||||||
public static function createFromAddress(Address $original) : Address
|
public static function createFromAddress(Address $original) : Address
|
||||||
{
|
{
|
||||||
return (new Address())
|
return (new Address())
|
||||||
|
->setBuildingName($original->getBuildingName())
|
||||||
|
->setCorridor($original->getCorridor())
|
||||||
|
->setCustoms($original->getCustoms())
|
||||||
|
->setDistribution($original->getDistribution())
|
||||||
|
->setExtra($original->getExtra())
|
||||||
|
->setFlat($original->getFlat())
|
||||||
|
->setFloor($original->getFloor())
|
||||||
|
->setIsNoAddress($original->getIsNoAddress())
|
||||||
|
->setLinkedToThirdParty($original->getLinkedToThirdParty())
|
||||||
|
->setPoint($original->getPoint())
|
||||||
->setPostcode($original->getPostcode())
|
->setPostcode($original->getPostcode())
|
||||||
->setStreetAddress1($original->getStreetAddress1())
|
->setSteps($original->getSteps())
|
||||||
->setStreetAddress2($original->getStreetAddress2())
|
->setStreet($original->getStreet())
|
||||||
|
->setStreetNumber($original->getStreetNumber())
|
||||||
->setValidFrom($original->getValidFrom())
|
->setValidFrom($original->getValidFrom())
|
||||||
|
->setValidTo($original->getValidTo())
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,7 +518,7 @@ class Address
|
|||||||
return $this->validTo;
|
return $this->validTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setValidTo(\DateTimeInterface $validTo): self
|
public function setValidTo(?\DateTimeInterface $validTo = null): self
|
||||||
{
|
{
|
||||||
$this->validTo = $validTo;
|
$this->validTo = $validTo;
|
||||||
|
|
||||||
|
@ -76,10 +76,7 @@ class CenterType extends AbstractType
|
|||||||
{
|
{
|
||||||
$nbReachableCenters = count($this->reachableCenters);
|
$nbReachableCenters = count($this->reachableCenters);
|
||||||
|
|
||||||
if ($nbReachableCenters === 0) {
|
if ($nbReachableCenters <= 1) {
|
||||||
throw new \RuntimeException("The user is not associated with "
|
|
||||||
. "any center. Associate user with a center");
|
|
||||||
} elseif ($nbReachableCenters === 1) {
|
|
||||||
return HiddenType::class;
|
return HiddenType::class;
|
||||||
} else {
|
} else {
|
||||||
return EntityType::class;
|
return EntityType::class;
|
||||||
|
@ -47,9 +47,9 @@ class UserType extends AbstractType
|
|||||||
])
|
])
|
||||||
->add('label', TextType::class)
|
->add('label', TextType::class)
|
||||||
->add('mainCenter', EntityType::class, [
|
->add('mainCenter', EntityType::class, [
|
||||||
'label' => 'main center',
|
'label' => 'Main center',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'placeholder' => 'choose a main center',
|
'placeholder' => 'Choose a main center',
|
||||||
'class' => Center::class,
|
'class' => Center::class,
|
||||||
'query_builder' => function (EntityRepository $er) {
|
'query_builder' => function (EntityRepository $er) {
|
||||||
$qb = $er->createQueryBuilder('c');
|
$qb = $er->createQueryBuilder('c');
|
||||||
@ -59,16 +59,16 @@ class UserType extends AbstractType
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
->add('mainScope', EntityType::class, [
|
->add('mainScope', EntityType::class, [
|
||||||
'label' => 'Choose a main scope',
|
'label' => 'Main scope',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'placeholder' => 'choose a main scope',
|
'placeholder' => 'Choose a main scope',
|
||||||
'class' => Scope::class,
|
'class' => Scope::class,
|
||||||
'choice_label' => function (Scope $c) {
|
'choice_label' => function (Scope $c) {
|
||||||
return $this->translatableStringHelper->localize($c->getName());
|
return $this->translatableStringHelper->localize($c->getName());
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
->add('userJob', EntityType::class, [
|
->add('userJob', EntityType::class, [
|
||||||
'label' => 'Choose a job',
|
'label' => 'user job',
|
||||||
'required' => false,
|
'required' => false,
|
||||||
'placeholder' => 'choose a job',
|
'placeholder' => 'choose a job',
|
||||||
'class' => UserJob::class,
|
'class' => UserJob::class,
|
||||||
|
@ -7,6 +7,7 @@ namespace Chill\MainBundle\Repository;
|
|||||||
use Chill\MainBundle\Entity\Address;
|
use Chill\MainBundle\Entity\Address;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\ORM\QueryBuilder;
|
||||||
use Doctrine\Persistence\ObjectRepository;
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
final class AddressRepository implements ObjectRepository
|
final class AddressRepository implements ObjectRepository
|
||||||
@ -47,4 +48,9 @@ final class AddressRepository implements ObjectRepository
|
|||||||
public function getClassName() {
|
public function getClassName() {
|
||||||
return Address::class;
|
return Address::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function createQueryBuilder(string $alias, ?string $indexBy = null): QueryBuilder
|
||||||
|
{
|
||||||
|
return $this->repository->createQueryBuilder($alias, $indexBy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
49
src/Bundle/ChillMainBundle/Repository/UserJobRepository.php
Normal file
49
src/Bundle/ChillMainBundle/Repository/UserJobRepository.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Repository;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use Doctrine\Persistence\ObjectRepository;
|
||||||
|
|
||||||
|
class UserJobRepository implements ObjectRepository
|
||||||
|
{
|
||||||
|
private EntityRepository $repository;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $em)
|
||||||
|
{
|
||||||
|
$this->repository = $em->getRepository(UserJob::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function find($id): ?UserJob
|
||||||
|
{
|
||||||
|
return $this->repository->find($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|UserJob[]
|
||||||
|
*/
|
||||||
|
public function findAll(): array
|
||||||
|
{
|
||||||
|
return $this->repository->findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|UserJob[]|object[]
|
||||||
|
*/
|
||||||
|
public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
{
|
||||||
|
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findOneBy(array $criteria)
|
||||||
|
{
|
||||||
|
return $this->repository->findOneBy($criteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClassName()
|
||||||
|
{
|
||||||
|
return UserJob::class;
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,9 @@ const fetchScopes = () => {
|
|||||||
return response.json();
|
return response.json();
|
||||||
}
|
}
|
||||||
}).then(data => {
|
}).then(data => {
|
||||||
console.log(data);
|
//console.log(data);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log(data);
|
//console.log(data);
|
||||||
resolve(data.results);
|
resolve(data.results);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -53,32 +53,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
|
||||||
* Patch date
|
|
||||||
* TO MOVE in DatePane
|
|
||||||
addDateToAddressAndPostAddressTo(payload) {
|
|
||||||
payload.body = {
|
|
||||||
validFrom: {
|
|
||||||
datetime: `${this.context.valid.from.toISOString().split('T')[0]}T00:00:00+0100`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
console.log('addDateToAddress', payload);
|
|
||||||
|
|
||||||
this.$refs.addAddress.flag.loading = true;
|
|
||||||
return patchAddress(payload.addressId, payload.body)
|
|
||||||
.then(address => new Promise((resolve, reject) => {
|
|
||||||
this.context.valid.from = address.validFrom;
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.then(this.postAddressTo(payload))
|
|
||||||
)
|
|
||||||
.catch((error) => {
|
|
||||||
this.$refs.addAddress.errorMsg.push(error);
|
|
||||||
this.$refs.addAddress.flag.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Post new created address to targetEntity
|
* Post new created address to targetEntity
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/*
|
/**
|
||||||
* Endpoint chill_api_single_country__index
|
* Endpoint chill_api_single_country__index
|
||||||
* method GET, get Country Object
|
* method GET, get Country Object
|
||||||
* @returns {Promise} a promise containing all Country object
|
* @returns {Promise} a promise containing all Country object
|
||||||
@ -14,7 +14,7 @@ const fetchCountries = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Endpoint chill_api_single_postal_code__index
|
* Endpoint chill_api_single_postal_code__index
|
||||||
* method GET, get Country Object
|
* method GET, get Country Object
|
||||||
* @returns {Promise} a promise containing all Postal Code objects filtered with country
|
* @returns {Promise} a promise containing all Postal Code objects filtered with country
|
||||||
@ -29,7 +29,7 @@ const fetchCities = (country) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Endpoint chill_api_single_address_reference__index
|
* Endpoint chill_api_single_address_reference__index
|
||||||
* method GET, get AddressReference Object
|
* method GET, get AddressReference Object
|
||||||
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code
|
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code
|
||||||
@ -44,7 +44,7 @@ const fetchReferenceAddresses = (postalCode) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Endpoint chill_api_single_address_reference__index
|
* Endpoint chill_api_single_address_reference__index
|
||||||
* method GET, get AddressReference Object
|
* method GET, get AddressReference Object
|
||||||
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code
|
* @returns {Promise} a promise containing all AddressReference objects filtered with postal code
|
||||||
@ -60,7 +60,7 @@ const fetchAddresses = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Endpoint chill_api_single_address__entity__create
|
* Endpoint chill_api_single_address__entity__create
|
||||||
* method POST, post Address Object
|
* method POST, post Address Object
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
@ -81,8 +81,28 @@ const postAddress = (address) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param address
|
||||||
|
* @returns {Promise<Response>}
|
||||||
|
*/
|
||||||
|
const duplicateAddress = (address) => {
|
||||||
|
const url = `/api/1.0/main/address/${address.address_id}/duplicate.json`;
|
||||||
|
return fetch(url, {
|
||||||
|
'method': 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8'
|
||||||
|
},
|
||||||
|
}).then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
throw Error('Error with request resource response');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
|
/**
|
||||||
* Endpoint chill_api_single_address__entity__create
|
* Endpoint chill_api_single_address__entity__create
|
||||||
* method PATCH, patch Address Instance
|
* method PATCH, patch Address Instance
|
||||||
*
|
*
|
||||||
@ -142,6 +162,7 @@ const getAddress = (id) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
duplicateAddress,
|
||||||
fetchCountries,
|
fetchCountries,
|
||||||
fetchCities,
|
fetchCities,
|
||||||
fetchReferenceAddresses,
|
fetchReferenceAddresses,
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul class="record_actions"
|
<ul class="record_actions" v-if="!options.onlyButton"
|
||||||
:class="{ 'sticky-form-buttons': isStickyForm }">
|
:class="{ 'sticky-form-buttons': isStickyForm }">
|
||||||
|
|
||||||
<li v-if="isStickyForm" class="cancel">
|
<li v-if="isStickyForm" class="cancel">
|
||||||
<slot name="before"></slot>
|
<slot name="before"></slot>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
<slot name="action"></slot>
|
<slot name="action"></slot>
|
||||||
|
</li>
|
||||||
<li v-if="isStickyForm">
|
<li v-if="isStickyForm">
|
||||||
<slot name="after"></slot>
|
<slot name="after"></slot>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<slot v-else name="action"></slot>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -23,9 +24,6 @@ export default {
|
|||||||
return (typeof this.options.stickyActions !== 'undefined') ?
|
return (typeof this.options.stickyActions !== 'undefined') ?
|
||||||
this.options.stickyActions : this.defaultz.stickyActions;
|
this.options.stickyActions : this.defaultz.stickyActions;
|
||||||
},
|
},
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
v-bind:defaultz="this.defaultz"
|
v-bind:defaultz="this.defaultz"
|
||||||
v-bind:entity="this.entity"
|
v-bind:entity="this.entity"
|
||||||
v-bind:flag="this.flag"
|
v-bind:flag="this.flag"
|
||||||
|
@pick-address="this.pickAddress"
|
||||||
ref="suggestAddress">
|
ref="suggestAddress">
|
||||||
</suggest-pane>
|
</suggest-pane>
|
||||||
</template>
|
</template>
|
||||||
@ -55,6 +56,7 @@
|
|||||||
v-bind:entity="this.entity"
|
v-bind:entity="this.entity"
|
||||||
v-bind:flag="this.flag"
|
v-bind:flag="this.flag"
|
||||||
v-bind:insideModal="false"
|
v-bind:insideModal="false"
|
||||||
|
@pick-address="this.pickAddress"
|
||||||
ref="suggestAddress">
|
ref="suggestAddress">
|
||||||
|
|
||||||
<template v-slot:before v-if="!bypassFirstStep">
|
<template v-slot:before v-if="!bypassFirstStep">
|
||||||
@ -217,7 +219,16 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
|
||||||
import { getAddress, fetchCountries, fetchCities, fetchReferenceAddresses, patchAddress, postAddress, postPostalCode } from '../api';
|
import {
|
||||||
|
duplicateAddress,
|
||||||
|
fetchCountries,
|
||||||
|
fetchCities,
|
||||||
|
fetchReferenceAddresses,
|
||||||
|
getAddress,
|
||||||
|
patchAddress,
|
||||||
|
postAddress,
|
||||||
|
postPostalCode,
|
||||||
|
} from '../api';
|
||||||
import { postAddressToPerson, postAddressToHousehold } from "ChillPersonAssets/vuejs/_api/AddAddress.js";
|
import { postAddressToPerson, postAddressToHousehold } from "ChillPersonAssets/vuejs/_api/AddAddress.js";
|
||||||
import ShowPane from './ShowPane.vue';
|
import ShowPane from './ShowPane.vue';
|
||||||
import SuggestPane from './SuggestPane.vue';
|
import SuggestPane from './SuggestPane.vue';
|
||||||
@ -234,6 +245,9 @@ export default {
|
|||||||
EditPane,
|
EditPane,
|
||||||
DatePane
|
DatePane
|
||||||
},
|
},
|
||||||
|
emits: {
|
||||||
|
pickAddress: null
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
flag: {
|
flag: {
|
||||||
@ -257,7 +271,7 @@ export default {
|
|||||||
validFrom: false,
|
validFrom: false,
|
||||||
validTo: false
|
validTo: false
|
||||||
},
|
},
|
||||||
hideAddress: false
|
onlyButton: false
|
||||||
},
|
},
|
||||||
entity: {
|
entity: {
|
||||||
address: {}, // <== loaded and returned
|
address: {}, // <== loaded and returned
|
||||||
@ -299,18 +313,22 @@ export default {
|
|||||||
return (typeof this.options.openPanesInModal !== 'undefined') ?
|
return (typeof this.options.openPanesInModal !== 'undefined') ?
|
||||||
this.options.openPanesInModal : this.defaultz.openPanesInModal;
|
this.options.openPanesInModal : this.defaultz.openPanesInModal;
|
||||||
},
|
},
|
||||||
useDatePane() {
|
validFrom() {
|
||||||
let vFrom = (typeof this.options.useDate !== 'undefined'
|
return (typeof this.options.useDate !== 'undefined' && typeof this.options.useDate.validFrom !== 'undefined') ?
|
||||||
&& typeof this.options.useDate.validFrom !== 'undefined') ?
|
this.options.useDate.validFrom : this.defaultz.useDate.validFrom;
|
||||||
this.options.useDate.validFrom : this.defaultz.useDate.validFrom ;
|
},
|
||||||
let vTo = (typeof this.options.useDate !== 'undefined'
|
validTo() {
|
||||||
&& typeof this.options.useDate.validTo !== 'undefined') ?
|
return (typeof this.options.useDate !== 'undefined' && typeof this.options.useDate.validTo !== 'undefined') ?
|
||||||
this.options.useDate.validTo : this.defaultz.useDate.validTo ;
|
this.options.useDate.validTo : this.defaultz.useDate.validTo ;
|
||||||
return (vFrom || vTo) ? true : false;
|
},
|
||||||
|
useDatePane() {
|
||||||
|
return (this.validFrom || this.validTo) ? true : false;
|
||||||
},
|
},
|
||||||
hasSuggestions() {
|
hasSuggestions() {
|
||||||
// TODO
|
if (typeof(this.context.suggestions) !== 'undefined') {
|
||||||
//return addressSuggestions.length > 0
|
console.log('hasSuggestions', this.context.suggestions);
|
||||||
|
return this.context.suggestions.length > 0;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
displaySuggestions() {
|
displaySuggestions() {
|
||||||
@ -335,7 +353,9 @@ export default {
|
|||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
||||||
console.log('useDatePane', this.useDatePane);
|
//console.log('validFrom', this.validFrom);
|
||||||
|
//console.log('validTo', this.validTo);
|
||||||
|
//console.log('useDatePane', this.useDatePane);
|
||||||
|
|
||||||
console.log('Mounted now !');
|
console.log('Mounted now !');
|
||||||
if (this.context.edit) {
|
if (this.context.edit) {
|
||||||
@ -566,6 +586,22 @@ export default {
|
|||||||
'point': this.entity.selected.address.point.coordinates
|
'point': this.entity.selected.address.point.coordinates
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (this.validFrom) {
|
||||||
|
console.log('add validFrom in fetch body', this.entity.selected.valid.from);
|
||||||
|
newAddress = Object.assign(newAddress, {
|
||||||
|
'validFrom': {
|
||||||
|
datetime: `${this.entity.selected.valid.from.toISOString().split('T')[0]}T00:00:00+0100`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.validTo && null !== this.entity.selected.valid.to) {
|
||||||
|
console.log('add validTo in fetch body', this.entity.selected.valid.to);
|
||||||
|
newAddress = Object.assign(newAddress, {
|
||||||
|
'validTo': {
|
||||||
|
datetime: `${this.entity.selected.valid.to.toISOString().split('T')[0]}T00:00:00+0100`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
if (this.entity.selected.writeNew.postcode) {
|
if (this.entity.selected.writeNew.postcode) {
|
||||||
let newPostcode = this.entity.selected.postcode;
|
let newPostcode = this.entity.selected.postcode;
|
||||||
newPostcode = Object.assign(newPostcode, {
|
newPostcode = Object.assign(newPostcode, {
|
||||||
@ -627,9 +663,12 @@ export default {
|
|||||||
this.flag.loading = false;
|
this.flag.loading = false;
|
||||||
this.flag.success = true;
|
this.flag.success = true;
|
||||||
resolve({
|
resolve({
|
||||||
|
address,
|
||||||
|
targetOrigin: this.context.target,
|
||||||
|
// for "legacy" use:
|
||||||
target: this.context.target.name,
|
target: this.context.target.name,
|
||||||
targetId: this.context.target.id,
|
targetId: this.context.target.id,
|
||||||
addressId: this.entity.address.address_id
|
addressId: this.entity.address.address_id,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}))
|
}))
|
||||||
@ -675,6 +714,9 @@ export default {
|
|||||||
this.flag.loading = false;
|
this.flag.loading = false;
|
||||||
this.flag.success = true;
|
this.flag.success = true;
|
||||||
return resolve({
|
return resolve({
|
||||||
|
address,
|
||||||
|
targetOrigin: this.context.target,
|
||||||
|
// for "legacy" use:
|
||||||
target: this.context.target.name,
|
target: this.context.target.name,
|
||||||
targetId: this.context.target.id,
|
targetId: this.context.target.id,
|
||||||
addressId: this.entity.address.address_id
|
addressId: this.entity.address.address_id
|
||||||
@ -687,18 +729,28 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Method just add closing pane to the callback method
|
*
|
||||||
* (get out step1 show pane, submit button)
|
* @param address the address selected
|
||||||
closePaneAndCallbackSubmit(payload)
|
|
||||||
{
|
|
||||||
//this.initForm();
|
|
||||||
//this.resetPane(); // because parent callback will cast afterLastPaneAction()
|
|
||||||
console.log('will call parent callback method', payload);
|
|
||||||
// callback props method from parent
|
|
||||||
this.addressChangedCallback(payload);
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
pickAddress(address) {
|
||||||
|
console.log('pickAddress', address);
|
||||||
|
duplicateAddress(address).then(newAddress => {
|
||||||
|
this.entity.address = newAddress;
|
||||||
|
this.flag.loading = false;
|
||||||
|
this.flag.success = true;
|
||||||
|
let payload = {
|
||||||
|
address: newAddress,
|
||||||
|
targetOrigin: this.context.target,
|
||||||
|
// for "legacy" use:
|
||||||
|
target: this.context.target.name,
|
||||||
|
targetId: this.context.target.id,
|
||||||
|
addressId: this.entity.address.address_id
|
||||||
|
};
|
||||||
|
this.addressChangedCallback(payload);
|
||||||
|
this.closeSuggestPane();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { dateToISO, ISOToDate, ISOToDatetime } from 'ChillMainAssets/chill/js/date.js';
|
import { dateToISO, ISOToDate } from 'ChillMainAssets/chill/js/date.js';
|
||||||
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
import AddressRenderBox from 'ChillMainAssets/vuejs/_components/Entity/AddressRenderBox.vue';
|
||||||
import ActionButtons from './ActionButtons.vue';
|
import ActionButtons from './ActionButtons.vue';
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div v-if="!hideAddress">
|
<div v-if="!onlyButton">
|
||||||
<div class="loading">
|
<div class="loading">
|
||||||
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
|
<i v-if="flag.loading" class="fa fa-circle-o-notch fa-spin fa-2x fa-fw"></i>
|
||||||
<span class="sr-only">{{ $t('loading') }}</span>
|
<span class="sr-only">{{ $t('loading') }}</span>
|
||||||
@ -28,13 +28,11 @@
|
|||||||
:options="this.options"
|
:options="this.options"
|
||||||
:defaultz="this.defaultz">
|
:defaultz="this.defaultz">
|
||||||
<template v-slot:action>
|
<template v-slot:action>
|
||||||
<li>
|
<button @click.prevent="$emit('openEditPane')"
|
||||||
<button @click.prevent="$emit('openEditPane')"
|
class="btn" :class="getClassButton"
|
||||||
class="btn" :class="getClassButton"
|
type="button" name="button" :title="$t(getTextButton)">
|
||||||
type="button" name="button" :title="$t(getTextButton)">
|
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
||||||
<span v-if="displayTextButton">{{ $t(getTextButton) }}</span>
|
</button>
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
</template>
|
</template>
|
||||||
</action-buttons>
|
</action-buttons>
|
||||||
|
|
||||||
@ -86,9 +84,9 @@ export default {
|
|||||||
getSuccessText() {
|
getSuccessText() {
|
||||||
return (this.context.edit) ? 'address_edit_success' : 'address_new_success';
|
return (this.context.edit) ? 'address_edit_success' : 'address_new_success';
|
||||||
},
|
},
|
||||||
hideAddress() {
|
onlyButton() {
|
||||||
return (typeof this.options.hideAddress !== 'undefined') ?
|
return (typeof this.options.onlyButton !== 'undefined') ?
|
||||||
this.options.hideAddress : this.defaultz.hideAddress;
|
this.options.onlyButton : this.defaultz.onlyButton;
|
||||||
},
|
},
|
||||||
forceRedirect() {
|
forceRedirect() {
|
||||||
return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined'));
|
return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined'));
|
||||||
|
@ -10,13 +10,14 @@
|
|||||||
<h4 class="h3">{{ $t('address_suggestions') }}</h4>
|
<h4 class="h3">{{ $t('address_suggestions') }}</h4>
|
||||||
|
|
||||||
<div class="flex-table AddressSuggestionList">
|
<div class="flex-table AddressSuggestionList">
|
||||||
<div class="item-bloc">
|
<div v-for="a in context.suggestions" class="item-bloc">
|
||||||
<div class="float-button bottom">
|
<div class="float-button bottom">
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="action">
|
<div class="action">
|
||||||
|
<!-- QUESTION normal que ça vienne avant l'adresse ? pourquoi pas après avoir affiché le address-render-box ? -->
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
<button class="btn btn-sm btn-choose">
|
<button class="btn btn-sm btn-choose" @click="this.pickAddress(a)">
|
||||||
{{ $t('use_this_address') }}
|
{{ $t('use_this_address') }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
@ -25,9 +26,7 @@
|
|||||||
<ul class="list-content fa-ul">
|
<ul class="list-content fa-ul">
|
||||||
<li>
|
<li>
|
||||||
<i class="fa fa-li fa-map-marker"></i>
|
<i class="fa fa-li fa-map-marker"></i>
|
||||||
<!--
|
<address-render-box :address="a"></address-render-box>
|
||||||
<address-render-box></address-render-box>
|
|
||||||
-->
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -68,9 +67,14 @@ export default {
|
|||||||
'flag',
|
'flag',
|
||||||
'entity',
|
'entity',
|
||||||
'errorMsg',
|
'errorMsg',
|
||||||
'insideModal'
|
'insideModal',
|
||||||
],
|
],
|
||||||
computed: {},
|
computed: {},
|
||||||
methods: {}
|
methods: {
|
||||||
|
pickAddress(address) {
|
||||||
|
console.log('pickAddress in suggest pane', address);
|
||||||
|
this.$emit('pickAddress', address);
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -53,7 +53,7 @@ containers.forEach((container) => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/// Don't display show renderbox Address: showPane display only a button
|
/// Don't display show renderbox Address: showPane display only a button
|
||||||
hideAddress: container.dataset.hideAddress === 'true' //boolean, default: false
|
onlyButton: container.dataset.onlyButton === 'true' //boolean, default: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<on-the-fly
|
||||||
|
:type="context.type"
|
||||||
|
:id="context.id"
|
||||||
|
:action="context.action"
|
||||||
|
:buttonText="options.buttonText"
|
||||||
|
:displayBadge="options.displayBadge === 'true'"
|
||||||
|
@saveFormOnTheFly="saveFormOnTheFly">
|
||||||
|
</on-the-fly>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import OnTheFly from './components/OnTheFly.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "App",
|
||||||
|
components: {
|
||||||
|
OnTheFly
|
||||||
|
},
|
||||||
|
props: ['onTheFly'],
|
||||||
|
computed: {
|
||||||
|
context() {
|
||||||
|
return this.onTheFly.context;
|
||||||
|
},
|
||||||
|
options() {
|
||||||
|
return this.onTheFly.options;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
//console.log('OnTheFly mounted');
|
||||||
|
//console.log('OnTheFly: data context', this.context);
|
||||||
|
//console.log('OnTheFly: data options', this.options);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
saveFormOnTheFly(payload) {
|
||||||
|
console.log('saveFormOnTheFly', payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
@ -3,7 +3,7 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" :class="{ active: isActive('person') }">
|
<a class="nav-link" :class="{ active: isActive('person') }">
|
||||||
<label for="person">
|
<label for="person">
|
||||||
<input type="radio" name="person" v-model="radioType" value="person">
|
<input type="radio" name="person" id="person" v-model="radioType" value="person">
|
||||||
{{ $t('onthefly.create.person') }}
|
{{ $t('onthefly.create.person') }}
|
||||||
</label>
|
</label>
|
||||||
</a>
|
</a>
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" :class="{ active: isActive('thirdparty') }">
|
<a class="nav-link" :class="{ active: isActive('thirdparty') }">
|
||||||
<label for="thirdparty">
|
<label for="thirdparty">
|
||||||
<input type="radio" name="thirdparty" v-model="radioType" value="thirdparty">
|
<input type="radio" name="thirdparty" id="thirdparty" v-model="radioType" value="thirdparty">
|
||||||
{{ $t('onthefly.create.thirdparty') }}
|
{{ $t('onthefly.create.thirdparty') }}
|
||||||
</label>
|
</label>
|
||||||
</a>
|
</a>
|
||||||
@ -56,6 +56,7 @@ export default {
|
|||||||
radioType: {
|
radioType: {
|
||||||
set(type) {
|
set(type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
console.log('## type:', type, ', action:', this.action);
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
return this.type;
|
return this.type;
|
||||||
@ -71,7 +72,10 @@ export default {
|
|||||||
case 'person':
|
case 'person':
|
||||||
return this.$refs.castPerson.$data.person;
|
return this.$refs.castPerson.$data.person;
|
||||||
case 'thirdparty':
|
case 'thirdparty':
|
||||||
return this.$refs.castThirdparty.$data.thirdparty;
|
let data = this.$refs.castThirdparty.$data.thirdparty;
|
||||||
|
data.name = data.text;
|
||||||
|
data.address = { id: data.address.address_id }
|
||||||
|
return data;
|
||||||
default:
|
default:
|
||||||
throw Error('Invalid type of entity')
|
throw Error('Invalid type of entity')
|
||||||
}
|
}
|
@ -1,6 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<a class="btn btn-sm" target="_blank"
|
<a v-if="isDisplayBadge" @click="openModal">
|
||||||
|
<span class="chill-entity" :class="badgeType">
|
||||||
|
{{ buttonText }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a v-else class="btn btn-sm" target="_blank"
|
||||||
:class="classAction"
|
:class="classAction"
|
||||||
:title="$t(titleAction)"
|
:title="$t(titleAction)"
|
||||||
@click="openModal">
|
@click="openModal">
|
||||||
@ -42,16 +47,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-slot:footer>
|
<template v-slot:footer>
|
||||||
<button v-if="action === 'show'"
|
<a v-if="action === 'show'"
|
||||||
@click="goToLocation(id, type)"
|
:href="buildLocation(id, type)"
|
||||||
:title="$t(titleMessage)"
|
:title="$t(titleMessage)"
|
||||||
class="btn btn-show">{{ $t(buttonMessage) }}
|
class="btn btn-show">{{ $t(buttonMessage) }}
|
||||||
</button>
|
</a>
|
||||||
<button v-else
|
<a v-else
|
||||||
class="btn btn-save"
|
class="btn btn-save"
|
||||||
@click="saveAction">
|
@click="saveAction">
|
||||||
{{ $t('action.save')}}
|
{{ $t('action.save')}}
|
||||||
</button>
|
</a>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
</modal>
|
</modal>
|
||||||
@ -61,7 +66,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
|
import Modal from 'ChillMainAssets/vuejs/_components/Modal.vue';
|
||||||
import OnTheFlyCreate from './OnTheFly/Create.vue';
|
import OnTheFlyCreate from './Create.vue';
|
||||||
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
|
import OnTheFlyPerson from 'ChillPersonAssets/vuejs/_components/OnTheFly/Person.vue';
|
||||||
import OnTheFlyThirdparty from 'ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue';
|
import OnTheFlyThirdparty from 'ChillThirdPartyAssets/vuejs/_components/OnTheFly/ThirdParty.vue';
|
||||||
|
|
||||||
@ -73,7 +78,7 @@ export default {
|
|||||||
OnTheFlyThirdparty,
|
OnTheFlyThirdparty,
|
||||||
OnTheFlyCreate
|
OnTheFlyCreate
|
||||||
},
|
},
|
||||||
props: ['type', 'id', 'action', 'buttonText'],
|
props: ['type', 'id', 'action', 'buttonText', 'displayBadge'],
|
||||||
emits: ['saveFormOnTheFly'],
|
emits: ['saveFormOnTheFly'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -123,17 +128,25 @@ export default {
|
|||||||
return 'action.redirect.' + this.type;
|
return 'action.redirect.' + this.type;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
buttonMessage(){
|
buttonMessage() {
|
||||||
switch (this.type){
|
switch (this.type){
|
||||||
case 'person':
|
case 'person':
|
||||||
return 'onthefly.show.file_' + this.type;
|
return 'onthefly.show.file_' + this.type;
|
||||||
case 'thirdparty':
|
case 'thirdparty':
|
||||||
return 'onthefly.show.file_' + this.type;
|
return 'onthefly.show.file_' + this.type;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
isDisplayBadge() {
|
||||||
|
return (this.displayBadge === true && this.buttonText !== null);
|
||||||
|
},
|
||||||
|
badgeType() {
|
||||||
|
return 'entity-' + this.type + ' badge-' + this.type;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openModal() {
|
openModal() {
|
||||||
|
console.log('## OPEN ON THE FLY MODAL');
|
||||||
|
console.log('## type:', this.type, ', action:', this.action);
|
||||||
this.modal.showModal = true;
|
this.modal.showModal = true;
|
||||||
this.$nextTick(function() {
|
this.$nextTick(function() {
|
||||||
//this.$refs.search.focus();
|
//this.$refs.search.focus();
|
||||||
@ -144,7 +157,6 @@ export default {
|
|||||||
},
|
},
|
||||||
saveAction() {
|
saveAction() {
|
||||||
console.log('saveAction button: create/edit action with', this.type);
|
console.log('saveAction button: create/edit action with', this.type);
|
||||||
|
|
||||||
let
|
let
|
||||||
type = this.type,
|
type = this.type,
|
||||||
data = {} ;
|
data = {} ;
|
||||||
@ -159,10 +171,9 @@ export default {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (typeof this.type === 'undefined') {
|
if (typeof this.type === 'undefined') { // action=create
|
||||||
type = this.$refs.castNew.radioType;
|
type = this.$refs.castNew.radioType;
|
||||||
data = this.$refs.castNew.castDataByType();
|
data = this.$refs.castNew.castDataByType();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw 'error with object type';
|
throw 'error with object type';
|
||||||
}
|
}
|
||||||
@ -173,11 +184,12 @@ export default {
|
|||||||
|
|
||||||
this.modal.showModal = false;
|
this.modal.showModal = false;
|
||||||
},
|
},
|
||||||
goToLocation(id, type){
|
buildLocation(id, type) {
|
||||||
if(type == 'person'){
|
if (type === 'person') {
|
||||||
window.location = `../../person/${id}/general`
|
// TODO i18n
|
||||||
} else if(type == 'thirdparty') {
|
return `/fr/person/${id}/general`;
|
||||||
window.location = `../../thirdparty/thirdparty/${id}/show`
|
} else if (type === 'thirdparty') {
|
||||||
|
return `/fr/thirdparty/thirdparty/${id}/show`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,5 +200,4 @@ export default {
|
|||||||
a {
|
a {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
@ -0,0 +1,24 @@
|
|||||||
|
const ontheflyMessages = {
|
||||||
|
fr: {
|
||||||
|
onthefly: {
|
||||||
|
show: {
|
||||||
|
person: "Détails de l'usager",
|
||||||
|
thirdparty: "Détails du tiers",
|
||||||
|
file_person: "Ouvrir la fiche de l'usager",
|
||||||
|
file_thirdparty: "Voir le Tiers",
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
person: "Modifier un usager",
|
||||||
|
thirdparty: "Modifier un tiers"
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
button: "Créer \"{q}\"",
|
||||||
|
title: "Création d'un nouvel usager ou d'un tiers professionnel",
|
||||||
|
person: "un nouvel usager",
|
||||||
|
thirdparty: "un nouveau tiers professionnel"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ontheflyMessages };
|
@ -0,0 +1,35 @@
|
|||||||
|
import { createApp } from "vue";
|
||||||
|
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n';
|
||||||
|
import { ontheflyMessages } from './i18n.js';
|
||||||
|
import App from "./App.vue";
|
||||||
|
|
||||||
|
const i18n = _createI18n( ontheflyMessages );
|
||||||
|
|
||||||
|
let containers = document.querySelectorAll('.onthefly-container');
|
||||||
|
|
||||||
|
containers.forEach((container) => {
|
||||||
|
|
||||||
|
const app = createApp({
|
||||||
|
template: `<app :onTheFly="this.onTheFly" ></app>`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
onTheFly: {
|
||||||
|
context: {
|
||||||
|
action: container.dataset.action,
|
||||||
|
type: container.dataset.targetName,
|
||||||
|
id: parseInt(container.dataset.targetId),
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
buttonText: container.dataset.buttonText || null,
|
||||||
|
displayBadge: container.dataset.displayBadge || false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.use(i18n)
|
||||||
|
.component('app', App)
|
||||||
|
.mount(container);
|
||||||
|
|
||||||
|
//console.log('container dataset', container.dataset);
|
||||||
|
});
|
@ -53,24 +53,6 @@ const messages = {
|
|||||||
top: "Haut",
|
top: "Haut",
|
||||||
bottom: "Bas",
|
bottom: "Bas",
|
||||||
},
|
},
|
||||||
onthefly: {
|
|
||||||
show: {
|
|
||||||
person: "Détails de l'usager",
|
|
||||||
thirdparty: "Détails du tiers",
|
|
||||||
file_person: "Ouvrir la fiche de l'usager",
|
|
||||||
file_thirdparty: "Voir le Tiers",
|
|
||||||
},
|
|
||||||
edit: {
|
|
||||||
person: "Modifier un usager",
|
|
||||||
thirdparty: "Modifier un tiers"
|
|
||||||
},
|
|
||||||
create: {
|
|
||||||
button: "Créer \"{q}\"",
|
|
||||||
title: "Création d'un nouvel usager ou d'un tiers professionnel",
|
|
||||||
person: "un nouvel usager",
|
|
||||||
thirdparty: "un nouveau tiers professionnel"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
renderbox: {
|
renderbox: {
|
||||||
person: "Usager",
|
person: "Usager",
|
||||||
birthday: {
|
birthday: {
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
* stickyActions bool (default: false)
|
* stickyActions bool (default: false)
|
||||||
* useValidFrom bool (default: false)
|
* useValidFrom bool (default: false)
|
||||||
* useValidTo bool (default: false)
|
* useValidTo bool (default: false)
|
||||||
* hideAddress bool (default: false)
|
* onlyButton bool (default: false)
|
||||||
#}
|
#}
|
||||||
<div class="address-container"
|
<div class="address-container"
|
||||||
|
|
||||||
@ -69,7 +69,7 @@
|
|||||||
data-use-valid-to="true"
|
data-use-valid-to="true"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if hideAddress is defined and hideAddress == 1 %}
|
{% if onlyButton is defined and onlyButton == 1 %}
|
||||||
data-hide-address="true"
|
data-hide-address="true"
|
||||||
{% endif %}
|
{% endif %}
|
||||||
></div>
|
></div>
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
{% extends '@ChillMain/Admin/layout_permissions.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}{{ ('crud.' ~ crud_name ~ '.index.title')|trans({'%crud_name%': crud_name}) }}{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% embed '@ChillMain/CRUD/_index.html.twig' %}
|
||||||
|
{% endembed %}
|
||||||
|
{% endblock content %}
|
@ -1,17 +1,15 @@
|
|||||||
{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %}
|
{% extends "@ChillMain/Admin/layoutWithVerticalMenu.html.twig" %}
|
||||||
|
|
||||||
|
{% block vertical_menu_content %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
{% block admin_content %}
|
{% block admin_content %}
|
||||||
<h1>{{ 'Administration interface'|trans }}</h1>
|
<h1>{{ 'Administration interface'|trans }}</h1>
|
||||||
|
|
||||||
{{ 'welcome_message_raw'|trans|raw }}
|
<p>{{ 'Welcome to the admin section !'|trans }}</p>
|
||||||
|
|
||||||
<div>
|
{{ chill_menu('admin_index', {
|
||||||
<h2>{{ 'Configuration alerts'|trans }}</h2>
|
'layout': '@ChillMain/Admin/menu_admin_index.html.twig'
|
||||||
|
}) }}
|
||||||
<p>{{ 'Here you can check the configuration of your instance.'|trans }}</p>
|
|
||||||
|
|
||||||
{{ chill_widget('configuration_warnings', {}) }}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -1,26 +1,3 @@
|
|||||||
{#
|
|
||||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
|
||||||
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#}
|
|
||||||
|
|
||||||
{#
|
|
||||||
The layout of the admin section. All the page / template of the admin section must use this
|
|
||||||
layout.
|
|
||||||
#}
|
|
||||||
|
|
||||||
{% extends "@ChillMain/layout.html.twig" %}
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
{% block navigation_search_bar %}{% endblock %}
|
{% block navigation_search_bar %}{% endblock %}
|
||||||
|
@ -1,37 +1,14 @@
|
|||||||
{#
|
|
||||||
* Copyright (C) 2014-2015, Champs Libres Cooperative SCRLFS,
|
|
||||||
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#}
|
|
||||||
|
|
||||||
{#
|
|
||||||
The layout of the admin section. All the page / template of the admin section must use this
|
|
||||||
layout.
|
|
||||||
#}
|
|
||||||
|
|
||||||
{% extends "@ChillMain/layoutWithVerticalMenu.html.twig" %}
|
{% extends "@ChillMain/layoutWithVerticalMenu.html.twig" %}
|
||||||
|
|
||||||
{% block navigation_search_bar %}{% endblock %}
|
{% block navigation_search_bar %}{% endblock %}
|
||||||
{% block navigation_section_menu %}
|
{% block navigation_section_menu %}
|
||||||
{{ chill_menu('admin_section', {
|
{{ chill_menu('admin_section', {
|
||||||
'layout': '@ChillMain/Menu/adminSection.html.twig',
|
'layout': '@ChillMain/Admin/menu_admin_section.html.twig',
|
||||||
}) }}
|
}) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block layout_wvm_content %}
|
{% block layout_wvm_content %}
|
||||||
{% block admin_content %}<!-- block personcontent empty -->
|
{% block admin_content %}
|
||||||
<h2>{{ 'Welcome to the admin section !'|trans }}</h2>
|
<!-- block admin content emty -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
{% block vertical_menu_content %}
|
{% block vertical_menu_content %}
|
||||||
{{ chill_menu('admin_permissions', {
|
{{ chill_menu('admin_permissions', {
|
||||||
'layout': '@ChillMain/Menu/admin_permissions.html.twig',
|
'layout': '@ChillMain/Admin/menu_admin_permissions.html.twig',
|
||||||
}) }}
|
}) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
<div class="{{ 'menu-' ~ menus.name }}">
|
||||||
|
<ul>
|
||||||
|
{% for menu in menus %}
|
||||||
|
<li>
|
||||||
|
<a class=""
|
||||||
|
href="{{ menu.uri }}">
|
||||||
|
<h3>{{ menu.label|trans }}</h3>
|
||||||
|
|
||||||
|
{% if menu.extras.explain is defined %}
|
||||||
|
<div class="" >
|
||||||
|
{{ menu.extras.explain|trans }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
@ -1,10 +1,11 @@
|
|||||||
|
{% set formId = crudMainFormId|default('crud_main_form') %}
|
||||||
<div class="{% block crud_content_main_div_class %}{% endblock %}">
|
<div class="{% block crud_content_main_div_class %}{% endblock %}">
|
||||||
{% block crud_content_header %}
|
{% block crud_content_header %}
|
||||||
<h1>{{ ('crud.'~crud_name~'.title_edit')|trans }}</h1>
|
<h1>{{ ('crud.'~crud_name~'.title_edit')|trans }}</h1>
|
||||||
{% endblock crud_content_header %}
|
{% endblock crud_content_header %}
|
||||||
|
|
||||||
{% block crud_content_form %}
|
{% block crud_content_form %}
|
||||||
{{ form_start(form) }}
|
{{ form_start(form, { 'attr' : { 'id': formId } } ) }}
|
||||||
|
|
||||||
{% block crud_content_form_rows %}
|
{% block crud_content_form_rows %}
|
||||||
{% for f in form %}
|
{% for f in form %}
|
||||||
@ -12,6 +13,10 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock crud_content_form_rows %}
|
{% endblock crud_content_form_rows %}
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% block crud_content_after_form %}{% endblock %}
|
||||||
|
|
||||||
{% block crud_content_form_actions %}
|
{% block crud_content_form_actions %}
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
{% block content_form_actions_back %}
|
{% block content_form_actions_back %}
|
||||||
@ -42,14 +47,14 @@
|
|||||||
{% endblock content_form_actions_view %}
|
{% endblock content_form_actions_view %}
|
||||||
{% block content_form_actions_save_and_close %}
|
{% block content_form_actions_save_and_close %}
|
||||||
<li class="">
|
<li class="">
|
||||||
<button type="submit" name="submit" value="save-and-close" class="btn btn-update">
|
<button type="submit" name="submit" value="save-and-close" class="btn btn-update" form="{{ formId }}">
|
||||||
{{ 'crud.edit.save_and_close'|trans }}
|
{{ 'crud.edit.save_and_close'|trans }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content_form_actions_save_and_show %}
|
{% block content_form_actions_save_and_show %}
|
||||||
<li class="">
|
<li class="">
|
||||||
<button type="submit" name="submit" value="save-and-show" class="btn btn-update">
|
<button type="submit" name="submit" value="save-and-show" class="btn btn-update" form="{{ formId }}">
|
||||||
{{ 'crud.edit.save_and_show'|trans }}
|
{{ 'crud.edit.save_and_show'|trans }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
@ -58,6 +63,5 @@
|
|||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{{ form_end(form) }}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
{% endif %}{% endfor %}
|
{% endif %}{% endfor %}
|
||||||
{% endblock crud_content_form_rows %}
|
{% endblock crud_content_form_rows %}
|
||||||
|
|
||||||
{% block crud_content_form_actions %}
|
{% block crud_content_after_form %}{% endblock %}
|
||||||
|
|
||||||
|
{% block crud_content_form_actions %}
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
{% block content_form_actions_back %}
|
{% block content_form_actions_back %}
|
||||||
<li class="cancel">
|
<li class="cancel">
|
||||||
|
@ -1,20 +1,3 @@
|
|||||||
{#
|
|
||||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
|
|
||||||
* <info@champs-libres.coop> / <http://www.champs-libres.coop>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#}
|
|
||||||
<header>
|
<header>
|
||||||
<nav class="navbar navbar-dark bg-primary navbar-expand-md">
|
<nav class="navbar navbar-dark bg-primary navbar-expand-md">
|
||||||
<div class="container-xxl">
|
<div class="container-xxl">
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
{% for menu in menus %}
|
{% for menu in menus %}
|
||||||
{% if is_granted('ROLE_PREVIOUS_ADMIN') and menu.name == 'Logout' %}
|
{% if is_granted('ROLE_PREVIOUS_ADMIN') and menu.name == 'Logout' %}
|
||||||
<a class="dropdown-item list-group-item bg-dark text-white"
|
<a class="dropdown-item list-group-item bg-dark text-white"
|
||||||
href="{{ path('admin_user', {'_switch_user': '_exit'}) }}">
|
href="{{ path('chill_crud_admin_user_index', {'_switch_user': '_exit'}) }}">
|
||||||
{{ 'Exit impersonation'|trans }}
|
{{ 'Exit impersonation'|trans }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="dropdown-item list-group-item bg-dark text-white"
|
<a class="dropdown-item list-group-item bg-dark text-white"
|
||||||
|
@ -25,13 +25,9 @@
|
|||||||
<li class="title">
|
<li class="title">
|
||||||
{% block v_menu_title %}<!-- title of the verticalMenu is empty -->{% endblock %}
|
{% block v_menu_title %}<!-- title of the verticalMenu is empty -->{% endblock %}
|
||||||
</li>
|
</li>
|
||||||
{% for route in routes %}
|
{% for menu in menus %}
|
||||||
<li class="{% apply spaceless %}
|
<li class="{% if menu is knp_menu_current %}current {% endif %}">
|
||||||
{% if route.key == activeRouteKey %}
|
<a href="{{ menu.uri }}" >{{ menu.label|trans }}</a>
|
||||||
active
|
|
||||||
{% endif %}
|
|
||||||
{% endapply %} ">
|
|
||||||
<a href="{{ path(route.key, args ) }}" >{{ route.label|trans }}</a>
|
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
@ -0,0 +1,37 @@
|
|||||||
|
{#
|
||||||
|
This Twig template include load vue_onthefly component.
|
||||||
|
It push all variables from context in OnTheFly/App.vue.
|
||||||
|
|
||||||
|
OPTIONS
|
||||||
|
* targetEntity {
|
||||||
|
name: string 'person', 'thirdparty'
|
||||||
|
id: integer
|
||||||
|
}
|
||||||
|
* action string 'show', 'edit', 'create'
|
||||||
|
* buttonText string
|
||||||
|
* displayBadge boolean (default: false) replace button by badge, need to define buttonText for content
|
||||||
|
|
||||||
|
#}
|
||||||
|
<span class="onthefly-container"
|
||||||
|
|
||||||
|
data-target-name="{{ targetEntity.name|e('html_attr') }}"
|
||||||
|
data-target-id="{{ targetEntity.id|e('html_attr') }}"
|
||||||
|
|
||||||
|
{% if action is defined %}
|
||||||
|
data-action="{{ action|e('html_attr') }}"
|
||||||
|
{% else %}
|
||||||
|
data-action="show"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if buttonText is defined %}
|
||||||
|
data-button-text="{{ buttonText|e('html_attr') }}"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if displayBadge is defined and displayBadge == 1 %}
|
||||||
|
data-display-badge="true"
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
></span>
|
||||||
|
|
||||||
|
{{ encore_entry_script_tags('vue_onthefly') }}
|
||||||
|
{{ encore_entry_link_tags('vue_onthefly') }}
|
@ -1,78 +1,56 @@
|
|||||||
{% extends '@ChillMain/Admin/layout_permissions.html.twig' %}
|
{% extends '@ChillMain/Admin/Permission/layout_crud_permission_index.html.twig' %}
|
||||||
|
|
||||||
{% block title %}{{ 'User edit'|trans }}{% endblock %}
|
|
||||||
|
|
||||||
{% block admin_content -%}
|
{% block admin_content -%}
|
||||||
<h1>{{ 'User edit'|trans }}</h1>
|
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
|
||||||
|
{% block crud_content_after_form %}
|
||||||
|
<h2>{{ 'Permissions granted'|trans }}</h2>
|
||||||
|
|
||||||
{{ form_start(edit_form) }}
|
{% if entity.groupcenters|length > 0 %}
|
||||||
|
<table>
|
||||||
{{ form_row(edit_form.username) }}
|
<thead>
|
||||||
{{ form_row(edit_form.email) }}
|
<tr>
|
||||||
{{ form_row(edit_form.enabled, { 'label': "User'status"}) }}
|
<th>{{ 'Permission group'|trans }}</th>
|
||||||
|
<th>{{ 'Center'|trans }}</th>
|
||||||
{{ form_widget(edit_form.submit, { 'attr': { 'class' : 'btn btn-chill-green center' } } ) }}
|
<th> </th>
|
||||||
<a href="{{ path('admin_user_edit_password', { 'id' : entity.id }) }}" class="btn btn-chill-orange">{{ 'Edit password'|trans }}</a>
|
</tr>
|
||||||
|
</thead>
|
||||||
{{ form_end(edit_form) }}
|
<tbody>
|
||||||
|
{% for groupcenter in entity.groupcenters %}
|
||||||
<h2>{{ 'Permissions granted'|trans }}</h2>
|
<tr>
|
||||||
|
<td>
|
||||||
{% if entity.groupcenters|length > 0 %}
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{{ 'Permission group'|trans }}</th>
|
|
||||||
<th>{{ 'Center'|trans }}</th>
|
|
||||||
<th> </th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for groupcenter in entity.groupcenters %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<span class="user_group permissionsgroup">
|
<span class="user_group permissionsgroup">
|
||||||
{{ groupcenter.permissionsgroup.name }}
|
{{ groupcenter.permissionsgroup.name }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="user_group center">
|
<span class="user_group center">
|
||||||
{{ groupcenter.center.name }}
|
{{ groupcenter.center.name }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ form_start(delete_groupcenter_form[groupcenter.id]) }}
|
{{ form_start(delete_groupcenter_form[groupcenter.id]) }}
|
||||||
{{ form_row(delete_groupcenter_form[groupcenter.id].submit, { 'attr': { 'class': 'btn btn-chill-red' } } ) }}
|
{{ form_row(delete_groupcenter_form[groupcenter.id].submit, { 'attr': { 'class': 'btn btn-chill-red' } } ) }}
|
||||||
{{ form_rest(delete_groupcenter_form[groupcenter.id]) }}
|
{{ form_rest(delete_groupcenter_form[groupcenter.id]) }}
|
||||||
{{ form_end(delete_groupcenter_form[groupcenter.id]) }}
|
{{ form_end(delete_groupcenter_form[groupcenter.id]) }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>{{ 'Any permissions granted to this user'|trans }}.</p>
|
<p>{{ 'Any permissions granted to this user'|trans }}.</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h3>{{ 'Grant new permissions'|trans }}</h3>
|
<h3>{{ 'Grant new permissions'|trans }}</h3>
|
||||||
|
|
||||||
{{ form_start(add_groupcenter_form) }}
|
{{ form_start(add_groupcenter_form) }}
|
||||||
{{ form_row(add_groupcenter_form.composed_groupcenter.center) }}
|
{{ form_row(add_groupcenter_form.composed_groupcenter.center) }}
|
||||||
{{ form_row(add_groupcenter_form.composed_groupcenter.permissionsgroup) }}
|
{{ form_row(add_groupcenter_form.composed_groupcenter.permissionsgroup) }}
|
||||||
{{ form_row(add_groupcenter_form.submit, { 'attr' : { 'class': 'btn btn-chill-green' } } ) }}
|
{{ form_row(add_groupcenter_form.submit, { 'attr' : { 'class': 'btn btn-chill-green' } } ) }}
|
||||||
|
|
||||||
{{ form_end(add_groupcenter_form) }}
|
{{ form_end(add_groupcenter_form) }}
|
||||||
|
|
||||||
<ul class="record_actions">
|
{% endblock %}
|
||||||
<li>
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
<a href="{{ path('admin_user_show', { 'id': entity.id }) }}">
|
{% endembed %}
|
||||||
{{ 'show'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('admin_user') }}">
|
|
||||||
{{ 'Back to the list'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{% extends '@ChillMain/Admin/layout_permissions.html.twig' %}
|
{% extends '@ChillMain/Admin/Permission/layout_crud_permission_index.html.twig' %}
|
||||||
|
|
||||||
{% block title %}{{ 'Edit password for %username%'|trans( { '%username%': entity.username } ) }}{% endblock %}
|
{% block title %}{{ 'Edit password for %username%'|trans( { '%username%': entity.username } ) }}{% endblock %}
|
||||||
|
|
||||||
@ -7,19 +7,17 @@
|
|||||||
|
|
||||||
{{ form_start(edit_form) }}
|
{{ form_start(edit_form) }}
|
||||||
{{ form_row(edit_form.new_password) }}
|
{{ form_row(edit_form.new_password) }}
|
||||||
{{ form_widget(edit_form.submit, { 'attr': { 'class': 'btn btn-chill-orange' } } ) }}
|
|
||||||
{{ form_end(edit_form) }}
|
|
||||||
|
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li class="cancel">
|
||||||
<a href="{{ path('admin_user') }}">
|
<a href="{{ chill_return_path_or('chill_crud_admin_user_index') }}" class="btn btn-cancel">
|
||||||
{{ 'Back to the list'|trans }}
|
{{ 'Cancel'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ path('admin_user_edit', { 'id' : entity.id }) }}">
|
{{ form_widget(edit_form.submit, { 'attr': { 'class': 'btn btn-edit' } } ) }}
|
||||||
{{ 'Back to the user edition'|trans }}
|
</li>
|
||||||
</a>
|
</ul>
|
||||||
</li>
|
|
||||||
</ul>
|
{{ form_end(edit_form) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,53 +1,60 @@
|
|||||||
{% extends '@ChillMain/Admin/layout_permissions.html.twig' %}
|
{% extends '@ChillMain/Admin/Permission/layout_crud_permission_index.html.twig' %}
|
||||||
|
|
||||||
{% block title %}{{ 'user list'|trans|capitalize }}{% endblock %}
|
|
||||||
|
|
||||||
{% block admin_content -%}
|
{% block admin_content -%}
|
||||||
<h1>{{ 'user list'|trans|capitalize }}</h1>
|
{% embed '@ChillMain/CRUD/_index.html.twig' %}
|
||||||
|
{% block table_entities_thead_tr %}
|
||||||
<table class="records_list">
|
<th>{{ 'crud.admin_user.index.is_active'|trans }}</th>
|
||||||
<thead>
|
<th>{{ 'crud.admin_user.index.usernames'|trans }}</th>
|
||||||
<tr>
|
<th>{{ 'crud.admin_user.index.mains'|trans }}</th>
|
||||||
<th>{{ 'Username'|trans|capitalize }}</th>
|
<th> </th>
|
||||||
<th>{{ 'Actions'|trans|capitalize }}</th>
|
{% endblock %}
|
||||||
</tr>
|
{% block table_entities_tbody %}
|
||||||
</thead>
|
{% for entity in entities %}
|
||||||
<tbody>
|
<tr data-username="{{ entity.username|e('html_attr') }}">
|
||||||
{% for entity in entities %}
|
|
||||||
<tr class="{% if entity.isEnabled == false %}user-disabled{% else %}user-enabled{% endif %}" >
|
|
||||||
<td><a href="{{ path('admin_user_show', { 'id': entity.id }) }}">{{ entity.username }}</a></td>
|
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
{% if entity.isEnabled %}
|
||||||
<li>
|
<i class="fa fa-check chill-green"></i>
|
||||||
<a href="{{ path('admin_user_show', { 'id': entity.id }) }}">{{ 'show'|trans }}</a>
|
{% else %}
|
||||||
</li>
|
<i class="fa fa-times chill-red"></i>
|
||||||
<li>
|
|
||||||
<a href="{{ path('admin_user_edit', { 'id': entity.id }) }}">{{ 'edit'|trans }}</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('admin_user_edit_password', { 'id' : entity.id }) }}">{{ 'Edit password'|trans }}</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
{% if is_granted('ROLE_ALLOWED_TO_SWITCH') %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('chill_main_homepage', {'_switch_user': entity.username }) }}">
|
|
||||||
{{ 'Impersonate'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ entity.username }}
|
||||||
|
<br/>
|
||||||
|
{{ entity.label }}
|
||||||
|
<br/>
|
||||||
|
{{ entity.email }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if entity.userJob %}
|
||||||
|
{{ entity.userJob.label|localize_translatable_string }}
|
||||||
|
<br/>
|
||||||
|
{% endif %}
|
||||||
|
{% if entity.mainScope %}
|
||||||
|
{{ entity.mainScope.name|localize_translatable_string }}
|
||||||
|
<br/>
|
||||||
|
{% endif %}
|
||||||
|
{% if entity.mainCenter %}
|
||||||
|
{{ entity.mainCenter.name }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-edit" href="{{ path('chill_crud_admin_user_edit', { 'id': entity.id }) }}"></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-chill-red" href="{{ path('admin_user_edit_password', { 'id' : entity.id }) }}" title="{{ 'Edit password'|trans|e('html_attr') }}"><i class="fa fa-ellipsis-h"></i></a>
|
||||||
|
</li>
|
||||||
|
{% if is_granted('ROLE_ALLOWED_TO_SWITCH') %}
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-chill-blue" href="{{ path('chill_main_homepage', {'_switch_user': entity.username }) }}" title="{{ "Impersonate"|trans|e('html_attr') }}"><i class="fa fa-user-secret"></i></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
{% endblock %}
|
||||||
</table>
|
{% endembed %}
|
||||||
|
{% endblock %}
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('admin_user_new') }}">
|
|
||||||
{{ 'Add a new user'|trans|capitalize }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% endblock admin_content %}
|
|
||||||
|
@ -1,22 +1,7 @@
|
|||||||
{% extends '@ChillMain/Admin/layout_permissions.html.twig' %}
|
{% extends '@ChillMain/Admin/Permission/layout_crud_permission_index.html.twig' %}
|
||||||
|
|
||||||
{% block title %}{{ 'User creation'|trans }}{% endblock %}
|
|
||||||
|
|
||||||
{% block admin_content -%}
|
{% block admin_content -%}
|
||||||
<h1>{{ 'User creation'|trans }}</h1>
|
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
|
||||||
|
{% block content_form_actions_save_and_show %}{% endblock %}
|
||||||
{{ form_start(form) }}
|
{% endembed %}
|
||||||
{{ form_row(form.username) }}
|
|
||||||
{{ form_row(form.email) }}
|
|
||||||
{{ form_row(form.plainPassword) }}
|
|
||||||
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-chill-blue' } }) }}
|
|
||||||
{{ form_end(form) }}
|
|
||||||
|
|
||||||
<ul class="record_actions">
|
|
||||||
<li>
|
|
||||||
<a href="{{ path('admin_user') }}">
|
|
||||||
{{ 'Back to the list'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,25 +1,3 @@
|
|||||||
{#
|
|
||||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
|
|
||||||
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#}
|
|
||||||
|
|
||||||
{#
|
|
||||||
The basic layout of Chill. All the page / template of Chill must use this template.
|
|
||||||
#}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
<head>
|
<head>
|
||||||
|
@ -1,26 +1,3 @@
|
|||||||
{#
|
|
||||||
* Copyright (C) 2014-2021, Champs Libres Cooperative SCRLFS,
|
|
||||||
<info@champs-libres.coop> / <http://www.champs-libres.coop>
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU Affero General Public License as
|
|
||||||
* published by the Free Software Foundation, either version 3 of the
|
|
||||||
* License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU Affero General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#}
|
|
||||||
|
|
||||||
{#
|
|
||||||
Layout with a vertical menu and a conainer for the content (like admin, export)
|
|
||||||
( for the vertical menu you can extends Menu/veticalMenu.html.twig ).
|
|
||||||
#}
|
|
||||||
|
|
||||||
{% extends "@ChillMain/layout.html.twig" %}
|
{% extends "@ChillMain/layout.html.twig" %}
|
||||||
|
|
||||||
{% block sublayout_content %}
|
{% block sublayout_content %}
|
||||||
|
@ -51,12 +51,13 @@ class AdminSectionMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
])
|
])
|
||||||
->setExtras([
|
->setExtras([
|
||||||
'icons' => ['key'],
|
'icons' => ['key'],
|
||||||
'order' => 200
|
'order' => 200,
|
||||||
|
'explain' => "Configure permissions for users"
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getMenuIds(): array
|
public static function getMenuIds(): array
|
||||||
{
|
{
|
||||||
return [ 'admin_section' ];
|
return [ 'admin_section', 'admin_index' ];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Routing\MenuBuilder;
|
||||||
|
|
||||||
|
use Knp\Menu\MenuItem;
|
||||||
|
|
||||||
|
class PermissionMenuBuilder implements \Chill\MainBundle\Routing\LocalMenuBuilderInterface
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public static function getMenuIds(): array
|
||||||
|
{
|
||||||
|
return [ 'admin_permissions' ];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildMenu($menuId, MenuItem $menu, array $parameters)
|
||||||
|
{
|
||||||
|
$menu->addChild('Permissions group list', [
|
||||||
|
'route' => 'admin_permissionsgroup'
|
||||||
|
])->setExtras([
|
||||||
|
'order' => 300
|
||||||
|
]);
|
||||||
|
|
||||||
|
$menu->addChild('crud.admin_user.index.title', [
|
||||||
|
'route' => 'chill_crud_admin_user_index'
|
||||||
|
])->setExtras(['order' => 400]);
|
||||||
|
|
||||||
|
$menu->addChild('List circles', [
|
||||||
|
'route' => 'admin_scope'
|
||||||
|
])->setExtras(['order' => 200]);
|
||||||
|
|
||||||
|
$menu->addChild('Center list', [
|
||||||
|
'route' => 'admin_center'
|
||||||
|
])->setExtras(['order' => 100]);
|
||||||
|
|
||||||
|
$menu->addChild('User jobs', [
|
||||||
|
'route' => 'chill_crud_admin_user_job_index'
|
||||||
|
])->setExtras(['order' => 150]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -17,12 +17,11 @@
|
|||||||
*/
|
*/
|
||||||
namespace Chill\MainBundle\Test;
|
namespace Chill\MainBundle\Test;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare a client authenticated with a user
|
* Prepare a client authenticated with a user
|
||||||
*
|
|
||||||
* @author Julien Fastré <julien.fastre@champs-libres.coop>
|
|
||||||
*/
|
*/
|
||||||
trait PrepareClientTrait
|
trait PrepareClientTrait
|
||||||
{
|
{
|
||||||
@ -37,7 +36,7 @@ trait PrepareClientTrait
|
|||||||
public function getClientAuthenticated(
|
public function getClientAuthenticated(
|
||||||
$username = 'center a_social',
|
$username = 'center a_social',
|
||||||
$password = 'password'
|
$password = 'password'
|
||||||
) {
|
): KernelBrowser {
|
||||||
if (!$this instanceof WebTestCase) {
|
if (!$this instanceof WebTestCase) {
|
||||||
throw new \LogicException(sprintf("The current class does not "
|
throw new \LogicException(sprintf("The current class does not "
|
||||||
. "implements %s", WebTestCase::class));
|
. "implements %s", WebTestCase::class));
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Address;
|
||||||
|
use Chill\MainBundle\Repository\AddressRepository;
|
||||||
|
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||||
|
|
||||||
|
class AddressControllerTest extends \Symfony\Bundle\FrameworkBundle\Test\WebTestCase
|
||||||
|
{
|
||||||
|
private KernelBrowser $client;
|
||||||
|
|
||||||
|
use PrepareClientTrait;
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$this->client = $this->getClientAuthenticated();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider generateAddressIds
|
||||||
|
* @param int $addressId
|
||||||
|
*/
|
||||||
|
public function testDuplicate(int $addressId)
|
||||||
|
{
|
||||||
|
$this->client->request('POST', "/api/1.0/main/address/$addressId/duplicate.json");
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful('test that duplicate is successful');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateAddressIds()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
$qb = $em->createQueryBuilder();
|
||||||
|
$addresses = $qb->select('a')->from(Address::class, 'a')
|
||||||
|
->setMaxResults(2)
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
|
||||||
|
foreach ($addresses as $a) {
|
||||||
|
yield [ $a->getId() ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,17 @@
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Tests\Controller;
|
namespace Chill\MainBundle\Tests\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
|
||||||
|
|
||||||
class UserControllerTest extends WebTestCase
|
class UserControllerTest extends WebTestCase
|
||||||
{
|
{
|
||||||
private $client;
|
private $client;
|
||||||
|
|
||||||
|
private array $toDelete = [];
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
self::bootKernel();
|
self::bootKernel();
|
||||||
@ -22,18 +27,14 @@ class UserControllerTest extends WebTestCase
|
|||||||
public function testList()
|
public function testList()
|
||||||
{
|
{
|
||||||
// get the list
|
// get the list
|
||||||
$crawler = $this->client->request('GET', '/fr/admin/user/');
|
$crawler = $this->client->request('GET', '/fr/admin/main/user');
|
||||||
$this->assertEquals(200, $this->client->getResponse()->getStatusCode(),
|
$this->assertEquals(200, $this->client->getResponse()->getStatusCode(),
|
||||||
"Unexpected HTTP status code for GET /admin/user/");
|
"Unexpected HTTP status code for GET /admin/main/user");
|
||||||
|
|
||||||
$link = $crawler->selectLink('Ajouter un nouvel utilisateur')->link();
|
|
||||||
$this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $link);
|
|
||||||
$this->assertRegExp('|/fr/admin/user/new$|', $link->getUri());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNew()
|
public function testNew()
|
||||||
{
|
{
|
||||||
$crawler = $this->client->request('GET', '/fr/admin/user/new');
|
$crawler = $this->client->request('GET', '/fr/admin/main/user/new');
|
||||||
|
|
||||||
$username = 'Test_user'. uniqid();
|
$username = 'Test_user'. uniqid();
|
||||||
$password = 'Password1234!';
|
$password = 'Password1234!';
|
||||||
@ -54,22 +55,15 @@ class UserControllerTest extends WebTestCase
|
|||||||
$this->assertGreaterThan(0, $crawler->filter('td:contains("Test_user")')->count(),
|
$this->assertGreaterThan(0, $crawler->filter('td:contains("Test_user")')->count(),
|
||||||
'Missing element td:contains("Test user")');
|
'Missing element td:contains("Test user")');
|
||||||
|
|
||||||
$update = $crawler->selectLink('Modifier')->link();
|
|
||||||
|
|
||||||
$this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $update);
|
|
||||||
$this->assertRegExp('|/fr/admin/user/[0-9]{1,}/edit$|', $update->getUri());
|
|
||||||
|
|
||||||
//test the auth of the new client
|
//test the auth of the new client
|
||||||
$this->isPasswordValid($username, $password);
|
$this->isPasswordValid($username, $password);
|
||||||
|
|
||||||
return $update;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function isPasswordValid($username, $password)
|
protected function isPasswordValid($username, $password)
|
||||||
{
|
{
|
||||||
/* @var $passwordEncoder \Symfony\Component\Security\Core\Encoder\UserPasswordEncoder */
|
/* @var $passwordEncoder \Symfony\Component\Security\Core\Encoder\UserPasswordEncoder */
|
||||||
$passwordEncoder = self::$kernel->getContainer()
|
$passwordEncoder = self::$container
|
||||||
->get('security.password_encoder');
|
->get(UserPasswordEncoderInterface::class);
|
||||||
|
|
||||||
$user = self::$kernel->getContainer()
|
$user = self::$kernel->getContainer()
|
||||||
->get('doctrine.orm.entity_manager')
|
->get('doctrine.orm.entity_manager')
|
||||||
@ -81,46 +75,33 @@ class UserControllerTest extends WebTestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\DomCrawler\Link $update
|
* @dataProvider dataGenerateUserId
|
||||||
* @depends testNew
|
|
||||||
*/
|
*/
|
||||||
public function testUpdate(\Symfony\Component\DomCrawler\Link $update)
|
public function testUpdate(int $userId, string $username)
|
||||||
{
|
{
|
||||||
$crawler = $this->client->click($update);
|
$crawler = $this->client->request('GET', "/fr/admin/main/user/$userId/edit");
|
||||||
|
|
||||||
$username = 'Foo bar '.uniqid();
|
$username = 'Foo bar '.uniqid();
|
||||||
$form = $crawler->selectButton('Mettre à jour')->form(array(
|
$form = $crawler->selectButton('Enregistrer & fermer')->form(array(
|
||||||
'chill_mainbundle_user[username]' => $username,
|
'chill_mainbundle_user[username]' => $username,
|
||||||
));
|
));
|
||||||
|
|
||||||
$this->client->submit($form);
|
$this->client->submit($form);
|
||||||
$crawler = $this->client->followRedirect();
|
$crawler = $this->client->followRedirect();
|
||||||
// Check the element contains an attribute with value equals "Foo"
|
// Check the element contains an attribute with value equals "Foo"
|
||||||
$this->assertGreaterThan(0, $crawler->filter('[value="'.$username.'"]')->count(),
|
$this->assertGreaterThan(0, $crawler->filter('[data-username="'.$username.'"]')->count(),
|
||||||
'Missing element [value="Foo bar"]');
|
'Missing element [data-username="Foo bar"]');
|
||||||
|
|
||||||
$updatePassword = $crawler->selectLink('Modifier le mot de passe')->link();
|
|
||||||
|
|
||||||
$this->assertInstanceOf('Symfony\Component\DomCrawler\Link', $updatePassword);
|
|
||||||
$this->assertRegExp('|/fr/admin/user/[0-9]{1,}/edit_password$|',
|
|
||||||
$updatePassword->getUri());
|
|
||||||
|
|
||||||
return array('link' => $updatePassword, 'username' => $username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\DomCrawler\Link $updatePassword
|
* @dataProvider dataGenerateUserId
|
||||||
* @depends testUpdate
|
|
||||||
*/
|
*/
|
||||||
public function testUpdatePassword(array $params)
|
public function testUpdatePassword(int $userId, $username)
|
||||||
{
|
{
|
||||||
$link = $params['link'];
|
$crawler = $this->client->request('GET', "/fr/admin/user/$userId/edit_password");
|
||||||
$username = $params['username'];
|
|
||||||
$newPassword = '1234Password!';
|
$newPassword = '1234Password!';
|
||||||
|
|
||||||
$crawler = $this->client->click($link);
|
|
||||||
|
|
||||||
$form = $crawler->selectButton('Changer le mot de passe')->form(array(
|
$form = $crawler->selectButton('Changer le mot de passe')->form(array(
|
||||||
'chill_mainbundle_user_password[new_password][first]' => $newPassword,
|
'chill_mainbundle_user_password[new_password][first]' => $newPassword,
|
||||||
'chill_mainbundle_user_password[new_password][second]' => $newPassword,
|
'chill_mainbundle_user_password[new_password][second]' => $newPassword,
|
||||||
@ -130,10 +111,38 @@ class UserControllerTest extends WebTestCase
|
|||||||
|
|
||||||
$this->assertTrue($this->client->getResponse()->isRedirect(),
|
$this->assertTrue($this->client->getResponse()->isRedirect(),
|
||||||
"the response is a redirection");
|
"the response is a redirection");
|
||||||
$this->client->followRedirect();
|
|
||||||
|
|
||||||
$this->isPasswordValid($username, $newPassword);
|
$this->isPasswordValid($username, $newPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
foreach ($this->toDelete as list($class, $id)) {
|
||||||
|
$obj = $em->getRepository($class)->find($id);
|
||||||
|
$em->remove($obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataGenerateUserId()
|
||||||
|
{
|
||||||
|
self::bootKernel();
|
||||||
|
$em = self::$container->get(EntityManagerInterface::class);
|
||||||
|
|
||||||
|
$user = new User();
|
||||||
|
$user->setUsername('Test_user '.uniqid());
|
||||||
|
$user->setPassword(self::$container->get(UserPasswordEncoderInterface::class)->encodePassword($user,
|
||||||
|
'password'));
|
||||||
|
|
||||||
|
$em->persist($user);
|
||||||
|
$em->flush();
|
||||||
|
|
||||||
|
$this->toDelete[] = [User::class, $user->getId()];
|
||||||
|
|
||||||
|
yield [ $user->getId(), $user->getUsername() ];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -293,6 +293,32 @@ paths:
|
|||||||
401:
|
401:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
|
||||||
|
/1.0/main/address/{id}/duplicate.json:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- address
|
||||||
|
summary: Duplicate an existing address
|
||||||
|
parameters:
|
||||||
|
- name: id
|
||||||
|
in: path
|
||||||
|
required: true
|
||||||
|
description: The address id that will be duplicated
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
format: integer
|
||||||
|
minimum: 1
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "ok"
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/Address'
|
||||||
|
404:
|
||||||
|
description: "not found"
|
||||||
|
401:
|
||||||
|
description: "Unauthorized"
|
||||||
|
|
||||||
/1.0/main/address-reference.json:
|
/1.0/main/address-reference.json:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
@ -61,5 +61,6 @@ module.exports = function(encore, entries)
|
|||||||
|
|
||||||
// Vue entrypoints
|
// Vue entrypoints
|
||||||
encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js');
|
encore.addEntry('vue_address', __dirname + '/Resources/public/vuejs/Address/index.js');
|
||||||
|
encore.addEntry('vue_onthefly', __dirname + '/Resources/public/vuejs/OnTheFly/index.js');
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -6,10 +6,6 @@ chill_main_admin_permissionsgroup:
|
|||||||
resource: "@ChillMainBundle/config/routes/permissionsgroup.yaml"
|
resource: "@ChillMainBundle/config/routes/permissionsgroup.yaml"
|
||||||
prefix: "{_locale}/admin/permissionsgroup"
|
prefix: "{_locale}/admin/permissionsgroup"
|
||||||
|
|
||||||
chill_main_admin_user:
|
|
||||||
resource: "@ChillMainBundle/config/routes/user.yaml"
|
|
||||||
prefix: "{_locale}/admin/user"
|
|
||||||
|
|
||||||
chill_main_admin_scope:
|
chill_main_admin_scope:
|
||||||
resource: "@ChillMainBundle/config/routes/scope.yaml"
|
resource: "@ChillMainBundle/config/routes/scope.yaml"
|
||||||
prefix: "{_locale}/admin/scope"
|
prefix: "{_locale}/admin/scope"
|
||||||
@ -57,15 +53,15 @@ chill_main_homepage:
|
|||||||
path: /{_locale}/homepage
|
path: /{_locale}/homepage
|
||||||
controller: Chill\MainBundle\Controller\DefaultController::indexAction
|
controller: Chill\MainBundle\Controller\DefaultController::indexAction
|
||||||
|
|
||||||
chill_main_admin_central:
|
# chill_main_admin_central:
|
||||||
path: /{_locale}/admin
|
# path: /{_locale}/admin
|
||||||
controller: Chill\MainBundle\Controller\AdminController::indexAction
|
# controller: Chill\MainBundle\Controller\AdminController::indexAction
|
||||||
options:
|
# options:
|
||||||
menus:
|
# menus:
|
||||||
admin_permissions:
|
# admin_permissions:
|
||||||
order: 0
|
# order: 0
|
||||||
label: Main admin menu
|
# label: Main admin menu
|
||||||
|
#
|
||||||
chill_main_admin_permissions:
|
chill_main_admin_permissions:
|
||||||
path: /{_locale}/admin/permissions
|
path: /{_locale}/admin/permissions
|
||||||
controller: Chill\MainBundle\Controller\AdminController::indexPermissionsAction
|
controller: Chill\MainBundle\Controller\AdminController::indexPermissionsAction
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
admin_center:
|
admin_center:
|
||||||
path: /
|
path: /
|
||||||
controller: Chill\MainBundle\Controller\CenterController::indexAction
|
controller: Chill\MainBundle\Controller\CenterController::indexAction
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 100
|
|
||||||
label: Center list
|
|
||||||
|
|
||||||
admin_center_show:
|
admin_center_show:
|
||||||
path: /{id}/show
|
path: /{id}/show
|
||||||
@ -14,11 +9,6 @@ admin_center_show:
|
|||||||
admin_center_new:
|
admin_center_new:
|
||||||
path: /new
|
path: /new
|
||||||
controller: Chill\MainBundle\Controller\CenterController::newAction
|
controller: Chill\MainBundle\Controller\CenterController::newAction
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 101
|
|
||||||
label: New center
|
|
||||||
|
|
||||||
admin_center_create:
|
admin_center_create:
|
||||||
path: /create
|
path: /create
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
admin_permissionsgroup:
|
admin_permissionsgroup:
|
||||||
path: /
|
path: /
|
||||||
controller: Chill\MainBundle\Controller\PermissionsGroupController::indexAction
|
controller: Chill\MainBundle\Controller\PermissionsGroupController::indexAction
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 300
|
|
||||||
label: Permissions group list
|
|
||||||
|
|
||||||
admin_permissionsgroup_show:
|
admin_permissionsgroup_show:
|
||||||
path: /{id}/show
|
path: /{id}/show
|
||||||
@ -14,11 +9,6 @@ admin_permissionsgroup_show:
|
|||||||
admin_permissionsgroup_new:
|
admin_permissionsgroup_new:
|
||||||
path: /new
|
path: /new
|
||||||
controller: Chill\MainBundle\Controller\PermissionsGroupController::newAction
|
controller: Chill\MainBundle\Controller\PermissionsGroupController::newAction
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 301
|
|
||||||
label: New permission group
|
|
||||||
|
|
||||||
admin_permissionsgroup_create:
|
admin_permissionsgroup_create:
|
||||||
path: /create
|
path: /create
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
admin_scope:
|
admin_scope:
|
||||||
path: /
|
path: /
|
||||||
controller: Chill\MainBundle\Controller\ScopeController::indexAction
|
controller: Chill\MainBundle\Controller\ScopeController::indexAction
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 200
|
|
||||||
label: List circles
|
|
||||||
|
|
||||||
admin_scope_show:
|
admin_scope_show:
|
||||||
path: /{id}/show
|
path: /{id}/show
|
||||||
@ -14,11 +9,6 @@ admin_scope_show:
|
|||||||
admin_scope_new:
|
admin_scope_new:
|
||||||
path: /new
|
path: /new
|
||||||
controller: Chill\MainBundle\Controller\ScopeController::newAction
|
controller: Chill\MainBundle\Controller\ScopeController::newAction
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 201
|
|
||||||
label: New circle
|
|
||||||
|
|
||||||
admin_scope_create:
|
admin_scope_create:
|
||||||
path: /create
|
path: /create
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
admin_user:
|
|
||||||
path: /
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::indexAction
|
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 400
|
|
||||||
label: List users
|
|
||||||
|
|
||||||
admin_user_show:
|
|
||||||
path: /{id}/show
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::showAction
|
|
||||||
|
|
||||||
admin_user_new:
|
|
||||||
path: /new
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::newAction
|
|
||||||
options:
|
|
||||||
menus:
|
|
||||||
admin_permissions:
|
|
||||||
order: 401
|
|
||||||
label: Add a new user
|
|
||||||
|
|
||||||
admin_user_create:
|
|
||||||
path: /create
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::createAction
|
|
||||||
methods: POST
|
|
||||||
|
|
||||||
admin_user_edit:
|
|
||||||
path: /{id}/edit
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::editAction
|
|
||||||
|
|
||||||
admin_user_edit_password:
|
|
||||||
path: /{id}/edit_password
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::editPasswordAction
|
|
||||||
|
|
||||||
admin_user_update:
|
|
||||||
path: /{id}/update
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::updateAction
|
|
||||||
methods: [POST, PUT]
|
|
||||||
|
|
||||||
admin_user_update_password:
|
|
||||||
path: /{id}/update_password
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::updatePasswordAction
|
|
||||||
methods: [POST, PUT]
|
|
||||||
|
|
||||||
admin_user_delete_group_center:
|
|
||||||
path: /{uid}/delete_link_groupcenter/{gcid}
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::deleteLinkGroupCenterAction
|
|
||||||
methods: [DELETE]
|
|
||||||
|
|
||||||
admin_user_add_group_center:
|
|
||||||
path: /{uid}/add_link_groupcenter
|
|
||||||
controller: Chill\MainBundle\Controller\UserController::addLinkGroupCenterAction
|
|
||||||
methods: [POST]
|
|
@ -29,10 +29,8 @@ services:
|
|||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
|
||||||
Chill\MainBundle\Controller\UserController:
|
Chill\MainBundle\Controller\UserController:
|
||||||
arguments:
|
autowire: true
|
||||||
$logger: '@Psr\Log\LoggerInterface'
|
autoconfigure: true
|
||||||
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
|
|
||||||
tags: ['controller.service_arguments']
|
|
||||||
|
|
||||||
Chill\MainBundle\Controller\NotificationController:
|
Chill\MainBundle\Controller\NotificationController:
|
||||||
arguments:
|
arguments:
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
services:
|
services:
|
||||||
|
Chill\MainBundle\Routing\MenuBuilder\:
|
||||||
|
resource: '../../Routing/MenuBuilder'
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
|
||||||
Chill\MainBundle\Routing\MenuBuilder\UserMenuBuilder:
|
Chill\MainBundle\Routing\MenuBuilder\UserMenuBuilder:
|
||||||
arguments:
|
arguments:
|
||||||
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
|
$tokenStorage: '@Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'
|
||||||
|
@ -143,10 +143,8 @@ The role '%role%' has been removed: Le rôle "%role%" a été enlevé de ce grou
|
|||||||
The role '%role%' on circle '%scope%' has been removed: Le rôle "%role%" sur le cercle "%scope%" a été enlevé de ce groupe de permission
|
The role '%role%' on circle '%scope%' has been removed: Le rôle "%role%" sur le cercle "%scope%" a été enlevé de ce groupe de permission
|
||||||
|
|
||||||
#admin section for users
|
#admin section for users
|
||||||
List users: Liste des utilisateurs
|
|
||||||
user list: Liste des utilisateurs
|
user list: Liste des utilisateurs
|
||||||
User edit: Modification d'un utilisateur
|
User edit: Modification d'un utilisateur
|
||||||
User creation: Créer un utilisateur
|
|
||||||
User'status: Statut de l'utilisateur
|
User'status: Statut de l'utilisateur
|
||||||
Disabled, the user is not allowed to login: Désactivé, l'utilisateur n'est pas autorisé à se connecter
|
Disabled, the user is not allowed to login: Désactivé, l'utilisateur n'est pas autorisé à se connecter
|
||||||
Enabled, the user is active: Actif, l'utilisateur peut se connecter
|
Enabled, the user is active: Actif, l'utilisateur peut se connecter
|
||||||
|
@ -118,6 +118,7 @@ class AccompanyingCourseController extends Controller
|
|||||||
return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [
|
return $this->render('@ChillPerson/AccompanyingCourse/index.html.twig', [
|
||||||
'accompanyingCourse' => $accompanyingCourse,
|
'accompanyingCourse' => $accompanyingCourse,
|
||||||
'withoutHousehold' => $withoutHousehold,
|
'withoutHousehold' => $withoutHousehold,
|
||||||
|
'participationsByHousehold' => $accompanyingCourse->actualParticipationsByHousehold(),
|
||||||
'works' => $works,
|
'works' => $works,
|
||||||
'activities' => $activities
|
'activities' => $activities
|
||||||
]);
|
]);
|
||||||
|
@ -45,9 +45,9 @@ class PersonApiController extends ApiController
|
|||||||
$person = parent::createEntity($action, $request);
|
$person = parent::createEntity($action, $request);
|
||||||
|
|
||||||
// TODO temporary hack to allow creation of person with fake center
|
// TODO temporary hack to allow creation of person with fake center
|
||||||
$centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
/* $centers = $this->authorizationHelper->getReachableCenters($this->getUser(),
|
||||||
new Role(PersonVoter::CREATE));
|
new Role(PersonVoter::CREATE));
|
||||||
$person->setCenter($centers[0]);
|
$person->setCenter($centers[0]); */
|
||||||
|
|
||||||
return $person;
|
return $person;
|
||||||
}
|
}
|
||||||
|
@ -247,7 +247,6 @@ class LoadPeople extends AbstractFixture implements OrderedFixtureInterface, Con
|
|||||||
if (\random_int(0, 10) > 3) {
|
if (\random_int(0, 10) > 3) {
|
||||||
// always add social scope:
|
// always add social scope:
|
||||||
$accompanyingPeriod->addScope($this->getReference('scope_social'));
|
$accompanyingPeriod->addScope($this->getReference('scope_social'));
|
||||||
var_dump(count($accompanyingPeriod->getScopes()));
|
|
||||||
|
|
||||||
$accompanyingPeriod->setAddressLocation($this->createAddress());
|
$accompanyingPeriod->setAddressLocation($this->createAddress());
|
||||||
$manager->persist($accompanyingPeriod->getAddressLocation());
|
$manager->persist($accompanyingPeriod->getAddressLocation());
|
||||||
|
@ -640,12 +640,13 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
|||||||
Request::METHOD_GET => true,
|
Request::METHOD_GET => true,
|
||||||
Request::METHOD_HEAD => true,
|
Request::METHOD_HEAD => true,
|
||||||
Request::METHOD_POST=> true,
|
Request::METHOD_POST=> true,
|
||||||
|
Request::METHOD_PATCH => true
|
||||||
],
|
],
|
||||||
'roles' => [
|
'roles' => [
|
||||||
Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||||
Request::METHOD_HEAD => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
Request::METHOD_HEAD => \Chill\PersonBundle\Security\Authorization\PersonVoter::SEE,
|
||||||
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
||||||
|
Request::METHOD_PATCH => \Chill\PersonBundle\Security\Authorization\PersonVoter::CREATE,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'address' => [
|
'address' => [
|
||||||
|
@ -213,7 +213,7 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
private $scopes;
|
private $scopes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\ManyToOne(targetEntity=Person::class)
|
* @ORM\ManyToOne(targetEntity=Person::class, inversedBy="accompanyingPeriodRequested")
|
||||||
* @ORM\JoinColumn(nullable=true)
|
* @ORM\JoinColumn(nullable=true)
|
||||||
*/
|
*/
|
||||||
private $requestorPerson;
|
private $requestorPerson;
|
||||||
@ -513,6 +513,44 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array with open participations sorted by household
|
||||||
|
* [
|
||||||
|
* [
|
||||||
|
* "household" => Household x,
|
||||||
|
* "members" => [
|
||||||
|
* Participation y , Participation z, ...
|
||||||
|
* ]
|
||||||
|
* ],
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function actualParticipationsByHousehold(): array
|
||||||
|
{
|
||||||
|
$participations = $this->getOPenParticipations()->toArray();
|
||||||
|
|
||||||
|
$households = [];
|
||||||
|
foreach ($participations as $p) {
|
||||||
|
$households[] = $p->getPerson()->getCurrentHousehold();
|
||||||
|
}
|
||||||
|
$households = array_unique($households, SORT_REGULAR);
|
||||||
|
|
||||||
|
$array = [];
|
||||||
|
foreach ($households as $household) {
|
||||||
|
$members = [];
|
||||||
|
foreach ($participations as $p) {
|
||||||
|
if ($household === $p->getPerson()->getCurrentHousehold()) {
|
||||||
|
$members[] = array_shift($participations);
|
||||||
|
} else {
|
||||||
|
$participations[] = array_shift($participations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$array[] = [ 'household' => $household, 'members' => $members ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if the accompanying period contains a person.
|
* Return true if the accompanying period contains a person.
|
||||||
*
|
*
|
||||||
|
@ -129,4 +129,9 @@ class AccompanyingPeriodParticipation
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isOpen(): bool
|
||||||
|
{
|
||||||
|
return $this->endDate === null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,7 +229,7 @@ class Household
|
|||||||
))
|
))
|
||||||
->andWhere($expr->orX(
|
->andWhere($expr->orX(
|
||||||
$expr->isNull('endDate'),
|
$expr->isNull('endDate'),
|
||||||
$expr->gte('endDate', $date)
|
$expr->gt('endDate', $date)
|
||||||
));
|
));
|
||||||
|
|
||||||
return $criteria;
|
return $criteria;
|
||||||
@ -306,7 +306,7 @@ class Household
|
|||||||
)
|
)
|
||||||
->orWhere(
|
->orWhere(
|
||||||
$expr->andX(
|
$expr->andX(
|
||||||
$expr->lt('endDate', $date),
|
$expr->lte('endDate', $date),
|
||||||
$expr->neq('endDate', null)
|
$expr->neq('endDate', null)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -28,9 +28,9 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
|
|||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\Center;
|
||||||
use Chill\MainBundle\Entity\Country;
|
use Chill\MainBundle\Entity\Country;
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
use Chill\PersonBundle\Entity\Household\Household;
|
use Chill\PersonBundle\Entity\Household\Household;
|
||||||
use Chill\PersonBundle\Entity\MaritalStatus;
|
use Chill\PersonBundle\Entity\MaritalStatus;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
|
||||||
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
use Chill\PersonBundle\Entity\Household\HouseholdMember;
|
||||||
use Chill\MainBundle\Entity\HasCenterInterface;
|
use Chill\MainBundle\Entity\HasCenterInterface;
|
||||||
use Chill\MainBundle\Entity\Address;
|
use Chill\MainBundle\Entity\Address;
|
||||||
@ -146,7 +146,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
* groups={"general", "creation"}
|
* groups={"general", "creation"}
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
private ?\DateTimeImmutable $deathdate;
|
private ?\DateTimeImmutable $deathdate = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The person's place of birth
|
* The person's place of birth
|
||||||
@ -329,6 +329,15 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
*/
|
*/
|
||||||
private $accompanyingPeriodParticipations;
|
private $accompanyingPeriodParticipations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The accompanying period requested by the Person
|
||||||
|
*
|
||||||
|
* @ORM\OneToMany(targetEntity=AccompanyingPeriod::class,
|
||||||
|
* mappedBy="requestorPerson")
|
||||||
|
* @var Collection|AccompanyingPeriod[]
|
||||||
|
*/
|
||||||
|
private Collection $accompanyingPeriodRequested;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A remark over the person
|
* A remark over the person
|
||||||
* @var string
|
* @var string
|
||||||
@ -478,6 +487,7 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
$this->genderComment = new CommentEmbeddable();
|
$this->genderComment = new CommentEmbeddable();
|
||||||
$this->maritalStatusComment = new CommentEmbeddable();
|
$this->maritalStatusComment = new CommentEmbeddable();
|
||||||
$this->periodLocatedOn = new ArrayCollection();
|
$this->periodLocatedOn = new ArrayCollection();
|
||||||
|
$this->accompanyingPeriodRequested = new ArrayCollection();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -605,6 +615,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get AccompanyingPeriodParticipations Collection
|
* Get AccompanyingPeriodParticipations Collection
|
||||||
|
*
|
||||||
|
* @return AccompanyingPeriodParticipation[]|Collection
|
||||||
*/
|
*/
|
||||||
public function getAccompanyingPeriodParticipations(): Collection
|
public function getAccompanyingPeriodParticipations(): Collection
|
||||||
{
|
{
|
||||||
@ -614,6 +626,8 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
/**
|
/**
|
||||||
* Return a collection of participation, where the participation
|
* Return a collection of participation, where the participation
|
||||||
* is still opened, not a draft, and the period is still opened
|
* is still opened, not a draft, and the period is still opened
|
||||||
|
*
|
||||||
|
* @return AccompanyingPeriodParticipation[]|Collection
|
||||||
*/
|
*/
|
||||||
public function getOpenedParticipations(): Collection
|
public function getOpenedParticipations(): Collection
|
||||||
{
|
{
|
||||||
@ -1650,6 +1664,84 @@ class Person implements HasCenterInterface, TrackCreationInterface, TrackUpdateI
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AccompanyingPeriod[]|Collection
|
||||||
|
*/
|
||||||
|
public function getAccompanyingPeriodRequested(): Collection
|
||||||
|
{
|
||||||
|
return $this->accompanyingPeriodRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of all accompanying period where the person is involved:
|
||||||
|
*
|
||||||
|
* * as requestor;
|
||||||
|
* * as participant, only for opened participation;
|
||||||
|
*
|
||||||
|
* @param bool $asParticipantOpen add participation which are still opened
|
||||||
|
* @param bool $asRequestor add accompanying period where the person is requestor
|
||||||
|
* @return AccompanyingPeriod[]|Collection
|
||||||
|
*/
|
||||||
|
public function getAccompanyingPeriodInvolved(
|
||||||
|
bool $asParticipantOpen = true,
|
||||||
|
bool $asRequestor = true
|
||||||
|
): Collection
|
||||||
|
{
|
||||||
|
$result = new ArrayCollection();
|
||||||
|
|
||||||
|
if ($asParticipantOpen) {
|
||||||
|
foreach ($this->getOpenedParticipations()
|
||||||
|
->map(fn (AccompanyingPeriodParticipation $app) =>
|
||||||
|
$app->getAccompanyingPeriod())
|
||||||
|
as $period
|
||||||
|
) {
|
||||||
|
if (!$result->contains($period)) {
|
||||||
|
$result->add($period);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($asRequestor) {
|
||||||
|
foreach ($this->accompanyingPeriodRequested as $period) {
|
||||||
|
if (!$result->contains($period)) {
|
||||||
|
$result->add($period);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handy method to get the AccompanyingPeriodParticipation
|
||||||
|
* matching a given AccompanyingPeriod.
|
||||||
|
*
|
||||||
|
* Used in template, to find the participation when iterating on a list
|
||||||
|
* of period.
|
||||||
|
*
|
||||||
|
* @param \Chill\PersonBundle\Entity\AccompanyingPeriod $period
|
||||||
|
* @return AccompanyingPeriodParticipation
|
||||||
|
*/
|
||||||
|
public function findParticipationForPeriod(AccompanyingPeriod $period): ?AccompanyingPeriodParticipation
|
||||||
|
{
|
||||||
|
$closeCandidates = [];
|
||||||
|
|
||||||
|
foreach ($this->getAccompanyingPeriodParticipations() as $participation) {
|
||||||
|
if ($participation->getAccompanyingPeriod() === $period) {
|
||||||
|
if ($participation->isOpen()) {
|
||||||
|
return $participation;
|
||||||
|
}
|
||||||
|
$closeCandidates[] = $participation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 < count($closeCandidates)) {
|
||||||
|
return $closeCandidates[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public function getCreatedBy(): ?User
|
public function getCreatedBy(): ?User
|
||||||
{
|
{
|
||||||
return $this->createdBy;
|
return $this->createdBy;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user