Merge remote-tracking branch 'origin/features/edit-accompanying-period-social-work' into _vue_echanges

This commit is contained in:
2021-06-26 12:14:32 +02:00
99 changed files with 4656 additions and 375 deletions

View File

@@ -22,6 +22,7 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Reference;
use Chill\MainBundle\Routing\MenuComposer;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Alias;
/**
*
@@ -49,29 +50,32 @@ class CRUDControllerCompilerPass implements CompilerPassInterface
private function configureCrudController(ContainerBuilder $container, array $crudEntry, string $apiOrCrud): void
{
$controllerClass = $crudEntry['controller'];
$controllerServiceName = 'cs'.$apiOrCrud.'_'.$crudEntry['name'].'_controller';
if ($container->hasDefinition($controllerClass)) {
$controller = $container->getDefinition($controllerClass);
$container->removeDefinition($controllerClass);
$alreadyDefined = true;
} else {
$controller = new Definition($controllerClass);
$alreadyDefined = false;
}
$controller->addTag('controller.service_arguments');
if (FALSE === $alreadyDefined) {
$controller->setAutoconfigured(true);
$controller->setPublic(true);
}
// create config parameter in container
$param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name'];
$container->setParameter($param, $crudEntry);
$controller->addMethodCall('setCrudConfig', ['%'.$param.'%']);
$container->setDefinition($controllerServiceName, $controller);
if ($container->hasDefinition($controllerClass)) {
// create an alias to not to re-create the service
$alias = new Alias($controllerClass, true);
$container->setAlias($controllerServiceName, $alias);
// add the "addMethodCall"
$container->getDefinition($controllerClass)
->addMethodCall('setCrudConfig', ['%'.$param.'%']);
} else {
$controller = new Definition($controllerClass);
$controller->addTag('controller.service_arguments');
$controller->setAutoconfigured(true);
$controller->setPublic(true);
$controller->addMethodCall('setCrudConfig', ['%'.$param.'%']);
$container->setDefinition($controllerServiceName, $controller);
}
}
}

View File

@@ -8,6 +8,11 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Chill\MainBundle\Pagination\PaginatorFactory;
use Chill\MainBundle\Pagination\PaginatorInterface;
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
use Chill\MainBundle\CRUD\Resolver\Resolver;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Translation\TranslatorInterface;
class AbstractCRUDController extends AbstractController
{
@@ -248,4 +253,24 @@ class AbstractCRUDController extends AbstractController
{
return $this->get('validator');
}
/**
* @return array
*/
public static function getSubscribedServices(): array
{
return \array_merge(
parent::getSubscribedServices(),
[
'chill_main.paginator_factory' => PaginatorFactory::class,
'translator' => TranslatorInterface::class,
AuthorizationHelper::class => AuthorizationHelper::class,
EventDispatcherInterface::class => EventDispatcherInterface::class,
Resolver::class => Resolver::class,
SerializerInterface::class => SerializerInterface::class,
'validator' => ValidatorInterface::class,
]
);
}
}

View File

@@ -359,9 +359,10 @@ class ApiController extends AbstractCRUDController
* 6. validate the base entity (not the deserialized one). Groups are fetched from getValidationGroups, validation is perform by `validate`
* 7. run onAfterValidation
* 8. if errors, return a 422 response with errors
* 9. flush the data
* 10. run onAfterFlush
* 11. return a 202 response for DELETE with empty body, or HTTP 200 for post with serialized posted entity
* 9. if $forcePersist === true, persist the entity
* 10. flush the data
* 11. run onAfterFlush
* 12. return a 202 response for DELETE with empty body, or HTTP 200 for post with serialized posted entity
*
* @param string action
* @param mixed id
@@ -370,11 +371,12 @@ class ApiController extends AbstractCRUDController
* @param string $property the name of the property. This will be used to make a `add+$property` and `remove+$property` method
* @param string $postedDataType the type of the posted data (the content)
* @param string $postedDataContext a context to deserialize posted data (the content)
* @param bool $forcePersist force to persist the created element (only for POST request)
* @throw BadRequestException if unable to deserialize the posted data
* @throw BadRequestException if the method is not POST or DELETE
*
*/
protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, $postedDataContext = []): Response
protected function addRemoveSomething(string $action, $id, Request $request, string $_format, string $property, string $postedDataType, array $postedDataContext = [], bool $forcePersist = false): Response
{
$entity = $this->getEntity($action, $id, $request);
@@ -429,6 +431,10 @@ class ApiController extends AbstractCRUDController
return $this->json($errors, 422);
}
if ($forcePersist && $request->getMethod() === Request::METHOD_POST) {
$this->getDoctrine()->getManager()->persist($postedData);
}
$this->getDoctrine()->getManager()->flush();

View File

