Merge remote-tracking branch 'origin/master' into rector/rules-up-to-php74

This commit is contained in:
2023-04-27 23:32:31 +02:00
64 changed files with 584 additions and 577 deletions

View File

@@ -274,7 +274,7 @@ class ApiController extends AbstractCRUDController
$postedData = $this->getSerializer()->deserialize($request->getContent(), $postedDataType, $_format, $postedDataContext);
} catch (\Symfony\Component\Serializer\Exception\UnexpectedValueException $e) {
throw new BadRequestHttpException(sprintf('Unable to deserialize posted ' .
'data: %s', $e->getMessage()), 0, $e);
'data: %s', $e->getMessage()), $e, 0);
}
switch ($request->getMethod()) {

View File

@@ -107,5 +107,4 @@ class AddressToReferenceMatcherController
true
);
}
}

View File

@@ -31,7 +31,7 @@ class GroupCenter
* )
* @ORM\Cache(usage="NONSTRICT_READ_WRITE")
*/
private $center;
private ?Center $center = null;
/**
* @var int
@@ -40,83 +40,64 @@ class GroupCenter
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
private ?int $id = null;
/**
* @var PermissionsGroup
*
* @ORM\ManyToOne(
* targetEntity="Chill\MainBundle\Entity\PermissionsGroup",
* inversedBy="groupCenters")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE")
*/
private $permissionsGroup;
private ?PermissionsGroup $permissionsGroup = null;
/**
* @var Collection
*
* @ORM\ManyToMany(
* targetEntity="Chill\MainBundle\Entity\User",
* mappedBy="groupCenters"
* )
* @var Collection<User::class>
*/
private $users;
private Collection $users;
/**
* GroupCenter constructor.
*/
public function __construct()
{
$this->permissionsGroup = new ArrayCollection();
$this->users = new ArrayCollection();
}
/**
* @return Center
*/
public function getCenter()
public function getCenter(): ?Center
{
return $this->center;
}
/**
* @return int
*/
public function getId()
public function getId(): ?int
{
return $this->id;
}
/**
* @return PermissionGroup
*/
public function getPermissionsGroup()
public function getPermissionsGroup(): ?PermissionsGroup
{
return $this->permissionsGroup;
}
/**
* @return ArrayCollection|Collection
* @return Collection<User::class>
*/
public function getUsers()
public function getUsers(): Collection
{
return $this->users;
}
/**
* @return \Chill\MainBundle\Entity\GroupCenter
*/
public function setCenter(Center $center)
public function setCenter(Center $center): self
{
$this->center = $center;
return $this;
}
/**
* @return \Chill\MainBundle\Entity\GroupCenter
*/
public function setPermissionsGroup(PermissionsGroup $permissionsGroup)
public function setPermissionsGroup(PermissionsGroup $permissionsGroup): self
{
$this->permissionsGroup = $permissionsGroup;

View File

@@ -87,6 +87,7 @@ class ComposedRoleScopeType extends AbstractType
->add('scope', EntityType::class, [
'class' => Scope::class,
'choice_label' => static fn (Scope $scope) => $translatableStringHelper->localize($scope->getName()),
'placeholder' => 'Choose amongst scopes',
'required' => false,
'data' => null,
]);

View File

@@ -60,13 +60,15 @@ class ScopePickerType extends AbstractType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$items = array_filter(
$this->authorizationHelper->getReachableScopes(
$this->security->getUser(),
$options['role'] instanceof Role ? $options['role']->getRole() : $options['role'],
$options['center']
),
static fn (Scope $s) => $s->isActive()
$items = array_values(
array_filter(
$this->authorizationHelper->getReachableScopes(
$this->security->getUser(),
$options['role'] instanceof Role ? $options['role']->getRole() : $options['role'],
$options['center']
),
static fn (Scope $s) => $s->isActive()
)
);
if (0 === count($items)) {

View File

@@ -241,7 +241,7 @@ class WorkflowStepType extends AbstractType
function ($step, ExecutionContextInterface $context, $payload) {
$form = $context->getObject();
foreach($form->get('future_dest_users')->getData() as $u) {
foreach ($form->get('future_dest_users')->getData() as $u) {
if (in_array($u, $form->get('future_cc_users')->getData(), true)) {
$context
->buildViolation('workflow.The user in cc cannot be a dest user in the same workflow step')

View File

@@ -15,7 +15,10 @@ use Chill\MainBundle\Entity\User;
use Psr\Log\LoggerInterface;
use Swift_Mailer;
use Swift_Message;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Templating\EngineInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;
@@ -26,43 +29,34 @@ use function call_user_func;
* Classe d'aide pour l'envoi de notification.
*
* Héberge toutes les méthodes pour ré-écrire les URL en fonction de la langue de l'utilisateur.
*
* @deprecated use the MailerInterface
*/
class Mailer
{
/**
* @var Swift_Mailer
*/
protected $forcedMailer;
/**
* @var LoggerInterface
*/
protected $logger;
/**
* @var Swift_Mailer
*/
protected $mailer;
private $logger;
/**
* @var array
*/
protected $routeParameters;
private $routeParameters;
/**
* @var RouterInterface
*/
protected $router;
private $router;
/**
* @var TranslatorInterface
*/
protected $translator;
private $translator;
/**
* @var \Twig\Environment
*/
protected $twig;
private EngineInterface $twig;
private MailerInterface $mailer;
/**
* Mailer constructor.
@@ -70,11 +64,9 @@ class Mailer
* @param $routeParameters
*/
public function __construct(
MailerInterface $mailer,
LoggerInterface $logger,
Environment $twig,
Swift_Mailer $mailer,
// due to bug https://github.com/symfony/swiftmailer-bundle/issues/127
// \Swift_Transport $mailerTransporter,
EngineInterface $twig,
RouterInterface $router,
TranslatorInterface $translator,
$routeParameters
@@ -82,7 +74,6 @@ class Mailer
$this->logger = $logger;
$this->twig = $twig;
$this->mailer = $mailer;
//$this->forcedMailer = new \Swift_Mailer($mailerTransporter);
$this->router = $router;
$this->translator = $translator;
$this->routeParameters = $routeParameters;
@@ -115,20 +106,6 @@ class Mailer
return $content;
}
/**
* @param $force
*
* @throws \Symfony\Component\Mailer\Exception\TransportExceptionInterface
*/
public function sendMessage(Swift_Message $message, $force)
{
if ($force) {
$this->forcedMailer->send($message);
} else {
$this->mailer->send($message);
}
}
/**
* Envoie une notification à un utilisateur.
*
@@ -155,23 +132,25 @@ class Mailer
$subject[2] ?? null
);
$message = (new Swift_Message($subjectI18n))
->setFrom($fromEmail, $fromName)
->setTo($to);
$email = new Email();
$email->addTo($to)->subject($subjectI18n);
foreach ($bodies as $contentType => $content) {
$message->setBody($content, $contentType);
match ($contentType) {
'text/plain' => $email->text($content),
default => $email->text($content),
};
}
if (null !== $callback) {
call_user_func($callback, $message);
call_user_func($callback, $email);
}
$this->logger->info('[notification] Sending notification', [
'to' => $message->getTo(),
'subject' => $message->getSubject(),
'to' => $email->getTo(),
'subject' => $email->getSubject()
]);
$this->sendMessage($message, $force);
$this->mailer->send($email);
}
}

View File

@@ -375,6 +375,12 @@ span.dt {
font-weight: bolder;
background-color: var(--bs-chill-light-gray);
}
/// help text
.help-text {
margin-top: 0.25rem;
font-size: 0.875em;
color: var(--bs-gray);
}
/*

View File

@@ -1,3 +1,11 @@
/// mixin to set sticky area on bottom when scrolling
@mixin sticky-bottom {
position: sticky;
bottom: 0;
margin-top: 4em;
z-index: 1000;
}
ul.record_actions {
display: flex;
flex-direction: row;
@@ -53,16 +61,30 @@ ul.record_actions {
}
}
}
.sticky-form {
background-color: $white;
padding-top: 1.25em;
margin: -1em;
box-shadow: 0 -20px 20px -20px rgba($chill-gray, .5);
@include sticky-bottom;
.sticky-form-buttons {
position: initial;
bottom: unset;
margin-top: unset;
z-index: unset;
}
}
.sticky-form-buttons {
margin-top: 4em;
background-color: $beige;
position: sticky;
bottom: 0.3em;
text-align: center;
display: flex;
padding: 0.8em 1.6em;
border-radius: 0;
z-index: 1000;
display: flex;
background-color: $beige;
text-align: center;
padding: 0.8em 1.6em;
border-radius: 0;
@include sticky-bottom;
bottom: 0.3em;
}
/// EXCEPTIONS

View File

@@ -64,6 +64,7 @@ section.chill-entity {
margin: 0.7em 0;
p {
display: block;
margin-bottom: 0;
}
}
&.delimiter {

View File

@@ -1,7 +1,7 @@
<template>
<span v-if="data.working_ref_status === 'to_review'" class="badge bg-danger address-details-button-warning">L'adresse de référence a été modifiée</span>
<a v-if="data.loading === false" @click.prevent="clickOrOpen" class="btn btn-sm btn-misc">
<span class="fa fa-map address-details-button"></span>
<a v-if="data.loading === false" @click.prevent="clickOrOpen" class="btn btn-misc address-details-button">
<span class="fa fa-map"></span> <!-- button -->
</a>
<span v-if="data.loading" class="fa fa-spin fa-spinner "></span>
<AddressModal :address="data.working_address" @update-address="onUpdateAddress" ref="address_modal"></AddressModal>

View File

@@ -1,7 +1,7 @@
{% set formId = crudMainFormId|default('crud_main_form') %}
{% block crud_content_header %}
<h1>{{ ('crud.'~crud_name~'.title_edit')|trans }}</h1>
<h1 class="mb-5">{{ ('crud.'~crud_name~'.title_edit')|trans }}</h1>
{% endblock crud_content_header %}
{% block crud_content_form %}

View File

@@ -14,7 +14,7 @@
{% endblock %}
{% else %}
{% block table_entities %}
<table class="table table-bordered border-dark">
<table class="table table-bordered border-dark align-middle">
<thead>
<tr>
{% block table_entities_thead_tr %}

View File

@@ -10,6 +10,7 @@
* has_no_address bool
* multiline bool multiline display
* extended_infos bool add extra informations (step, floor, etc.) DEPRECATED
* details_button bool add an address details button
#}
@@ -79,7 +80,12 @@
<i class="fa fa-fw fa-map-marker"></i>
{% endif %}
{{ _self.inline(address, options, streetLine, lines) }}
<span data-address-details="1" data-address-id="{{ address.id|escape('html_attr') }}" data-address-ref-status="{{ address.refStatus|escape('html_attr') }}"></span>
{% if options['details_button'] is defined and options['details_button'] == true %}
<span data-address-details="1"
data-address-id="{{ address.id|escape('html_attr') }}"
data-address-ref-status="{{ address.refStatus|escape('html_attr') }}">
</span>
{% endif %}
</span>
{%- endif -%}
@@ -112,7 +118,12 @@
<i class="fa fa-fw fa-map-marker"></i>
{% endif %}
{{ _self.raw(lines) }}
<p><span data-address-details="1" data-address-id="{{ address.id|escape('html_attr') }}" data-address-ref-status="{{ address.refStatus|escape('html_attr') }}"></span></p>
{% if options['details_button'] is defined and options['details_button'] == true %}<p class="mt-3">
<span data-address-details="1"
data-address-id="{{ address.id|escape('html_attr') }}"
data-address-ref-status="{{ address.refStatus|escape('html_attr') }}">
</span></p>
{% endif %}
</div>
{% endif %}
{{ _self.validity(address, options) }}

View File

@@ -1,8 +1,8 @@
<footer class="footer">
<p>
{{ 'This program is free software: you can redistribute it and/or modify it under the terms of the <strong>GNU Affero General Public License</strong>'|trans|raw }}
<br/>
<a name="bottom" class="btn text-white" href="https://{{ app.request.locale }}.wikibooks.org/wiki/Chill" target="_blank">
<br/>
<a name="bottom" class="btn text-white" href="https://gitea.champs-libres.be/Chill-project/manuals/releases" target="_blank">
{{ 'User manual'|trans }}
</a>
</p>

View File

@@ -3,93 +3,130 @@
{% block title %}{{ 'PermissionsGroup "%name%" edit'|trans( { '%name%': entity.name } ) }}{% endblock %}
{% block admin_content -%}
<h1>{{ 'PermissionsGroup "%name%" edit'|trans( { '%name%': entity.name } ) }}</h1>
<div class="container-xxl">
<div class="row">
<h2>{{ 'Details'|trans }}</h2>
<h1 class="mb-4">{{ 'PermissionsGroup "%name%" edit'|trans( { '%name%': entity.name } ) }}</h1>
{{ form_start(edit_form) }}
{{ form_row(edit_form.name) }}
{% if edit_form.flags is defined %}
{{ form_row(edit_form.flags) }}
{% endif %}
{{ form_row(edit_form.submit, { 'attr': { 'class': 'btn btn-chill-green' } } ) }}
{{ form_end(edit_form) }}
<h2>{{ 'Details'|trans }}</h2>
<h2>{{ 'Grant those permissions'|trans }} :</h2>
{{ form_start(edit_form) }}
{{ form_row(edit_form.name) }}
{% if edit_form.flags is defined %}
{{ form_row(edit_form.flags) }}
{% endif %}
{{ form_row(edit_form.submit, { 'attr': { 'class': 'btn btn-save float-end' } } ) }}
{{ form_end(edit_form) }}
{%- if entity.getRoleScopes|length > 0 -%}
{% for title, role_scopes in role_scopes_sorted %}
<h2 class="mb-5">{{ 'Grant those permissions'|trans }} :</h2>
<h3>{{ title|default("Unclassified")|trans }}</h3>
{%- if entity.getRoleScopes|length > 0 -%}
{% for title, role_scopes in role_scopes_sorted %}
<table class="striped rounded">
<thead>
<h3>{{ title|default("Unclassified")|trans }}</h3>
<table class="table table-bordered border-dark align-middle mb-5">
<thead>
<tr>
<th>{{ 'Circle'|trans }}</th>
<th class="w-75">{{ 'Role'|trans }}</th>
<th>{{ 'Actions'|trans }}</th>
</tr>
</thead>
<tbody>
{% for role_scope in role_scopes %}
<tr>
<th>{{ 'Role'|trans }}</th>
<th>{{ 'Circle'|trans }}</th>
<th>{{ 'Actions'|trans }}</th>
</tr>
</thead>
<tbody>
{% for role_scope in role_scopes %}
<tr>
<td>
<span class="role_scope role">{{ role_scope.role|trans }}</span>
{% if expanded_roles[role_scope.role]|length > 1 %}
<br/>
<small>{{ 'Which implies'|trans }}&nbsp;: {% for role in expanded_roles[role_scope.role] %}{{ role|trans }}{% if not loop.last %}, {% endif %}{% endfor %}</small>
<td style="width: 7em">
{%- if role_scope.scope is not null -%}
<span class="role_scope scope">
{{ role_scope.scope.name|localize_translatable_string }}
</span>
{%- else -%}
<small><i>N/A</i></small>
{%- endif -%}
</td>
<td>
<span class="role_scope role">{{ role_scope.role|trans }}</span>
{% if expanded_roles[role_scope.role]|length > 1 %}
<div class="help-text">
<span style="text-decoration: underline dotted;">{{ 'Which implies'|trans }}&nbsp;:</span>
{% for role in expanded_roles[role_scope.role] %}
{% if role != role_scope.role %}
{{ role|trans }}
{% if not loop.last %}, {% endif %}
{% endif %}
{% endfor %}
</div>
{% endif %}
</td>
<td>
{%- if role_scope.scope is not null -%}
<span class="role_scope scope">
{{ role_scope.scope.name|localize_translatable_string }}
</span>
{%- else -%}
<em>N/A</em>
{%- endif -%}
</td>
<td>
{{ form_start(delete_role_scopes_form[role_scope.id]) }}
{{ form_widget(delete_role_scopes_form[role_scope.id].submit, { 'attr': { 'class': 'btn btn-chill-red' } } ) }}
{{ form_end(delete_role_scopes_form[role_scope.id]) }}
</td>
</tr>
</td>
<td style="width: 7em">
{{ form_start(delete_role_scopes_form[role_scope.id]) }}
{{ form_widget(delete_role_scopes_form[role_scope.id].submit, { 'attr': { 'class': 'btn btn-remove' } } ) }}
{{ form_end(delete_role_scopes_form[role_scope.id]) }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% endfor %}
</tbody>
</table>
{% endfor %}
{%- else -%}
<p>{{ 'This group does not provide any permission'|trans }}</p>
{%- endif -%}
{%- else -%}
<p>{{ 'This group does not provide any permission'|trans }}</p>
{%- endif -%}
</div>
<div class="row sticky-form">
<div class="mt-5">
<h2>{{ 'Grant new permissions'|trans }}</h2>
{{ form_start(add_role_scopes_form) }}
{{ form_errors(add_role_scopes_form) }}
{{ form_row(add_role_scopes_form.composed_role_scope.role) }}
{{ form_row(add_role_scopes_form.composed_role_scope.scope) }}
<div class="input-group">
{{ form_widget(add_role_scopes_form.composed_role_scope.role, { 'attr': { 'class': 'w-50' }}) }}
{{ form_widget(add_role_scopes_form.composed_role_scope.scope) }}
</div>
<div id="role_scope_legend" class="help-text mb-3">{{ 'Help to pick role and scope'|trans }}</div>
<ul class="record_actions sticky-form-buttons">
<li>
{{ form_row(add_role_scopes_form.submit, { 'attr' : { 'class': 'btn btn-create' } } ) }}
</li>
<li>
<a href="{{ path('admin_permissionsgroup_show', { 'id': entity.id }) }}" class="btn btn-cancel">{{ 'Cancel'|trans }}</a>
</li>
<li>
<li class="cancel">
<a href="{{ path('admin_permissionsgroup') }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
<a href="{{ path('admin_permissionsgroup_show', { 'id': entity.id }) }}" class="btn btn-misc">{{ 'Cancel'|trans }}</a>
</li>
<li>
{{ form_widget(add_role_scopes_form.submit, { 'attr' : { 'class': 'btn btn-create' } } ) }}
</li>
</ul>
{{ form_end(add_role_scopes_form) }}
</div>
</div>
{% endblock %}
{% block js %}
<script>
// An event listener give contextual legend when choosing an option.
const select = document.getElementById('form_composed_role_scope_role');
const legend = document.getElementById('role_scope_legend');
select.addEventListener('change', function() {
const option = this.options[this.selectedIndex];
const hasScope = option.getAttribute('data-has-scope');
legend.style.display = 'block';
if (hasScope === '0') {
legend.innerText = '{{ 'The role does not need scope'|trans }}';
} else if (hasScope === '1') {
legend.innerText = '{{ 'The role need scope'|trans }}';
} else {
legend.innerText = '{{ 'Help to pick role and scope'|trans }}';
}
});
</script>
{% endblock %}

View File

@@ -5,7 +5,7 @@
{% block admin_content -%}
<h1>{{ 'Permissions group list'|trans }}</h1>
<table class="records_list">
<table class="table table-bordered border-dark align-middle">
<thead>
<tr>
<th>{{ 'Name'|trans }}</th>

View File

@@ -10,8 +10,6 @@
{% if form.flags is defined %}
{{ form_row(form.flags) }}
{% endif %}
{{ form_row(form.submit, { 'attr': { 'class': 'btn btn-chill-green' } } ) }}
{{ form_end(form) }}
<ul class="record_actions sticky-form-buttons">
<li class='cancel'>
@@ -19,5 +17,10 @@
{{ 'Back to the list'|trans }}
</a>
</li>
<li>
{{ form_widget(form.submit, { 'attr': { 'class': 'btn btn-create' } } ) }}
</li>
</ul>
{{ form_end(form) }}
{% endblock %}

View File

@@ -3,44 +3,52 @@
{% block title %}{{ 'Permission group "%name%"'|trans({ '%name%': entity.name }) }}{% endblock %}
{% block admin_content -%}
<h1>{{ 'Permission group "%name%"'|trans({ '%name%': entity.name }) }}</h1>
<h1 class="mb-4">{{ 'Permission group "%name%"'|trans({ '%name%': entity.name }) }}</h1>
<table class="record_properties">
<table class="table table-bordered border-dark align-middle">
<tbody>
<tr>
<th>{{ 'Name'|trans }}</th>
<td>{{ entity.name }}</td>
<td class="w-25">{{ entity.name }}</td>
</tr>
</tbody>
</table>
{% if role_scopes_sorted|length > 0 %}
<h2>{{ 'Grant those permissions'|trans }}&nbsp;:</h2>
<h2 class="mb-5">{{ 'Grant those permissions'|trans }}&nbsp;:</h2>
{% for title, role_scopes in role_scopes_sorted %}
<h3>{{ title|default('Unclassified')|trans }}</h3>
<table class="striped rounded">
<table class="table table-bordered border-dark align-middle mb-5">
<thead>
<tr>
<th class="w-25">{{ 'Circle'|trans }}</th>
<th>{{ 'Role'|trans }}</th>
<th>{{ 'Circle'|trans }}</th>
</tr>
</thead>
<tbody>
{% for role_scope in role_scopes %}
<tr>
<td>
{{ role_scope.role|trans }}
{% if expanded_roles[role_scope.role]|length > 1 %}
<br/>
<small>{{ 'Which implies'|trans }}&nbsp;: {% for role in expanded_roles[role_scope.role] %}{{ role|trans }}{% if not loop.last %}, {% endif %}{% endfor %}</small>
{% endif %}
</td>
<td>{%- if role_scope.scope is not null -%}
{{ role_scope.scope.name|localize_translatable_string }}
<td style="width: 7em">{%- if role_scope.scope is not null -%}
{{ role_scope.scope.name|localize_translatable_string }}
{%- else -%}
<em>N/A</em>
{%- endif -%}
<small><i>N/A</i></small>
{%- endif -%}
</td>
<td>
<span class="role_scope role">{{ role_scope.role|trans }}</span>
{% if expanded_roles[role_scope.role]|length > 1 %}
<div class="help-text">
<span style="text-decoration: underline dotted;">{{ 'Which implies'|trans }}&nbsp;:</span>
{% for role in expanded_roles[role_scope.role] %}
{% if role != role_scope.role %}
{{ role|trans }}
{% if not loop.last %}, {% endif %}
{% endif %}
{% endfor %}
</div>
{% endif %}
</td>
</tr>
{% endfor %}
@@ -57,17 +65,15 @@
{% endif %}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a href="{{ path('admin_permissionsgroup') }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>
<li>
<a href="{{ path('admin_permissionsgroup_edit', { 'id': entity.id }) }}" class="btn btn-edit">
{{ 'Edit'|trans }}
</a>
</li>
<li>
<a href="{{ path('admin_permissionsgroup') }}" class="btn btn-cancel">
{{ 'Back to the list'|trans }}
</a>
</li>
</ul>
{% endblock %}

View File

@@ -4,10 +4,10 @@
{% embed '@ChillMain/CRUD/_edit_content.html.twig' %}
{% block crud_content_after_form %}
{% if access_permissions_group_list %}
<h2>{{ 'Permissions granted'|trans }}</h2>
<h2 class="mt-5">{{ 'Permissions granted'|trans }}</h2>
{% if entity.groupcenters|length > 0 %}
<table>
<table class="table table-bordered border-dark align-middle mb-5">
<thead>
<tr>
<th>{{ 'Permission group'|trans }}</th>
@@ -19,18 +19,18 @@
{% for groupcenter in entity.groupcenters %}
<tr>
<td>
<span class="user_group permissionsgroup">
{{ groupcenter.permissionsgroup.name }}
</span>
<span class="user_group permissionsgroup">
{{ groupcenter.permissionsgroup.name }}
</span>
</td>
<td>
<span class="user_group center">
{{ groupcenter.center.name }}
</span>
<span class="user_group center">
{{ groupcenter.center.name }}
</span>
</td>
<td>
<td class="w-25 text-end">
{{ form_start(delete_groupcenter_form[groupcenter.id]) }}
{{ form_row(delete_groupcenter_form[groupcenter.id].submit, { 'attr': { 'class': 'btn btn-chill-red' } } ) }}
{{ form_widget(delete_groupcenter_form[groupcenter.id].submit, { 'attr': { 'class': 'btn btn-remove' } } ) }}
{{ form_rest(delete_groupcenter_form[groupcenter.id]) }}
{{ form_end(delete_groupcenter_form[groupcenter.id]) }}
</td>
@@ -47,7 +47,7 @@
{{ form_start(add_groupcenter_form) }}
{{ form_row(add_groupcenter_form.composed_groupcenter.center) }}
{{ 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-create' } } ) }}
{{ form_end(add_groupcenter_form) }}
{% endif %}

View File

@@ -69,19 +69,20 @@
</td>
<td>
<ul class="record_actions">
{% 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 %}
<li>
<a class="btn btn-edit" title="{{ 'Edit'|trans }}" href="{{ path('chill_crud_admin_user_edit', { 'id': entity.id }) }}"></a>
</li>
{% if allow_change_password is same as(true) %}
<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>
{% endif %}
{% 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>
<a class="btn btn-reset" href="{{ path('admin_user_edit_password', { 'id' : entity.id }) }}" title="{{ 'Edit password'|trans|e('html_attr') }}"><i class="fa fa-key-modern"></i></a>
</li>
{% endif %}
</ul>

View File

@@ -2,14 +2,14 @@
{% block admin_content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
{% block table_entities_thead_tr %}
<th>id</th>
<th>{{ 'Label'|trans }}</th>
<th>{{ 'Active'|trans }}</th>
<th>{{ 'Actions'|trans }}</th>
{% endblock %}
{% block table_entities_tbody %}
{% for entity in entities %}
<tr>
@@ -25,19 +25,19 @@
<td>
<ul class="record_actions">
<li>
<a href="{{ chill_path_add_return_path('chill_crud_admin_user_job_edit', { 'id': entity.id}) }}" class="btn btn-sm btn-edit btn-mini"></a>
<a href="{{ chill_path_add_return_path('chill_crud_admin_user_job_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

@@ -120,6 +120,11 @@ class AuthorizationHelper implements AuthorizationHelperInterface
if ($role instanceof Role) {
$role = $role->getRole();
}
if (!$user instanceof User) {
return [];
}
/** @var array<string, Center> $centers */
$centers = [];

View File

@@ -14,6 +14,8 @@ namespace Chill\MainBundle\Security\PasswordRecover;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Notification\Mailer;
use DateTimeInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use function array_merge;
@@ -22,33 +24,26 @@ class RecoverPasswordHelper
{
public const RECOVER_PASSWORD_ROUTE = 'password_recover';
/**
* @var Mailer
*/
protected $mailer;
protected $routeParameters;
private MailerInterface $mailer;
/**
* @var TokenManager
*/
protected $tokenManager;
private $tokenManager;
/**
* @var UrlGeneratorInterface
*/
protected $urlGenerator;
private $urlGenerator;
public function __construct(
TokenManager $tokenManager,
UrlGeneratorInterface $urlGenerator,
Mailer $mailer,
array $routeParameters
MailerInterface $mailer,
) {
$this->tokenManager = $tokenManager;
$this->urlGenerator = $urlGenerator;
$this->mailer = $mailer;
$this->routeParameters = $routeParameters;
}
/**
@@ -59,27 +54,14 @@ class RecoverPasswordHelper
*/
public function generateUrl(User $user, DateTimeInterface $expiration, $absolute = true, array $parameters = [])
{
$context = $this->urlGenerator->getContext();
$previousHost = $context->getHost();
$previousScheme = $context->getScheme();
$context->setHost($this->routeParameters['host']);
$context->setScheme($this->routeParameters['scheme']);
$url = $this->urlGenerator->generate(
return $this->urlGenerator->generate(
self::RECOVER_PASSWORD_ROUTE,
array_merge(
$this->tokenManager->generate($user, $expiration),
$parameters
),
$absolute ? UrlGeneratorInterface::ABSOLUTE_URL : UrlGeneratorInterface::ABSOLUTE_PATH
UrlGeneratorInterface::ABSOLUTE_URL
);
// reset the host
$context->setHost($previousHost);
$context->setScheme($previousScheme);
return $url;
}
public function sendRecoverEmail(
@@ -91,26 +73,20 @@ class RecoverPasswordHelper
array $additionalUrlParameters = [],
$emailSubject = 'Recover your password'
) {
$content = $this->mailer->renderContentToUser(
$user,
$template,
array_merge(
[
'user' => $user,
'url' => $this->generateUrl($user, $expiration, true, $additionalUrlParameters),
],
$templateParameters
)
);
if (null === $user->getEmail() || '' === trim($user->getEmail())) {
throw new \UnexpectedValueException("No emaail associated to the user");
}
$this->mailer->sendNotification(
$user,
[$emailSubject],
[
'text/plain' => $content,
],
null,
$force
);
$email = (new TemplatedEmail())
->subject($emailSubject)
->to($user->getEmail())
->textTemplate($template)
->context([
'user' => $user,
'url' => $this->generateUrl($user, $expiration, true, $additionalUrlParameters),
...$templateParameters
]);
$this->mailer->send($email);
}
}

View File

@@ -207,7 +207,7 @@ final class GeographicalUnitBaseImporter
(id, geom, unitname, layer_id, unitrefid)
SELECT
nextval('chill_main_geographical_unit_id_seq'),
geom,
st_makevalid(geom),
unitName,
layer.id,
unitKey

View File

@@ -78,8 +78,8 @@ class PostalCodeFRFromOpenData
private function handleRecord(array $record): void
{
if ('' !== trim($record['coordonnees_gps'])) {
[$lat, $lon] = array_map(static fn ($el) => (float) trim($el), explode(',', $record['coordonnees_gps']));
if ('' !== trim($record['coordonnees_geographiques'] ?? $record['coordonnees_gps'])) {
[$lat, $lon] = array_map(static fn ($el) => (float) trim($el), explode(',', $record['coordonnees_geographiques'] ?? $record['coordonnees_gps']));
} else {
$lat = $lon = 0.0;
}

View File

@@ -10,12 +10,6 @@ services:
Chill\MainBundle\Notification\Mailer:
arguments:
$logger: '@Psr\Log\LoggerInterface'
$twig: '@Twig\Environment'
$mailer: '@swiftmailer.mailer.default'
# $mailerTransporter: '@swiftmailer.transport'
$router: '@Symfony\Component\Routing\RouterInterface'
$translator: '@Symfony\Contracts\Translation\TranslatorInterface'
$routeParameters: '%chill_main.notifications%'
Chill\MainBundle\Notification\NotificationHandlerManager:

View File

@@ -61,11 +61,7 @@ services:
arguments:
$secret: '%kernel.secret%'
Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper:
arguments:
$tokenManager: '@Chill\MainBundle\Security\PasswordRecover\TokenManager'
$mailer: '@Chill\MainBundle\Notification\Mailer'
$routeParameters: "%chill_main.notifications%"
Chill\MainBundle\Security\PasswordRecover\RecoverPasswordHelper: ~
Chill\MainBundle\Security\PasswordRecover\PasswordRecoverEventSubscriber:
arguments:

View File

@@ -69,7 +69,6 @@ final class Version20230306145728 extends AbstractMigration
$this->addSql('CREATE INDEX IDX_165051F63174800F ON chill_main_address (createdBy_id)');
$this->addSql('CREATE INDEX IDX_165051F665FF1AEC ON chill_main_address (updatedBy_id)');
$this->addSql('COMMENT ON COLUMN chill_main_address_reference.point IS \'(DC2Type:point)\'');
}
public function down(Schema $schema): void

View File

@@ -167,12 +167,16 @@ Permissionsgroup: Groupe de permissions
New permission group: Nouveau groupe de permissions
PermissionsGroup "%name%" edit: Modification du groupe de permission '%name%'
Role: Rôle
Choose amongst roles: Choisir parmi les rôles
Choose amongst roles: Choisir un rôle
Choose amongst scopes: Choisir un cercle
Add permission: Ajouter les permissions
This group does not provide any permission: Ce groupe n'attribue aucune permission
The role '%role%' has been removed: Le rôle "%role%" 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
Unclassified: Non classifié
Help to pick role and scope: Certains rôles ne nécessitent pas de cercle.
The role need scope: Ce rôle nécessite un cercle.
The role does not need scope: Ce rôle ne nécessite pas de cercle !
#admin section for users
User configuration: Gestion des utilisateurs
@@ -423,6 +427,7 @@ No entities: Aucun élément
CHILL_FOO_SEE: Voir un élément
CHILL_FOO_EDIT: Modifier un élément
chill_export: Exports (statistiques)
#Show templates
Date: Date