Merge branch 'master' into VSR-issues

This commit is contained in:
2023-01-24 15:36:22 +01:00
201 changed files with 2768 additions and 708 deletions

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Controller;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Symfony\Component\HttpFoundation\Request;
class RegroupmentController extends CRUDController
{
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
{
$query->addOrderBy('e.id', 'ASC');
return parent::orderQuery($action, $query, $request, $paginator);
}
}

View File

@@ -85,7 +85,6 @@ class WorkflowController extends AbstractController
->setRelatedEntityClass($request->query->get('entityClass'))
->setRelatedEntityId($request->query->getInt('entityId'))
->setWorkflowName($request->query->get('workflow'))
->addSubscriberToStep($this->getUser())
->addSubscriberToFinal($this->getUser());
$errors = $this->validator->validate($entityWorkflow, null, ['creation']);

View File

@@ -44,7 +44,7 @@ class CronManager implements CronManagerInterface
private const UPDATE_AFTER_EXEC = 'UPDATE ' . CronJobExecution::class . ' cr SET cr.lastEnd = :now, cr.lastStatus = :status WHERE cr.key = :key';
private const UPDATE_BEFORE_EXEC = 'UPDATE ' . CronJobExecution::class . ' cr SET cr.lastExecution = :now WHERE cr.key = :key';
private const UPDATE_BEFORE_EXEC = 'UPDATE ' . CronJobExecution::class . ' cr SET cr.lastStart = :now WHERE cr.key = :key';
private CronJobExecutionRepositoryInterface $cronJobExecutionRepository;
@@ -90,7 +90,8 @@ class CronManager implements CronManagerInterface
->setParameters([
'now' => new DateTimeImmutable('now'),
'key' => $job->getKey(),
]);
])
->execute();
} else {
$execution = new CronJobExecution($job->getKey());
$this->entityManager->persist($execution);

View File

@@ -18,6 +18,7 @@ use Chill\MainBundle\Controller\CountryController;
use Chill\MainBundle\Controller\LanguageController;
use Chill\MainBundle\Controller\LocationController;
use Chill\MainBundle\Controller\LocationTypeController;
use Chill\MainBundle\Controller\RegroupmentController;
use Chill\MainBundle\Controller\UserController;
use Chill\MainBundle\Controller\UserJobApiController;
use Chill\MainBundle\Controller\UserJobController;
@@ -48,6 +49,7 @@ use Chill\MainBundle\Entity\Country;
use Chill\MainBundle\Entity\Language;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\LocationType;
use Chill\MainBundle\Entity\Regroupment;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\MainBundle\Form\CivilityType;
@@ -55,6 +57,7 @@ use Chill\MainBundle\Form\CountryType;
use Chill\MainBundle\Form\LanguageType;
use Chill\MainBundle\Form\LocationFormType;
use Chill\MainBundle\Form\LocationTypeType;
use Chill\MainBundle\Form\RegroupmentType;
use Chill\MainBundle\Form\UserJobType;
use Chill\MainBundle\Form\UserType;
use Exception;
@@ -148,6 +151,11 @@ class ChillMainExtension extends Extension implements
$config['access_permissions_group_list']
);
$container->setParameter(
'chill_main.add_address',
$config['add_address']
);
$container->setParameter(
'chill_main.routing.resources',
$config['routing']['resources']
@@ -223,6 +231,7 @@ class ChillMainExtension extends Extension implements
'installation' => [
'name' => $config['installation_name'], ],
'available_languages' => $config['available_languages'],
'add_address' => $config['add_address'],
],
'form_themes' => ['@ChillMain/Form/fields.html.twig'],
];
@@ -493,6 +502,27 @@ class ChillMainExtension extends Extension implements
],
],
],
[
'class' => Regroupment::class,
'name' => 'regroupment',
'base_path' => '/admin/regroupment',
'form_class' => RegroupmentType::class,
'controller' => RegroupmentController::class,
'actions' => [
'index' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Admin/Regroupment/index.html.twig',
],
'new' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Admin/Regroupment/new.html.twig',
],
'edit' => [
'role' => 'ROLE_ADMIN',
'template' => '@ChillMain/Admin/Regroupment/edit.html.twig',
],
],
],
],
'apis' => [
[

View File

@@ -276,6 +276,16 @@ class Configuration implements ConfigurationInterface
->end() // end of root
;
$rootNode->children()
->arrayNode('add_address')->addDefaultsIfNotSet()->children()
->scalarNode('default_country')->cannotBeEmpty()->defaultValue('BE')->end()
->arrayNode('map_center')->children()
->scalarNode('x')->cannotBeEmpty()->defaultValue(50.8443)->end()
->scalarNode('y')->cannotBeEmpty()->defaultValue(4.3523)->end()
->scalarNode('z')->cannotBeEmpty()->defaultValue(15)->end()
->end()
->end();
return $treeBuilder;
}
}

