diff --git a/phpstan-types.neon b/phpstan-types.neon
index 1aae06880..b11cbd153 100644
--- a/phpstan-types.neon
+++ b/phpstan-types.neon
@@ -340,11 +340,6 @@ parameters:
count: 1
path: src/Bundle/ChillPersonBundle/Form/Type/PersonPhoneType.php
- -
- message: "#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#"
- count: 3
- path: src/Bundle/ChillPersonBundle/Search/PersonSearch.php
-
-
message: "#^Method Chill\\\\PersonBundle\\\\Search\\\\PersonSearch\\:\\:renderResult\\(\\) should return string but return statement is missing\\.$#"
count: 1
diff --git a/src/Bundle/ChillMainBundle/Controller/AbsenceController.php b/src/Bundle/ChillMainBundle/Controller/AbsenceController.php
new file mode 100644
index 000000000..5dafa4615
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Controller/AbsenceController.php
@@ -0,0 +1,65 @@
+getUser();
+ $form = $this->createForm(AbsenceType::class, $user);
+
+ $form->handleRequest($request);
+
+ if ($form->isSubmitted() && $form->isValid()) {
+ $em = $this->getDoctrine()->getManager();
+ $em->flush();
+
+ return $this->redirect($this->generateUrl('chill_main_user_absence_index'));
+ }
+
+ return $this->render('@ChillMain/Menu/absence.html.twig', [
+ 'user' => $user,
+ 'form' => $form->createView(),
+ ]);
+ }
+
+ /**
+ * @Route(
+ * "/{_locale}/absence/unset",
+ * name="chill_main_user_absence_unset",
+ * methods={"GET", "POST"}
+ * )
+ */
+ public function unsetAbsence(Request $request)
+ {
+ $user = $this->getUser();
+
+ $user->setAbsenceStart(null);
+ $em = $this->getDoctrine()->getManager();
+ $em->flush();
+
+ return $this->redirect($this->generateUrl('chill_main_user_absence_index'));
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php
index dda6b63e4..a8ef88fbe 100644
--- a/src/Bundle/ChillMainBundle/Entity/User.php
+++ b/src/Bundle/ChillMainBundle/Entity/User.php
@@ -11,14 +11,15 @@ declare(strict_types=1);
namespace Chill\MainBundle\Entity;
+use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use RuntimeException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Serializer\Annotation as Serializer;
-use Symfony\Component\Validator\Context\ExecutionContextInterface;
+use Symfony\Component\Validator\Context\ExecutionContextInterface;
use function in_array;
/**
@@ -40,6 +41,11 @@ class User implements UserInterface
*/
protected ?int $id = null;
+ /**
+ * @ORM\Column(type="datetime_immutable", nullable=true)
+ */
+ private ?DateTimeImmutable $absenceStart = null;
+
/**
* Array where SAML attributes's data are stored.
*
@@ -173,6 +179,11 @@ class User implements UserInterface
{
}
+ public function getAbsenceStart(): ?DateTimeImmutable
+ {
+ return $this->absenceStart;
+ }
+
/**
* Get attributes.
*
@@ -291,6 +302,11 @@ class User implements UserInterface
return $this->usernameCanonical;
}
+ public function isAbsent(): bool
+ {
+ return null !== $this->getAbsenceStart() && $this->getAbsenceStart() <= new DateTimeImmutable('now');
+ }
+
/**
* @return bool
*/
@@ -355,6 +371,11 @@ class User implements UserInterface
}
}
+ public function setAbsenceStart(?DateTimeImmutable $absenceStart): void
+ {
+ $this->absenceStart = $absenceStart;
+ }
+
public function setAttributeByDomain(string $domain, string $key, $value): self
{
$this->attributes[$domain][$key] = $value;
diff --git a/src/Bundle/ChillMainBundle/Form/AbsenceType.php b/src/Bundle/ChillMainBundle/Form/AbsenceType.php
new file mode 100644
index 000000000..d0aed640c
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Form/AbsenceType.php
@@ -0,0 +1,38 @@
+add('absenceStart', ChillDateType::class, [
+ 'required' => true,
+ 'input' => 'datetime_immutable',
+ 'label' => 'absence.Absence start',
+ ]);
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefaults([
+ 'data_class' => User::class,
+ ]);
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Form/UserType.php b/src/Bundle/ChillMainBundle/Form/UserType.php
index b738cc8c7..dc2140997 100644
--- a/src/Bundle/ChillMainBundle/Form/UserType.php
+++ b/src/Bundle/ChillMainBundle/Form/UserType.php
@@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Center;
use Chill\MainBundle\Entity\Location;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\UserJob;
+use Chill\MainBundle\Form\Type\ChillDateType;
use Chill\MainBundle\Form\Type\PickCivilityType;
use Chill\MainBundle\Templating\TranslatableStringHelper;
use Doctrine\ORM\EntityRepository;
@@ -110,6 +111,11 @@ class UserType extends AbstractType
return $qb;
},
+ ])
+ ->add('absenceStart', ChillDateType::class, [
+ 'required' => false,
+ 'input' => 'datetime_immutable',
+ 'label' => 'absence.Absence start',
]);
// @phpstan-ignore-next-line
diff --git a/src/Bundle/ChillMainBundle/Resources/public/types.ts b/src/Bundle/ChillMainBundle/Resources/public/types.ts
index 142864393..9453c89b0 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/types.ts
+++ b/src/Bundle/ChillMainBundle/Resources/public/types.ts
@@ -35,6 +35,7 @@ export interface User {
id: number;
username: string;
text: string;
+ text_without_absence: string;
email: string;
user_job: Job;
label: string;
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/UserRenderBoxBadge.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/UserRenderBoxBadge.vue
index a5e1cf183..a9c2db9b4 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/UserRenderBoxBadge.vue
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/UserRenderBoxBadge.vue
@@ -1,8 +1,7 @@
{{ user.label }}
- ({{ user.user_job.label.fr }})
- ({{ user.main_scope.name.fr }})
+ ({{ user.user_job.label.fr }}) ({{ user.main_scope.name.fr }}) A
diff --git a/src/Bundle/ChillMainBundle/Resources/views/Entity/user.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Entity/user.html.twig
index 77dc959a2..ad05a5a2c 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/Entity/user.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/Entity/user.html.twig
@@ -6,4 +6,7 @@
{%- if opts['main_scope'] and user.mainScope is not null %}
({{ user.mainScope.name|localize_translatable_string }})
{%- endif -%}
+ {%- if opts['absence'] and user.isAbsent %}
+ {{ 'absence.A'|trans }}
+ {%- endif -%}
diff --git a/src/Bundle/ChillMainBundle/Resources/views/Homepage/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Homepage/index.html.twig
index aec38f3c3..98af21171 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/Homepage/index.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/Homepage/index.html.twig
@@ -1,15 +1,15 @@
-
{# vue component #}
-
+
{% include '@ChillMain/Homepage/fast_actions.html.twig' %}
+
{% block css %}
{{ encore_entry_link_tags('page_homepage_widget') }}
{% endblock %}
{% block js %}
{{ encore_entry_script_tags('page_homepage_widget') }}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/src/Bundle/ChillMainBundle/Resources/views/Menu/absence.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Menu/absence.html.twig
new file mode 100644
index 000000000..3258b5ac1
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/views/Menu/absence.html.twig
@@ -0,0 +1,43 @@
+{% extends '@ChillMain/Admin/layout.html.twig' %}
+
+{% block title %}
+ {{ 'absence.My absence'|trans }}
+{% endblock title %}
+
+{% block content %}
+
+
+
{{ 'absence.My absence'|trans }}
+
+ {% if user.absenceStart is not null %}
+
+
{{ 'absence.You are listed as absent, as of'|trans }} {{ user.absenceStart|format_date('long') }}
+
+
+ {% else %}
+
+
{{ 'absence.No absence listed'|trans }}
+
+
+ {{ form_start(form) }}
+ {{ form_row(form.absenceStart) }}
+
+
+
+ {{ form_end(form) }}
+
+ {% endif %}
+
+
+{% endblock %}
diff --git a/src/Bundle/ChillMainBundle/Resources/views/User/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/User/index.html.twig
index 0f1168113..b57e17c06 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/User/index.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/User/index.html.twig
@@ -2,20 +2,21 @@
{% block admin_content %}
{% embed '@ChillMain/CRUD/_index.html.twig' %}
-
+
{% block index_header %}
{{"Users"|trans}}
{% endblock %}
-
+
{% block filter_order %}{{ filter_order|chill_render_filter_order_helper }}{% endblock %}
-
+
{% block table_entities_thead_tr %}
{{ 'Active'|trans }} |
+ {{ 'absence.Is absent'|trans }} |
{{ 'Username'|trans }} |
{{ 'Datas'|trans }} |
{{ 'Actions'|trans }} |
{% endblock %}
-
+
{% block table_entities_tbody %}
{% for entity in entities %}
@@ -26,6 +27,13 @@
{% endif %}
+
+ {% if entity.isAbsent %}
+
+ {% else %}
+
+ {% endif %}
+ |
{#
{% if entity.civility is not null %}
@@ -64,13 +72,13 @@
-
+
{% if allow_change_password is same as(true) %}
{% endif %}
-
+
{% if is_granted('ROLE_ALLOWED_TO_SWITCH') %}
@@ -81,9 +89,9 @@
|
{% endfor %}
{% endblock %}
-
+
{% block pagination %}{{ chill_pagination(paginator) }}{% endblock %}
-
+
{% block list_actions %}
{% endblock list_actions %}
-
+
{% endembed %}
{% endblock %}
diff --git a/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig b/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig
index 319adad81..92454be35 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/layout.html.twig
@@ -69,18 +69,26 @@
{% block content %}
+ {% if app.user.isAbsent %}
+
+ {% endif %}
{{ 'Search'|trans }}
diff --git a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php
index e0e8a782f..ea5ed2062 100644
--- a/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php
+++ b/src/Bundle/ChillMainBundle/Routing/MenuBuilder/UserMenuBuilder.php
@@ -78,6 +78,15 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
$nbNotifications = $this->notificationByUserCounter->countUnreadByUser($user);
+ //TODO add an icon? How exactly? For example a clock icon...
+ $menu
+ ->addChild($this->translator->trans('absence.Set absence date'), [
+ 'route' => 'chill_main_user_absence_index',
+ ])
+ ->setExtras([
+ 'order' => -8888888,
+ ]);
+
$menu
->addChild(
$this->translator->trans('notification.My notifications with counter', ['nb' => $nbNotifications]),
diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php
index a8607cc21..fde3a3d8e 100644
--- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php
+++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php
@@ -31,6 +31,7 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
'id' => '',
'username' => '',
'text' => '',
+ 'text_without_absent' => '',
'label' => '',
'email' => '',
];
@@ -82,11 +83,13 @@ class UserNormalizer implements ContextAwareNormalizerInterface, NormalizerAware
'id' => $object->getId(),
'username' => $object->getUsername(),
'text' => $this->userRender->renderString($object, []),
+ 'text_without_absent' => $this->userRender->renderString($object, ['absence' => false]),
'label' => $object->getLabel(),
'email' => (string) $object->getEmail(),
'user_job' => $this->normalizer->normalize($object->getUserJob(), $format, $userJobContext),
'main_center' => $this->normalizer->normalize($object->getMainCenter(), $format, $centerContext),
'main_scope' => $this->normalizer->normalize($object->getMainScope(), $format, $scopeContext),
+ 'isAbsent' => $object->isAbsent(),
];
if ('docgen' === $format) {
diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php
index 141de2649..6780db742 100644
--- a/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php
+++ b/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php
@@ -13,8 +13,10 @@ namespace Chill\MainBundle\Templating\Entity;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Templating\TranslatableStringHelper;
-use Symfony\Component\Templating\EngineInterface;
+use DateTimeImmutable;
+use Symfony\Component\Templating\EngineInterface;
+use Symfony\Contracts\Translation\TranslatorInterface;
use function array_merge;
class UserRender implements ChillEntityRenderInterface
@@ -22,16 +24,20 @@ class UserRender implements ChillEntityRenderInterface
public const DEFAULT_OPTIONS = [
'main_scope' => true,
'user_job' => true,
+ 'absence' => true,
];
private EngineInterface $engine;
private TranslatableStringHelper $translatableStringHelper;
- public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine)
+ private TranslatorInterface $translator;
+
+ public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine, TranslatorInterface $translator)
{
$this->translatableStringHelper = $translatableStringHelper;
$this->engine = $engine;
+ $this->translator = $translator;
}
public function renderBox($entity, array $options): string
@@ -63,6 +69,10 @@ class UserRender implements ChillEntityRenderInterface
->localize($entity->getMainScope()->getName()) . ')';
}
+ if ($entity->isAbsent() && $opts['absence']) {
+ $str .= ' (' . $this->translator->trans('absence.Absent') . ')';
+ }
+
return $str;
}
diff --git a/src/Bundle/ChillMainBundle/config/services/form.yaml b/src/Bundle/ChillMainBundle/config/services/form.yaml
index 8157c27e9..232e81dd6 100644
--- a/src/Bundle/ChillMainBundle/config/services/form.yaml
+++ b/src/Bundle/ChillMainBundle/config/services/form.yaml
@@ -138,9 +138,8 @@ services:
autowire: true
autoconfigure: true
- Chill\MainBundle\Form\RegroupmentType:
- autowire: true
- autoconfigure: true
+ Chill\MainBundle\Form\AbsenceType: ~
+ Chill\MainBundle\Form\RegroupmentType: ~
Chill\MainBundle\Form\DataTransformer\IdToLocationDataTransformer: ~
Chill\MainBundle\Form\DataTransformer\IdToUserDataTransformer: ~
diff --git a/src/Bundle/ChillMainBundle/migrations/Version20230111160610.php b/src/Bundle/ChillMainBundle/migrations/Version20230111160610.php
new file mode 100644
index 000000000..c00a3f521
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/migrations/Version20230111160610.php
@@ -0,0 +1,37 @@
+addSql('ALTER TABLE users DROP absenceStart');
+ }
+
+ public function getDescription(): string
+ {
+ return 'Add absence property to user';
+ }
+
+ public function up(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE users ADD absenceStart TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL');
+ $this->addSql('COMMENT ON COLUMN users.absenceStart IS \'(DC2Type:datetime_immutable)\'');
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
index 63e93891f..f01976e87 100644
--- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
@@ -584,3 +584,17 @@ saved_export:
Export is deleted: L'export est supprimé
Saved export is saved!: L'export est enregistré
Created on %date%: Créé le %date%
+
+
+absence:
+ # single letter for absence
+ A: A
+ My absence: Mon absence
+ Unset absence: Supprimer la date d'absence
+ Set absence date: Indiquer une date d'absence
+ Absence start: Absent à partir du
+ Absent: Absent
+ You are marked as being absent: Vous êtes indiqué absent.
+ You are listed as absent, as of: Votre absence est indiquée à partir du
+ No absence listed: Aucune absence indiquée.
+ Is absent: Absent?
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue
index 7e3b45103..dcade7e0f 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Banner.vue
@@ -22,7 +22,12 @@
{{ $t('course.open_at') }}{{ $d(accompanyingCourse.openingDate.datetime, 'text') }}
- {{ $t('course.referrer') }}: {{ accompanyingCourse.user.text }}
+ {{ $t('course.referrer') }}:
+ {{ accompanyingCourse.user.text }}
+
+
+ A
+
@@ -59,13 +64,15 @@
import ToggleFlags from './Banner/ToggleFlags';
import SocialIssue from './Banner/SocialIssue.vue';
import PersonsAssociated from './Banner/PersonsAssociated.vue';
+import UserRenderBoxBadge from 'ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue';
export default {
name: 'Banner',
components: {
ToggleFlags,
SocialIssue,
- PersonsAssociated
+ PersonsAssociated,
+ UserRenderBoxBadge,
},
computed: {
accompanyingCourse() {
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js
index 44238b0c7..170e19bf9 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/js/i18n.js
@@ -29,7 +29,8 @@ const appMessages = {
emergency: "urgent",
confidential: "confidentiel",
regular: "régulier",
- occasional: "ponctuel"
+ occasional: "ponctuel",
+ absent: "Absent",
},
origin: {
title: "Origine de la demande",
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeUser.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeUser.vue
index 7a8b302c7..a549e7970 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeUser.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_components/AddPersons/TypeUser.vue
@@ -1,9 +1,7 @@
-
- {{ item.result.text }}
-
+
@@ -16,10 +14,12 @@