@@ -142,11 +142,11 @@ class CRUDRoutesLoader extends Loader
protected function loadApi(array $crudConfig): RouteCollection
{
$collection = new RouteCollection();
$controller ='csapi_'.$crudConfig['name'].'_controller';
$controller = 'csapi_'.$crudConfig['name'].'_controller';
foreach ($crudConfig['actions'] as $name => $action) {
// filter only on single actions
$singleCollection = $action['single-collection'] ?? $name === '_entity' ? 'single' : NULL;
$singleCollection = $action['single_collection'] ?? $name === '_entity' ? 'single' : NULL;
if ('collection' === $singleCollection) {
// continue;
}
@@ -171,7 +171,7 @@ class CRUDRoutesLoader extends Loader
// path are rewritten
// if name === 'default', we rewrite it to nothing :-)
$localName = \in_array($name, [ '_entity', '_index' ]) ? '' : '/'.$name;
if ('collection' === $action['single-collection'] || '_index' === $name) {
if ('collection' === $action['single_collection'] || '_index' === $name) {
$localPath = $action['path'] ?? $localName.'.{_format}';
} else {
$localPath = $action['path'] ?? '/{id}'.$localName.'.{_format}';

View File

@@ -205,7 +205,7 @@ class Configuration implements ConfigurationInterface
->ignoreExtraKeys(false)
->info('the requirements for the route. Will be set to `[ \'id\' => \'\d+\' ]` if left empty.')
->end()
->enumNode('single-collection')
->enumNode('single_collection')
->values(['single', 'collection'])
->defaultValue('single')
->info('indicates if the returned object is a single element or a collection. '.

View File

@@ -51,7 +51,7 @@ class CommentType extends AbstractType
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
$data = $event->getForm()->getData();
$comment = $event->getData();
$comment = $event->getData() ?? ['comment' => ''];
if ($data->getComment() !== $comment['comment']) {
$data->setDate(new \DateTime());

View File

@@ -11,13 +11,16 @@
*
* Do not take time into account
*
* **Experimental**
*/
const dateToISO = (date) => {
if (null === date) {
return null;
}
return [
this.$store.state.startDate.getFullYear(),
(this.$store.state.startDate.getMonth() + 1).toString().padStart(2, '0'),
this.$store.state.startDate.getDate().toString().padStart(2, '0')
date.getFullYear(),
(date.getMonth() + 1).toString().padStart(2, '0'),
date.getDate().toString().padStart(2, '0')
].join('-');
};
@@ -36,15 +39,17 @@ const ISOToDate = (str) => {
/**
* Return a date object from iso string formatted as YYYY-mm-dd:HH:MM:ss+01:00
*
* **Experimental**
*/
const ISOToDatetime = (str) => {
console.log(str);
if (null === str) {
return null;
}
let
[cal, times] = str.split('T'),
[year, month, date] = cal.split('-'),
[time, timezone] = cal.split(times.charAt(9)),
[hours, minutes, seconds] = cal.split(':')
[time, timezone] = times.split(times.charAt(8)),
[hours, minutes, seconds] = time.split(':')
;
return new Date(year, month-1, date, hours, minutes, seconds);

View File

@@ -26,6 +26,12 @@
<div v-if="errors.length > 0">
{{ errors }}
</div>
<div v-if="loading">
{{ $t('loading') }}
</div>
<div v-if="success">
{{ $t('person_address_creation_success') }}
</div>
</div>
<div>
@@ -68,6 +74,12 @@ export default {
},
errors() {
return this.$store.state.errorMsg;
},
loading() {
return this.$store.state.loading;
},
success() {
return this.$store.state.success;
}
},
methods: {

View File

@@ -26,7 +26,9 @@ const addressMessages = {
date: 'Date de la nouvelle adresse',
add_an_address_to_person: 'Ajouter l\'adresse à la personne',
validFrom: 'Date de la nouvelle adresse',
back_to_the_list: 'Retour à la liste'
back_to_the_list: 'Retour à la liste',
person_address_creation_success: 'La nouvelle adresse de la personne est enregistrée',
loading: 'chargement en cours...'
}
};

View File

@@ -11,7 +11,9 @@ const store = createStore({
address: {},
editAddress: {}, //TODO or should be address?
person: {},
errorMsg: []
errorMsg: [],
loading: false,
success: false
},
getters: {
},
@@ -39,11 +41,17 @@ const store = createStore({
console.log('@M getEditAddress address', address);
state.editAddress = address;
},
setLoading(state, b) {
state.loading = b;
},
setSuccess(state, b) {
state.success = b;
}
},
actions: {
addAddress({ commit }, payload) {
console.log('@A addAddress payload', payload);
commit('setLoading', true);
if('newPostalCode' in payload){
let postalCodeBody = payload.newPostalCode;
postalCodeBody = Object.assign(postalCodeBody, {'origin': 3});
@@ -55,9 +63,11 @@ const store = createStore({
.then(address => new Promise((resolve, reject) => {
commit('addAddress', address);
resolve();
commit('setLoading', false);
}))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
});
})
@@ -66,15 +76,17 @@ const store = createStore({
.then(address => new Promise((resolve, reject) => {
commit('addAddress', address);
resolve();
commit('setLoading', false);
}))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
});
}
},
addDateToAddressAndAddressToPerson({ commit }, payload) {
console.log('@A addDateToAddressAndAddressToPerson payload', payload);
commit('setLoading', true);
patchAddress(payload.addressId, payload.body)
.then(address => new Promise((resolve, reject) => {
commit('addDateToAddress', address.validFrom);
@@ -84,13 +96,17 @@ const store = createStore({
.then(person => new Promise((resolve, reject) => {
commit('addAddressToPerson', person);
resolve();
commit('setLoading', false);
commit('setSuccess', true);
}))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
})
))
.catch((error) => {
commit('catchError', error);
commit('setLoading', false);
});
},
updateAddress({ commit }, payload) {

View File

@@ -19,6 +19,10 @@
<template v-slot:body>
<div class="address_form">
<div v-if="loading">
{{ $t('loading') }}
</div>
<div class="address_form__header">
<h4>{{ $t('select_an_address_title') }}</h4>
</div>
@@ -110,6 +114,7 @@ export default {
showModal: false,
modalDialogClass: "modal-dialog-scrollable modal-xl"
},
loading: false,
address: {
writeNewAddress: false,
writeNewPostalCode: false,
@@ -143,7 +148,7 @@ export default {
extra: null,
distribution: null,
},
errorMsg: {}
errorMsg: {},
}
},
computed: {
@@ -170,33 +175,42 @@ export default {
},
getCountries() {
console.log('getCountries');
this.loading = true;
fetchCountries().then(countries => new Promise((resolve, reject) => {
this.address.loaded.countries = countries.results;
resolve()
this.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.loading = false;
});
},
getCities(country) {
console.log('getCities for', country.name);
this.loading = true;
fetchCities(country).then(cities => new Promise((resolve, reject) => {
this.address.loaded.cities = cities.results.filter(c => c.origin !== 3); // filter out user-defined cities
resolve();
this.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.loading = false;
});
},
getReferenceAddresses(city) {
this.loading = true;
console.log('getReferenceAddresses for', city.name);
fetchReferenceAddresses(city).then(addresses => new Promise((resolve, reject) => {
console.log('addresses', addresses);
this.address.loaded.addresses = addresses.results;
resolve();
this.loading = false;
}))
.catch((error) => {
this.errorMsg.push(error.message);
this.loading = false;
});
},
updateMapCenter(point) {

View File

@@ -23,7 +23,7 @@ export default {
},
methods:{
init() {
map = L.map('address_map').setView([48.8589, 2.3469], 12);
map = L.map('address_map').setView([46.67059, -1.42683], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'

View File

@@ -5,6 +5,7 @@
<input
type="text"
name="floor"
maxlength=16
:placeholder="$t('floor')"
v-model="floor"/>
</div>
@@ -13,6 +14,7 @@
<input
type="text"
name="corridor"
maxlength=16
:placeholder="$t('corridor')"
v-model="corridor"/>
</div>
@@ -21,6 +23,7 @@
<input
type="text"
name="steps"
maxlength=16
:placeholder="$t('steps')"
v-model="steps"/>
</div>
@@ -29,6 +32,7 @@
<input
type="text"
name="flat"
maxlength=16
:placeholder="$t('flat')"
v-model="flat"/>
</div>
@@ -37,6 +41,7 @@
<input
type="text"
name="buildingName"
maxlength=255
:placeholder="$t('buildingName')"
v-model="buildingName"/>
</div>
@@ -45,6 +50,7 @@
<input
type="text"
name="extra"
maxlength=255
:placeholder="$t('extra')"
v-model="extra"/>
</div>
@@ -53,6 +59,7 @@
<input
type="text"
name="distribution"
maxlength=255
:placeholder="$t('distribution')"
v-model="distribution"/>
</div>

View File

@@ -1,4 +1,5 @@
<template>
<div class="chill_address_address chill_address_address--multiline">
<div v-if="address.text">
{{ address.text }}
</div>
@@ -28,7 +29,8 @@
</div>
<div v-if="address.distribution">
<span>{{ $t('distribution') }}</span>: {{ address.distribution }}
</div>
</div>
</div>
</template>
<script>

View File

@@ -19,7 +19,6 @@ class CollectionNormalizer implements NormalizerInterface, NormalizerAwareInterf
public function normalize($collection, string $format = null, array $context = [])
{
/** @var $collection Collection */
/** @var $collection Chill\MainBundle\Pagination\PaginatorInterface */
$paginator = $collection->getPaginator();
$data['count'] = $paginator->getTotalItems();

View File

@@ -58,13 +58,14 @@ services:
arguments:
- "@chill.main.helper.translatable_string"
- '@Symfony\Component\Routing\Generator\UrlGeneratorInterface'
- '@chill.main.form.choice_loader.postal_code'
- '@Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader'
- '@Symfony\Component\Translation\TranslatorInterface'
tags:
- { name: form.type }
chill.main.form.choice_loader.postal_code:
class: Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader
Chill\MainBundle\Form\ChoiceLoader\PostalCodeChoiceLoader:
autowire: true
autoconfigure: true
chill.main.form.type.export:
class: Chill\MainBundle\Form\Type\Export\ExportType