View File

@@ -135,12 +135,8 @@ trait AddWidgetConfigurationTrait
/**
* add configuration nodes for the widget at the given place.
*
* @param type $place
*
* @return type
*/
protected function addWidgetsConfiguration($place, ContainerBuilder $containerBuilder)
protected function addWidgetsConfiguration(string $place, ContainerBuilder $containerBuilder)
{
$treeBuilder = new TreeBuilder($place);
$root = $treeBuilder->getRootNode($place)

View File

@@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="regroupment")
*/
class Regroupment
{
/**
* @var Center
* @ORM\ManyToMany(
* targetEntity="Chill\MainBundle\Entity\Center"
* )
* @ORM\Id
*/
private Collection $centers;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id = null;
/**
* @ORM\Column(type="boolean")
*/
private bool $isActive = true;
/**
* @ORM\Column(type="string", length=15, options={"default": ""}, nullable=false)
*/
private string $name = '';
public function __construct()
{
$this->centers = new ArrayCollection();
}
public function getCenters(): ?Collection
{
return $this->centers;
}
public function getId(): ?int
{
return $this->id;
}
public function getIsActive(): bool
{
return $this->isActive;
}
public function getName(): string
{
return $this->name;
}
public function setCenters(?Collection $centers): self
{
$this->centers = $centers;
return $this;
}
public function setIsActive(bool $isActive): self
{
$this->isActive = $isActive;
return $this;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}

View File

@@ -15,7 +15,7 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use RuntimeException;
use Symfony\Component\Security\Core\User\AdvancedUserInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation as Serializer;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
@@ -31,7 +31,7 @@ use function in_array;
* "user": User::class
* })
*/
class User implements AdvancedUserInterface
class User implements UserInterface
{
/**
* @ORM\Id
@@ -58,8 +58,6 @@ class User implements AdvancedUserInterface
private ?Location $currentLocation = null;
/**
* @var string
*
* @ORM\Column(type="string", length=150, nullable=true)
*/
private ?string $email = null;
@@ -216,7 +214,7 @@ class User implements AdvancedUserInterface
}
/**
* @return GroupCenter
* @return Collection<GroupCenter>
*/
public function getGroupCenters()
{
@@ -225,10 +223,8 @@ class User implements AdvancedUserInterface
/**
* Get id.
*
* @return int
*/
public function getId()
public function getId(): ?int
{
return $this->id;
}
@@ -487,7 +483,7 @@ class User implements AdvancedUserInterface
*
* @param string $name
*
* @return Agent
* @return User
*/
public function setUsername($name)
{

View File

@@ -132,8 +132,6 @@ class EntityWorkflowStep
{
if (!$this->destUser->contains($user)) {
$this->destUser[] = $user;
$this->getEntityWorkflow()
->addSubscriberToFinal($user);
}
return $this;
@@ -143,8 +141,6 @@ class EntityWorkflowStep
{
if (!$this->destUserByAccessKey->contains($user) && !$this->destUser->contains($user)) {
$this->destUserByAccessKey[] = $user;
$this->getEntityWorkflow()
->addSubscriberToFinal($user);
}
return $this;

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Form;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Regroupment;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class RegroupmentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class, [
'label' => 'Nom',
])
->add('centers', EntityType::class, [
'class' => Center::class,
'multiple' => true,
'attr' => ['class' => 'select2'],
])
->add('isActive', CheckboxType::class, [
'label' => 'Actif ?',
'required' => false,
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver
->setDefault('class', Regroupment::class);
}
}

View File

@@ -27,7 +27,6 @@ class ChillDateTimeType extends AbstractType
{
$resolver
->setDefault('date_widget', 'single_text')
->setDefault('date_format', 'dd-MM-yyyy')
->setDefault('time_widget', 'choice')
->setDefault('minutes', range(0, 59, 5))
->setDefault('hours', range(8, 22))

View File

@@ -67,13 +67,18 @@ export const makeFetch = <Input, Output>(method: 'POST'|'GET'|'PUT'|'PATCH'|'DEL
},
};
if (body !== null || typeof body !== 'undefined') {
console.log('for url '+url, body);
console.log('for url '+url, body !== null);
if (body !== null && typeof body !== 'undefined') {
Object.assign(opts, {body: JSON.stringify(body)})
}
if (typeof options !== 'undefined') {
opts = Object.assign(opts, options);
}
console.log('will fetch', url);
console.log('content for ' + url, opts);
return fetch(url, opts)
.then(response => {

View File

@@ -315,8 +315,11 @@ export default {
addressMap: {
// Note: LeafletJs demands [lat, lon]
// cfr https://macwright.com/lonlat/
center : [48.8589, 2.3469],
zoom: 12
center : [
this.context.defaults.map_center.x,
this.context.defaults.map_center.y,
],
zoom: this.context.defaults.map_center.z
},
},
errorMsg: []

View File

@@ -8,8 +8,12 @@ import L from 'leaflet';
import markerIconPng from 'leaflet/dist/images/marker-icon.png'
import 'leaflet/dist/leaflet.css';
const lonLatForLeaflet = (coordinates) => {
return [coordinates[1], coordinates[0]];
}
export default {
name: 'AddressMap',
name: 'AddressMap',
props: ['entity'],
data() {
return {
@@ -21,10 +25,47 @@ export default {
center() {
return this.entity.addressMap.center;
},
hasAddressPoint() {
if (Object.keys(this.entity.address).length === 0) {
return false;
}
if (null !== this.entity.address.addressReference) {
return true;
}
if (null !== this.entity.address.postcode && null !== this.entity.address.postcode.center) {
return true;
}
return false;
},
/**
*
* @returns {coordinates: [float, float], type: "Point"}
*/
addressPoint() {
if (Object.keys(this.entity.address).length === 0) {
return null;
}
if (null !== this.entity.address.addressReference) {
return this.entity.address.addressReference.point;
}
if (null !== this.entity.address.postcode && null !== this.entity.address.postcode.center) {
return this.entity.address.postcode.center;
}
return null;
},
},
methods:{
init() {
this.map = L.map('address_map').setView([46.67059, -1.42683], 12);
this.map = L.map('address_map');
if (!this.hasAddressPoint) {
this.map.setView(lonLatForLeaflet(this.entity.addressMap.center), this.entity.addressMap.zoom);
} else {
this.map.setView(lonLatForLeaflet(this.addressPoint.coordinates), 15);
}
this.map.scrollWheelZoom.disable();
@@ -37,20 +78,22 @@ export default {
iconAnchor: [12, 41],
});
this.marker = L.marker([48.8589, 2.3469], {icon: markerIcon});
if (!this.hasAddressPoint) {
this.marker = L.marker(lonLatForLeaflet(this.entity.addressMap.center), {icon: markerIcon});
} else {
this.marker = L.marker(lonLatForLeaflet(this.addressPoint.coordinates), {icon: markerIcon});
}
this.marker.addTo(this.map);
},
update() {
console.log('update map with : ', this.center)
if (this.marker && this.center) {
this.marker.setLatLng(this.center);
this.map.setView(this.center, 15);
if (this.marker && this.entity.addressMap.center) {
this.marker.setLatLng(lonLatForLeaflet(this.entity.addressMap.center));
this.map.panTo(lonLatForLeaflet(this.entity.addressMap.center));
}
}
},
mounted(){
mounted() {
this.init();
this.update();
}
},
}
</script>

View File

@@ -30,7 +30,7 @@ export default {
data() {
return {
value: this.selectCountryByCode(
this.context.edit ? this.entity.selected.country.code : 'FR'
this.context.edit ? this.entity.selected.country.code : this.context.defaults.default_country
)
}
},
@@ -45,14 +45,12 @@ export default {
},
},
mounted() {
this.init();
console.log('country selection mounted', this.value);
if (this.value !== undefined) {
this.selectCountry(this.value);
}
},
methods: {
init() {
if (this.value !== undefined) {
this.selectCountry(this.value);
}
},
methods: {
selectCountryByCode(countryCode) {
return this.entity.loaded.countries.filter(c => c.countryCode === countryCode)[0];
},

View File

@@ -174,8 +174,8 @@ export default {
},
updateMapCenter(point) {
console.log('point', point);
this.addressMap.center[0] = point.coordinates[1]; // TODO use reverse()
this.addressMap.center[1] = point.coordinates[0];
this.addressMap.center[0] = point.coordinates[0];
this.addressMap.center[1] = point.coordinates[1];
this.$refs.addressMap.update(); // cast child methods
}
}

View File

@@ -93,7 +93,7 @@ export default {
],
emits: ['openEditPane'],
mounted() {
console.log('context', this.context)
//console.log('context', this.context)
},
computed: {
address() {

View File

@@ -20,7 +20,8 @@ containers.forEach((container) => {
},
edit: container.dataset.mode === 'edit', //boolean
addressId: parseInt(container.dataset.addressId) || null,
backUrl: container.dataset.backUrl || null
backUrl: container.dataset.backUrl || null,
defaults: JSON.parse(container.dataset.addressDefaults)
},
options: {
/// Options override default.

View File

@@ -19,7 +19,6 @@ const addAddressInput = (inputs) => {
if (container === null) {
throw Error("no container");
}
console.log('useValidFrom', el.dataset.useValidFrom === '1');
const app = createApp({
template: `<app v-bind:addAddress="this.addAddress" @address-created="associateToInput"></app>`,
@@ -34,6 +33,7 @@ const addAddressInput = (inputs) => {
},
edit: isEdit,
addressId: addressIdInt,
defaults: window.addaddress,
},
options: {
/// Options override default.

View File

@@ -72,6 +72,8 @@
{% if onlyButton is defined and onlyButton == 1 %}
data-hide-address="true"
{% endif %}
data-address-defaults="{{ add_address|json_encode|e('html') }}"
></div>
{{ encore_entry_script_tags('vue_address') }}

View File

@@ -0,0 +1,11 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_edit_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock admin_content %}

View File

@@ -0,0 +1,39 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% block table_entities_thead_tr %}
<th>{{ 'Label'|trans }}</th>
<th>{{ 'Active'|trans }}</th>
<th>&nbsp;</th>
{% endblock %}
{% block table_entities_tbody %}
{% for entity in entities %}
<tr>
<td>{{ entity.name }}</td>
<td style="text-align:center">
{% if entity.isActive %}
<i class="fa fa-check-square-o"></i>
{% else %}
<i class="fa fa-square-o"></i>
{% endif %}
</td>
<td>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_crud_regroupment_edit', { 'id': entity.id }) }}" class="btn btn-edit"></a>
</li>
</ul>
</td>
</tr>
{% endfor %}
{% endblock %}
{% block actions_before %}
<li class='cancel'>
<a href="{{ path('chill_main_admin_central') }}" class="btn btn-cancel">{{'Back to the admin'|trans}}</a>
</li>
{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -0,0 +1,11 @@
{% extends '@ChillMain/CRUD/Admin/index.html.twig' %}
{% block title %}
{% include('@ChillMain/CRUD/_new_title.html.twig') %}
{% endblock %}
{% block admin_content %}
{% embed '@ChillMain/CRUD/_new_content.html.twig' %}
{% block content_form_actions_save_and_show %}{% endblock %}
{% endembed %}
{% endblock admin_content %}

View File

@@ -9,6 +9,11 @@
{% block head_custom %}{% endblock %}
<link rel="shortcut icon" href="{{ asset('build/images/favicon.ico') }}" type="image/x-icon">
<script type="application/javascript">
{# this is global data, in use for all js app #}
window.addaddress = {{ add_address|json_encode|raw }};
</script>
{{ encore_entry_link_tags('mod_bootstrap') }}
{{ encore_entry_link_tags('mod_forkawesome') }}
{{ encore_entry_link_tags('mod_ckeditor5') }}

View File

@@ -53,6 +53,10 @@ class AdminUserMenuBuilder implements LocalMenuBuilderInterface
'route' => 'admin_center',
])->setExtras(['order' => 1010]);
$menu->addChild('Regroupements des centres', [
'route' => 'chill_crud_regroupment_index',
])->setExtras(['order' => 1015]);
$menu->addChild('List circles', [
'route' => 'admin_scope',
])->setExtras(['order' => 1020]);

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Security\Authorization;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Symfony\Component\Security\Core\Security;
class AuthorizationHelperForCurrentUser implements AuthorizationHelperForCurrentUserInterface
{
private AuthorizationHelperInterface $authorizationHelper;
private Security $security;
public function __construct(AuthorizationHelperInterface $authorizationHelper, Security $security)
{
$this->authorizationHelper = $authorizationHelper;
$this->security = $security;
}
public function getReachableCenters(string $role, ?Scope $scope = null): array
{
if (!$this->security->getUser() instanceof User) {
return [];
}
return $this->authorizationHelper->getReachableCenters($this->security->getUser(), $role, $scope);
}
public function getReachableScopes(string $role, $center): array
{
if (!$this->security->getUser() instanceof User) {
return [];
}
return $this->authorizationHelper->getReachableScopes($this->security->getUser(), $role, $center);
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Security\Authorization;
use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Scope;
interface AuthorizationHelperForCurrentUserInterface
{
/**
* Get reachable Centers for the given user, role,
* and optionnaly Scope.
*
* @return Center[]
*/
public function getReachableCenters(string $role, ?Scope $scope = null): array;
/**
* @param array|Center|Center[] $center
*/
public function getReachableScopes(string $role, $center): array;
}

View File

@@ -31,6 +31,10 @@ class CenterNormalizer implements DenormalizerInterface, NormalizerInterface
public function denormalize($data, $type, $format = null, array $context = [])
{
if (null === $data) {
return null;
}
if (false === array_key_exists('type', $data)) {
throw new InvalidArgumentException('missing "type" key in data');
}

View File

@@ -17,12 +17,9 @@ use DateInterval;
use DateTimeImmutable;
use Doctrine\DBAL\Connection;
use UnexpectedValueException;
use function in_array;
class RefreshAddressToGeographicalUnitMaterializedViewCronJob implements CronJobInterface
{
private const ACCEPTED_HOURS = ['0', '1', '2', '3', '4', '5'];
private Connection $connection;
public function __construct(Connection $connection)
@@ -43,9 +40,8 @@ class RefreshAddressToGeographicalUnitMaterializedViewCronJob implements CronJob
$now = new DateTimeImmutable('now');
return $cronJobExecution->getLastStart() < $now->sub(new DateInterval('P1D'))
&& in_array($now->format('H'), self::ACCEPTED_HOURS, true)
// introduce a random component to ensure a roll when multiple instances are hosted on same machines
&& mt_rand(0, 5) === 0;
&& mt_rand(0, 10) === 0;
}
public function getKey(): string

View File

@@ -30,6 +30,56 @@ final class RefreshAddressToGeographicalUnitMaterializedViewCronJobTest extends
$this->connection = self::$container->get(Connection::class);
}
public function testCanRun(): void
{
// As the can run is executed one of ten, this should be executed at least one after
// 10 + 5 executions
$job = new \Chill\MainBundle\Service\AddressGeographicalUnit\RefreshAddressToGeographicalUnitMaterializedViewCronJob(
$this->connection
);
$lastExecution = new CronJobExecution($job->getKey());
$lastExecution->setLastStart(new DateTimeImmutable('2 days ago'));
$executedForFirstTime = 0;
$executedAfterPreviousExecution = 0;
for ($round = 0; 20 > $round; ++$round) {
if ($job->canRun(null)) {
++$executedForFirstTime;
}
if ($job->canRun($lastExecution)) {
++$executedAfterPreviousExecution;
}
}
$this->assertGreaterThan(0, $executedForFirstTime);
$this->assertGreaterThan(0, $executedAfterPreviousExecution);
}
public function testCanRunShouldReturnFalse(): void
{
// As the can run is executed one of ten, this should be executed at least one after
// 10 + 5 executions
$job = new \Chill\MainBundle\Service\AddressGeographicalUnit\RefreshAddressToGeographicalUnitMaterializedViewCronJob(
$this->connection
);
$lastExecution = new CronJobExecution($job->getKey());
$lastExecution->setLastStart(new DateTimeImmutable('2 hours ago'));
$executedAfterPreviousExecution = 0;
for ($round = 0; 20 > $round; ++$round) {
if ($job->canRun($lastExecution)) {
++$executedAfterPreviousExecution;
}
}
$this->assertEquals(0, $executedAfterPreviousExecution);
}
public function testFullRun(): void
{
$job = new \Chill\MainBundle\Service\AddressGeographicalUnit\RefreshAddressToGeographicalUnitMaterializedViewCronJob(

View File

@@ -33,3 +33,7 @@ services:
arguments:
$security: '@Symfony\Component\Security\Core\Security'
tags: ['controller.service_arguments']
Chill\MainBundle\Controller\RegroupmentController:
autowire: true
autoconfigure: true

View File

@@ -138,6 +138,10 @@ services:
autowire: true
autoconfigure: true
Chill\MainBundle\Form\RegroupmentType:
autowire: true
autoconfigure: true
Chill\MainBundle\Form\DataTransformer\IdToLocationDataTransformer: ~
Chill\MainBundle\Form\DataTransformer\IdToUserDataTransformer: ~
Chill\MainBundle\Form\DataTransformer\IdToUsersDataTransformer: ~

View File

@@ -3,6 +3,11 @@ services:
autowire: true
autoconfigure: true
Chill\MainBundle\Security\:
autoconfigure: true
autowire: true
resource: '../../Security'
Chill\MainBundle\Security\Resolver\CenterResolverDispatcher:
arguments:
- !tagged_iterator chill_main.center_resolver

View File

@@ -0,0 +1,43 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\Migrations\Main;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20230111104315 extends AbstractMigration
{
public function down(Schema $schema): void
{
$this->addSql('DROP SEQUENCE regroupment_id_seq CASCADE');
$this->addSql('ALTER TABLE regroupment_center DROP CONSTRAINT FK_2BCCE2F9EC6D1029');
$this->addSql('ALTER TABLE regroupment_center DROP CONSTRAINT FK_2BCCE2F95932F377');
$this->addSql('DROP TABLE regroupment');
$this->addSql('DROP TABLE regroupment_center');
}
public function getDescription(): string
{
return 'Add regroupment admin entity';
}
public function up(Schema $schema): void
{
$this->addSql('CREATE SEQUENCE regroupment_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
$this->addSql('CREATE TABLE regroupment (id INT NOT NULL, name VARCHAR(15) DEFAULT \'\' NOT NULL, isActive BOOLEAN NOT NULL, PRIMARY KEY(id))');
$this->addSql('CREATE TABLE regroupment_center (regroupment_id INT NOT NULL, center_id INT NOT NULL, PRIMARY KEY(regroupment_id, center_id))');
$this->addSql('CREATE INDEX IDX_2BCCE2F9EC6D1029 ON regroupment_center (regroupment_id)');
$this->addSql('CREATE INDEX IDX_2BCCE2F95932F377 ON regroupment_center (center_id)');
$this->addSql('ALTER TABLE regroupment_center ADD CONSTRAINT FK_2BCCE2F9EC6D1029 FOREIGN KEY (regroupment_id) REFERENCES regroupment (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE regroupment_center ADD CONSTRAINT FK_2BCCE2F95932F377 FOREIGN KEY (center_id) REFERENCES centers (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE');
}
}

View File

@@ -42,6 +42,8 @@ by_user: "par "
lifecycleUpdate: Evenements de création et mise à jour
address_fields: Données liées à l'adresse
inactive: inactif
Edit: Modifier
Update: Mettre à jour
Back to the list: Retour à la liste
@@ -408,6 +410,12 @@ crud:
add_new: Ajouter une civilité
title_new: Nouvelle civilité
title_edit: Modifier une civilité
regroupment:
index:
title: Liste des regroupements
add_new: Ajouter un regroupement
title_new: Nouveau regroupement
title_edit: Modifier un regroupement
No entities: Aucun élément