diff --git a/.editorconfig b/.editorconfig index fe115d4c0..d51908caf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,3 +18,10 @@ max_line_length = 80 [COMMIT_EDITMSG] max_line_length = 0 +<<<<<<< Updated upstream +======= + +[*.{js, vue, ts}] +indent_size = 2 +indent_style = space +>>>>>>> Stashed changes diff --git a/CHANGELOG.md b/CHANGELOG.md index 077cc0242..9d9a0da1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,31 @@ and this project adheres to ## Unreleased +* [workflow]: added pagination to workflow list page +* [homepage_widget]: null error on tasks widget fixed +* [person-thirdparty]: fix quick-add of names that consist of multiple parts (eg. De Vlieger) within onthefly modal person/thirdparty +* [search]: Order of birthdate fields changed in advanced search to avoid confusion. +* [workflow]: Constraint added to workflow (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/675) +* [action]: Agents traitants should be prefilled with referrer of the parcours or left empty if there is no referrer (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/696) + +## Test releases + +### 2022-05-30 + +* fix creating a new AccompanyingPeriodWorkEvaluationDocument when replacing the document (the workflow was lost) + +### 2022-05-27 + +* [storedobject] add title field on StoredObject entity + use it in activity documents (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/604) +* [main] add a "read more..." on comment embeddable when overflown (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/604) +* [person] add closing motive to closed acc course (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/603) +* [person] household filiation: fetch person info when unfolding person (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/586) +* [admin] repair edit of social action in the admin (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/601) +* [admin]: add select2 to Goal form type entity fields (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/702) +* [main] allow hide permissions group list menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/577) +* [main] allow hide change user password menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/577) +* [main] filter user jobs by active jobs (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/577) +* [main] add civility to User (entity, migration and form type) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/577) * [admin] refactorisation of the admin section: reorganisation of the menu, translations, form types, new entities (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/592) * [admin] add admin section for languages and countries (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/596) * [activity] activity admin: translations + remove label field for comment on admin activity type (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/587) @@ -18,8 +43,6 @@ and this project adheres to * [address] can add extra address info even if noAddress (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/576) -## Test releases - ### 2022-05-06 * [person] add civility when creating a person (with the on-the-fly component or in the php form) (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/557) @@ -32,6 +55,7 @@ and this project adheres to * [person] add maritalStatusComment to PersonDocGenNormalizer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/582) * Load relationships without gender in french fixtures * Add command to remove old draft accompanying periods +* [parcours]: If users assings him/herself as referrer and job is not null. Update parcours job (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/578) ### 2021-04-28 diff --git a/composer.json b/composer.json index d0fc51c0e..b815e58b0 100644 --- a/composer.json +++ b/composer.json @@ -10,8 +10,8 @@ "require": { "php": "^7.4", "champs-libres/async-uploader-bundle": "dev-sf4#d57134aee8e504a83c902ff0cf9f8d36ac418290", - "champs-libres/wopi-bundle": "dev-master#59b468503b9413f8d588ef9e626e7675560db3d8", - "champs-libres/wopi-lib": "dev-master#0e1da19bb6de820080b8651867a7e475be590060", + "champs-libres/wopi-bundle": "dev-master#6dd8e0a14e00131eb4b889ecc30270ee4a0e5224", + "champs-libres/wopi-lib": "dev-master#8615f4a45a39fc2b6a98765ea835fcfd39618787", "doctrine/doctrine-bundle": "^2.1", "doctrine/doctrine-migrations-bundle": "^3.0", "doctrine/orm": "^2.7", @@ -45,6 +45,7 @@ "symfony/translation": "^4.4", "symfony/twig-bundle": "^4.4", "symfony/validator": "^4.4", + "symfony/web-link": "*", "symfony/webpack-encore-bundle": "^1.11", "symfony/workflow": "^4.4", "symfony/yaml": "^4.4", diff --git a/phpstan-deprecations.neon b/phpstan-deprecations.neon index 2de8b8bc8..42981a551 100644 --- a/phpstan-deprecations.neon +++ b/phpstan-deprecations.neon @@ -471,11 +471,6 @@ parameters: count: 1 path: src/Bundle/ChillMainBundle/Form/Type/UserPickerType.php - - - message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" - count: 1 - path: src/Bundle/ChillMainBundle/Form/UserType.php - - message: "#^Only booleans are allowed in an if condition, mixed given\\.$#" count: 2 diff --git a/src/Bundle/ChillActivityBundle/Entity/Activity.php b/src/Bundle/ChillActivityBundle/Entity/Activity.php index 0c0632722..5fa0bca35 100644 --- a/src/Bundle/ChillActivityBundle/Entity/Activity.php +++ b/src/Bundle/ChillActivityBundle/Entity/Activity.php @@ -15,6 +15,7 @@ use Chill\ActivityBundle\Validator\Constraints as ActivityValidator; use Chill\DocStoreBundle\Entity\StoredObject; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; +use Chill\MainBundle\Entity\Embeddable\PrivateCommentEmbeddable; use Chill\MainBundle\Entity\HasCenterInterface; use Chill\MainBundle\Entity\HasScopeInterface; use Chill\MainBundle\Entity\Location; @@ -134,6 +135,11 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac */ private ?Collection $persons = null; + /** + * @ORM\Embedded(class="Chill\MainBundle\Entity\Embeddable\PrivateCommentEmbeddable", columnPrefix="privateComment_") + */ + private PrivateCommentEmbeddable $privateComment; + /** * @ORM\ManyToMany(targetEntity="Chill\ActivityBundle\Entity\ActivityReason") * @Groups({"docgen:read"}) @@ -193,6 +199,7 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac { $this->reasons = new ArrayCollection(); $this->comment = new CommentEmbeddable(); + $this->privateComment = new PrivateCommentEmbeddable(); $this->persons = new ArrayCollection(); $this->thirdParties = new ArrayCollection(); $this->documents = new ArrayCollection(); @@ -400,6 +407,11 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac return []; } + public function getPrivateComment(): PrivateCommentEmbeddable + { + return $this->privateComment; + } + public function getReasons(): Collection { return $this->reasons; @@ -586,6 +598,13 @@ class Activity implements AccompanyingPeriodLinkedWithSocialIssuesEntityInterfac return $this; } + public function setPrivateComment(PrivateCommentEmbeddable $privateComment): self + { + $this->privateComment = $privateComment; + + return $this; + } + public function setReasons(?ArrayCollection $reasons): self { $this->reasons = $reasons; diff --git a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php index bdf75ed05..845b31ca2 100644 --- a/src/Bundle/ChillActivityBundle/Entity/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Entity/ActivityType.php @@ -167,6 +167,16 @@ class ActivityType */ private int $personVisible = self::FIELD_REQUIRED; + /** + * @ORM\Column(type="string", nullable=false, options={"default": ""}) + */ + private string $privateCommentLabel = ''; + + /** + * @ORM\Column(type="smallint", nullable=false, options={"default": 1}) + */ + private int $privateCommentVisible = self::FIELD_OPTIONAL; + /** * @ORM\Column(type="string", nullable=false, options={"default": ""}) */ @@ -416,6 +426,16 @@ class ActivityType return $this->personVisible; } + public function getPrivateCommentLabel(): string + { + return $this->privateCommentLabel; + } + + public function getPrivateCommentVisible(): int + { + return $this->privateCommentVisible; + } + public function getReasonsLabel(): string { return $this->reasonsLabel; @@ -688,6 +708,20 @@ class ActivityType return $this; } + public function setPrivateCommentLabel(string $privateCommentLabel): self + { + $this->privateCommentLabel = $privateCommentLabel; + + return $this; + } + + public function setPrivateCommentVisible(int $privateCommentVisible): self + { + $this->privateCommentVisible = $privateCommentVisible; + + return $this; + } + public function setReasonsLabel(string $reasonsLabel): self { $this->reasonsLabel = $reasonsLabel; diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php index 6e75bde25..898f39e56 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -20,6 +20,7 @@ use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\ChillCollectionType; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\CommentType; +use Chill\MainBundle\Form\Type\PrivateCommentType; use Chill\MainBundle\Form\Type\ScopePickerType; use Chill\MainBundle\Form\Type\UserPickerType; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; @@ -251,6 +252,13 @@ class ActivityType extends AbstractType ]); } + if ($activityType->isVisible('privateComment')) { + $builder->add('privateComment', PrivateCommentType::class, [ + 'label' => '' === $activityType->getLabel('privateComment') ? 'private comment' : $activityType->getPrivateCommentLabel(), + 'required' => false, + ]); + } + if ($activityType->isVisible('persons')) { $builder->add('persons', HiddenType::class); $builder->get('persons') @@ -313,6 +321,7 @@ class ActivityType extends AbstractType 'button_add_label' => 'activity.Insert a document', 'button_remove_label' => 'activity.Remove a document', 'empty_collection_explain' => 'No documents', + 'entry_options' => ['has_title' => true], ]); } diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php index 17d2bb914..4cdcb31f2 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityTypeType.php @@ -57,7 +57,7 @@ class ActivityTypeType extends AbstractType $fields = [ 'persons', 'user', 'date', 'location', 'persons', 'thirdParties', 'durationTime', 'travelTime', 'attendee', - 'reasons', 'sentReceived', 'documents', + 'reasons', 'comment', 'privateComment', 'sentReceived', 'documents', 'emergency', 'socialIssues', 'socialActions', 'users', ]; diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig index 218dc37b0..8d9ee878c 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/edit.html.twig @@ -83,6 +83,10 @@ {{ form_row(edit_form.comment) }} {% endif %} +{%- if edit_form.privateComment is defined -%} + {{ form_row(edit_form.privateComment) }} +{% endif %} + {%- if edit_form.attendee is defined -%} {{ form_row(edit_form.attendee) }} {% endif %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig index f8b68eabd..79c946f17 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/list.html.twig @@ -2,12 +2,30 @@ {% if is_granted('CHILL_ACTIVITY_SEE_DETAILS', activity) %} {% if no_action is not defined or no_action == false %}
  • - - - {{ 'notification.Notify'|trans }} + {% set showGroup = activity.accompanyingPeriod is not null and activity.accompanyingPeriod.hasUser and activity.accompanyingPeriod.user is not same as(app.user) %} +
    + {% if showGroup %} + + + {% else %} + + {{ 'notification.Notify'|trans }} + + {% endif %} +
  • {% endif %} {% if context == 'person' and activity.accompanyingPeriod is not empty %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig index 8e078702c..6f6e1fe53 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/new.html.twig @@ -81,10 +81,13 @@ {% endif %} {%- if form.comment is defined -%} - {# TODO .. public and private #} {{ form_row(form.comment) }} {% endif %} +{%- if form.privateComment is defined -%} + {{ form_row(form.privateComment) }} +{% endif %} + {%- if form.attendee is defined -%} {{ form_row(form.attendee) }} {% endif %} diff --git a/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig b/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig index ce4c22304..49e71bfad 100644 --- a/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig +++ b/src/Bundle/ChillActivityBundle/Resources/views/Activity/show.html.twig @@ -1,4 +1,5 @@ {%- set t = entity.type -%} +{% set userId = app.user.id %} {%- import "@ChillDocStore/Macro/macro.html.twig" as m -%}

    {{ "Activity"|trans }}

    @@ -146,13 +147,28 @@ {% endif %} + {% if t.privateCommentVisible and is_granted('CHILL_ACTIVITY_SEE_DETAILS', entity) and entity.privateComment.hasCommentForUser(app.user) %} + {% if t.privateCommentLabel is not empty %} +
    {{ t.privateCommentLabel }}
    + {% else %} +
    {{ 'Private comment'|trans }}
    + {% endif %} +
    +
    +
    + {{ entity.privateComment.comments[userId] }} +
    +
    +
    + {% endif %} + {% if t.documentsVisible and is_granted('CHILL_ACTIVITY_SEE_DETAILS', entity) %}
    {{ 'Documents'|trans }}
    {% if entity.documents|length > 0 %} {% else %} @@ -201,9 +217,30 @@
  • - - {{ 'notification.Notify'|trans }} - + {% set showGroup = entity.accompanyingPeriod is not null and entity.accompanyingPeriod.hasUser and entity.accompanyingPeriod.user is not same as(app.user) %} +
    + {% if showGroup %} + + + {% else %} + + {{ 'notification.Notify'|trans }} + + {% endif %} +
  • {% if is_granted('CHILL_ACTIVITY_UPDATE', entity) %}
  • diff --git a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php index a787e9ecd..55d64ef93 100644 --- a/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php +++ b/src/Bundle/ChillActivityBundle/Service/DocGenerator/ActivityContext.php @@ -209,6 +209,7 @@ class ActivityContext implements */ public function storeGenerated(DocGeneratorTemplate $template, StoredObject $storedObject, object $entity, array $contextGenerationData): void { + $storedObject->setTitle($this->translatableStringHelper->localize($template->getName())); $entity->addDocument($storedObject); $this->em->persist($storedObject); diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20220425133027.php b/src/Bundle/ChillActivityBundle/migrations/Version20220425133027.php new file mode 100644 index 000000000..4a829f18c --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20220425133027.php @@ -0,0 +1,35 @@ +addSql('ALTER TABLE activitytype DROP privateCommentLabel'); + $this->addSql('ALTER TABLE activitytype DROP privateCommentVisible'); + } + + public function getDescription(): string + { + return 'add private comment option to activity types'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE activitytype ADD privateCommentLabel VARCHAR(255) DEFAULT \'\' NOT NULL'); + $this->addSql('ALTER TABLE activitytype ADD privateCommentVisible SMALLINT DEFAULT 1 NOT NULL'); + } +} diff --git a/src/Bundle/ChillActivityBundle/migrations/Version20220527124438.php b/src/Bundle/ChillActivityBundle/migrations/Version20220527124438.php new file mode 100644 index 000000000..2661edf4b --- /dev/null +++ b/src/Bundle/ChillActivityBundle/migrations/Version20220527124438.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE chill_person_accompanying_period_work DROP privateComment_comments'); + } + + public function getDescription(): string + { + return 'add private comment to activity'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE activity ADD privateComment_comments JSON DEFAULT \'{}\''); + } +} diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 3ca4def7c..abfa0ea89 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -44,6 +44,7 @@ Received: Recevoir by: 'Par ' location: Lieu Reasons: Sujets +Private comment: Commentaire privé #forms @@ -175,6 +176,8 @@ Reasons visible: Visibilité du champ Sujet Reasons label: Libellé du champ Sujet Comment visible: Visibilité du champ Commentaire Comment label: Libellé du champ Commentaire +Private comment visible: Visibilité du champ Commentaire Privé +Private comment label: Libellé du champ Commentaire Privé Emergency visible: Visibilité du champ Urgent Emergency label: Libellé du champ Urgent Accompanying period visible: Visibilité du champ Période d'accompagnement diff --git a/src/Bundle/ChillActivityBundle/translations/messages.nl.yaml b/src/Bundle/ChillActivityBundle/translations/messages.nl.yaml new file mode 100644 index 000000000..8d7cc293a --- /dev/null +++ b/src/Bundle/ChillActivityBundle/translations/messages.nl.yaml @@ -0,0 +1,234 @@ +#general +Show the activity: Toon activiteit +Edit the activity: Wijzig activiteit +Activity: Activiteit +Duration time: Duur +Duration Time: Duur +durationTime: duur +Travel time: Duur van verplaatsing +Attendee: Aanwezigheden +attendee: aanwezigheden +list_reasons: Onderwerpen +user_username: gebruikersnaam +circle_name: naam kring +Remark: Opmerking +No comments: Geen opmerkingen +Add a new activity: Voeg een nieuwe activiteit toe +Activity list: Lijst van activiteiten +present: aanwezig +not present: afwezig +Delete: Verwijderen +Update: Bijwerken +Update activity: Activieit bijwerken +Scope: Werkingsgebied +Activity data: Gegevens activiteit +Activity location: Locatie activiteit +No reason associated: Geen onderwerp +No social issues associated: Geen sociaal vraagstuk +No social actions associated: Geen maatschappelijke actie +There isn't any activities.: Er zijn geen activiteiten +type_name: Soort activiteit +person_firstname: voornaam +person_lastname: familienaam +person_id: Identificatienummer persoon +Type: Soort +Invisible: Onzichtbaar +Optional: Optioneel +Required: Verplicht +Persons: Personen +Users: Gebruikers +Emergency: Dringend +Sent received: Inkomend / Uitgaand +Sent: Verzenden +Received: Ontvangen +by: 'Door ' +location: Plaats +Reasons: Onderwerpen + + +#forms +Activity creation: Nouvelle activité +Create: Créer +Back to the list: Retour à la liste +Save activity: Sauver l'activité +Reset form: Remise à zéro du formulaire +Choose the duration: Choisir la durée +Choose a type: Choisir un type +5 minutes: 5 minutes +10 minutes: 10 minutes +15 minutes: 15 minutes +20 minutes: 20 minutes +25 minutes: 25 minutes +30 minutes: 30 minutes +45 minutes: 45 minutes +1 hour: 1 heure +1 hour 15: 1 heure 15 +1 hour 30: 1 heure 30 +1 hour 45: 1 heure 45 +2 hours: 2 heures +Concerned groups: Parties concernées +Persons in accompanying course: Usagers du parcours +Third persons: Tiers non-pro. +Others persons: Usagers +Third parties: Tiers professionnels +Users concerned: T(M)S +activity: + Insert a document: Insérer un document + Remove a document: Supprimer le document + comment: Commentaire +No documents: Aucun document + +#timeline +'%user% has done an %activity_type%': '%user% a effectué une activité de type "%activity_type%"' + +#controller +'Success : activity created!': L'activité a été créée. +'The form is not valid. The activity has not been created !': Le formulaire est invalide. L'activité n'a pas été créée. +'Success : activity updated!': L'activité a été mise à jour. +'The form is not valid. The activity has not been updated !': Le formulaire est invalide. L'activité n'a pas été mise à jour. + +# ROLES +CHILL_ACTIVITY_CREATE: Créer une activité +CHILL_ACTIVITY_UPDATE: Modifier une activité +CHILL_ACTIVITY_SEE: Voir une activité +CHILL_ACTIVITY_SEE_DETAILS: Voir le détail des activités +CHILL_ACTIVITY_DELETE: Supprimer une activité +CHILL_ACTIVITY_STATS: Statistique des activités +CHILL_ACTIVITY_LIST: Liste des activités + +# admin +Activities: Activités +Activity configuration: Configuration des activités +Activity configuration menu: Configuration des activités +Activity types: Types d'activité +Activity type configuration: Configuration des categories d'activités +Activity Reasons: Sujets d'une activité +Activity Reasons Category: Catégories de sujet d'activités +Activity Types Categories: Catégories des types d'activité +Activity Presences: Presences des activités + + +# Crud +crud: + activity_type: + title_new: Nouveau type d'activité + title_edit: Edition d'un type d'activité + activity_type_category: + title_new: Nouvelle catégorie de type d'activité + title_edit: Edition d'une catégorie de type d'activité + +# activity reason admin +ActivityReason list: Liste des sujets +Create a new activity reason: Créer un nouveau sujet +Active: Actif +Category: Catégorie +ActivityReason creation: Nouveau sujet +ActivityReason edit: Modification d'un sujet +ActivityReason: Sujet d'activité +The entity is inactive and won't be proposed: Le sujet est inactif et ne sera pas proposé +The entity is active and will be proposed: Le sujet est actif et sera proposé + +#activity reason category admin +ActivityReasonCategory list: Catégories de sujets +Create a new activity category reason: Créer une nouvelle catégorie +ActivityReasonCategory creation: Nouvelle catégorie de sujet +ActivityReasonCategory edit: Modification d'une catégorie de sujet +ActivityReasonCategory: Catégorie de sujet d'activité +ActivityReasonCategory is active and will be proposed: La catégorie est active et sera proposée +ActivityReasonCategory is inactive and won't be proposed: La catégorie est inactive et ne sera pas proposée + +# activity type type admin +ActivityType list: Types d'activités +Create a new activity type: Créer un nouveau type d'activité +Persons visible: Visibilité du champ Personnes +Persons label: Libellé du champ Personnes +User visible: Visibilité du champ Utilisateur +User label: Libellé du champ Utilisateur +Date visible: Visibilité du champ Date +Date label: Libellé du champ Date +Location visible: Visibilité du champ Lieu +Location label: Libellé du champ Lieu +Third parties visible: Visibilité du champ Tiers +Third parties label: Libellé du champ Tiers +Duration time visible: Visibilité du champ Durée +Duration time label: Libellé du champ Durée +Travel time visible: Visibilité du champ Durée de déplacement +Travel time label: Libellé du champ Durée de déplacement +Attendee visible: Visibilité du champ Présence de l'usager +Attendee label: Libellé du champ Présence de l'usager +Reasons visible: Visibilité du champ Sujet +Reasons label: Libellé du champ Sujet +Comment visible: Visibilité du champ Commentaire +Comment label: Libellé du champ Commentaire +Emergency visible: Visibilité du champ Urgent +Emergency label: Libellé du champ Urgent +Accompanying period visible: Visibilité du champ Période d'accompagnement +Accompanying period label: Libellé du champ Période d'accompagnement +Social issues visible: Visibilité du champ Problématiques sociales +Social issues label: Libellé du champ Problématiques sociales +Social actions visible: Visibilité du champ Action sociale +Social actions label: Libellé du champ Action sociale +Users visible: Visibilité du champ Utilisateurs +Users label: Libellé du champ Utilisateurs +Sent received visible: Visibilité du champ Entrant / Sortant +Sent received label: Libellé du champ Entrant / Sortant +Documents visible: Visibilité du champ Documents +Documents label: Libellé du champ Documents + +# activity type category admin +ActivityTypeCategory list: Liste des catégories des types d'activité +Create a new activity type category: Créer une nouvelle catégorie de type d'activité + +# activity delete +Remove activity: Supprimer une activité +Are you sure you want to remove the activity about "%name%" ?: Êtes-vous sûr de vouloir supprimer une activité qui concerne "%name%" ? +The activity has been successfully removed.: L'activité a été supprimée. + +# exports +Count activities: Nombre d'activités +Count activities by various parameters.: Compte le nombre d'activités enregistrées en fonction de différents paramètres. +Sum activity duration: Total de la durée des activités +Sum activities duration by various parameters.: Additionne la durée des activités en fonction de différents paramètres. +List activities: Liste les activités +Number of activities: Nombre d'activités + +#filters +Filter by reason: Filtrer par sujet d'activité +'Filtered by reasons: only %list%': 'Filtré par sujet: seulement %list%' +'Filtered by activity type: only %list%': "Filtré par type d'activity: seulement %list%" +Filtered by date activity: Filtrer par date d'activité +Activities after this date: Activités après cette date +Activities before this date: Activités avant cette date +"Filtered by date of activity: only between %date_from% and %date_to%": "Filtré par date de l'activité: uniquement entre %date_from% et %date_to%" +This date should be after the date given in "Implied in an activity after this date" field: Cette date devrait être postérieure à la date donnée dans le champ "activités après cette date" + +Filtered by person having an activity in a period: Uniquement les personnes ayant eu une activité dans la période donnée +Implied in an activity after this date: Impliqué dans une activité après cette date +Implied in an activity before this date: Impliqué dans une activité avant cette date +Filtered by person having an activity between %date_from% and %date_to% with reasons %reasons_name%: Filtré par personnes associées à une activité entre %date_from% et %date_to% avec les sujets %reasons_name% +Activity reasons for those activities: Sujets de ces activités + +Filter by activity type: Filtrer par type d'activité + +#aggregators +Activity type: Type d'activité +Activity user: Utilisateur lié à l'activity +By reason: Par sujet +By category of reason: Par catégorie de sujet +Reason's level: Niveau du sujet +Group by reasons: Sujet d'activité +Aggregate by activity user: Aggréger par utilisateur lié à l'activité +Aggregate by activity type: Aggréger par type d'activité +Aggregate by activity reason: Aggréger par sujet de l'activité + +Last activities: Les dernières activités + +See activity in accompanying course context: Voir l'activité dans le contexte du parcours d'accompagnement + +You get notified of an activity which does not exists any more: Cette notification ne correspond pas à une activité valide. +you are not allowed to see it details: La notification fait référence à une activité à laquelle vous n'avez pas accès. +This is the minimal activity data: Activité n° + +docgen: + Activity basic: Echange + A basic context for activity: Contexte pour les échanges diff --git a/src/Bundle/ChillActivityBundle/translations/validators.nl.yaml b/src/Bundle/ChillActivityBundle/translations/validators.nl.yaml new file mode 100644 index 000000000..a334ae523 --- /dev/null +++ b/src/Bundle/ChillActivityBundle/translations/validators.nl.yaml @@ -0,0 +1,23 @@ +The reasons's level should not be empty: Het onderwerp niveau mag niet leeg zijn. +At least one reason must be choosen: Kies minstens één onderwerp +For this type of activity, you must add at least one person: Voor dit soort activiteit dient u minstens één persoon toe te voegen. +For this type of activity, you must add at least one user: Voor dit soort activiteit dient u minstens één gebruiker toe te voegen. +For this type of activity, you must add at least one third party: Voor dit soort activiteit dient u minstens één externe partner toe te voegen. +For this type of activity, user is required: Voor dit soort activiteit, dient u een gebruiker in te vullen. +For this type of activity, date is required: Voor dit soort activiteit, dient u een datum in te vullen. +For this type of activity, location is required: Voor dit soort activiteit, dient u een locatie in te vullen. +For this type of activity, attendee is required: Voor dit soort activiteit, dient u minstend één 'aanwezige persoon' in te vullen. +For this type of activity, duration time is required: Voor dit soort activiteit, dient u een duur in te vullen. +For this type of activity, travel time is required: Voor dit soort activiteit, dient u een verplaatsingsduur in te vullen. +For this type of activity, reasons is required: Voor dit soort activiteit, dient u een onderwerp in te vullen. +For this type of activity, comment is required: Voor dit soort activiteit, dient u een opmerking in te vullen. +For this type of activity, sent/received is required: Voor dit soort activiteit, dient u het veld 'inkomend/uitgaand' in te vullen. +For this type of activity, document is required: Voor dit soort activiteit, dient u een document toe te voegen. +For this type of activity, emergency is required: Voor dit soort activiteit, is het veld 'dringend' verplicht. +For this type of activity, accompanying period is required: Voor dit soort activiteit, dient u een begeleidingstraject in te vullen. +For this type of activity, you must add at least one social issue: Voor dit soort activiteit, dient u een sociaal vraagstuk aan te duiden. +For this type of activity, you must add at least one social action: Voor dit soort activiteit, dient u een maatschappelijke actie toe te voegen. + +# admin +This parameter must be equal to social issue parameter: Deze parameter moet gelijk zijn aan de parameter "zichtbaarheid veld sociaal vraagstuk". +The socialActionsVisible value is not compatible with the socialIssuesVisible value: De waarde van de parameter "zichtbaarheid veld maatschappelijke actie" is niet compatibel met de waarde van de parameter "zichtbaarheid veld sociaal vraagstuk". diff --git a/src/Bundle/ChillAsideActivityBundle/src/translations/messages.nl.yaml b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.nl.yaml new file mode 100644 index 000000000..cae3cd059 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/translations/messages.nl.yaml @@ -0,0 +1,167 @@ +#general +Show the aside activity: Toon de nevenactiviteit +Edit the aside activity: Wijzig de nevenactiviteit +Remove aside activity: Verwijder de nevenactiviteit +Aside activity: Nevenactiviteit +Aside Activity Type List: Lijst van nevenactiviteiten +Duration time: Duur +durationTime: duur +user_username: gebruikersnaam +Remark: Opmerking +No comments: Geen opmerkingen +Add a new aside activity: Nevenactiviteit toeveogen +Aside activity list: Nevenactiviteiten +present: aanwezig +not present: afwezig +Delete: Verwijderen +Update: Bijwerken +Aside activity data: Gegevens van nevenactiviteit +There aren't any aside activities.: Geen nevenactiviteiten om weer te geven +Type: Type +Invisible: Onzichtbaar +Optional: Optioneel +Required: Verplicht +Persons: Personen +Users: Gebruikers +Emergency: Dringend +by: "Door " +location: Plaats + +# Crud +crud: + aside_activity: + title_view: Details nevenactiviteit + title_new: Nieuwe nevenactiviteit + title_edit: Wijzig nevenactiviteit + title_delete: Verwijder nevenactiviteit + button_delete: Verwijderen + confirm_message_delete: Bent u zeker deze nevenactiviteit te willen verwijderen? + aside_activity_category: + title_new: Nieuwe categorie nevenactiviteiten + title_edit: Wijzigen categorie nevenactiviteiten + +#forms +Create a new aside activity type: Nieuwe categorie nevenactiviteiten +Back to the list: Terug naar de lijst +Choose the duration: Kies een duur +Choose a category: Kies een categorie +Is active: Actief +For agent: Voor de gebruiker +date: Datum +Duration: Duur +Note: Opmerking +Choose the agent for whom this activity is created: Kies de gebruiker voor wie deze nevenactiviteit wordt aangemaakt. +Choose the activity category: Kies een categorie + +#Duration +minutes: minuten +hour: uur +hours: uren +day: dag +days: dagen +5 minutes: 5 minuten +10 minutes: 10 minuten +15 minutes: 15 minuten +20 minutes: 20 minuten +25 minutes: 25 minuten +30 minutes: 30 minuten +45 minutes: 45 minuten +1 hour: 1 uur +1 hour 15: 1 uur 15 +1 hour 30: 1 uur 30 +1 hour 45: 1 uur 45 +2 hours: 2 uren +2 hours 30: 2 uur 30 +3 hours: 3 uren +3 hours 30: 3 uur 30 +4 hours: 4 uren +4 hours 30: 4 uur 30 +5 hours: 5 uren +5 hours 30: 5 uur 30 +6 hours: 6 uren +6 hours 30: 6 uur 30 +7 hours: 7 uren +7 hours 30: 7 uur 30 +8 hours: 8 uren +8 hours 30: 8 uur 30 +9 hours: 9 uren +9 hours 30: 9 uur 30 +10 hours: 10 uren +1/2 day: 1/2 dag +1 day: 1 dag +1 1/2 days: 1 1/2 dagen +2 days: 2 dagen +2 1/2 days: 2 1/2 dagen +3 days: 3 dagen +3 1/2 days: 3 1/2 dagen +4 days: 4 dagen +4 1/2 days: 4 1/2 dagen +5 days: 5 dagen +5 1/2 days: 5 1/2 dagen +6 days: 6 dagen +6 1/2 days: 6 1/2 dagen +7 days: 7 dagen +7 1/2 days: 7 1/2 dagen +8 days: 8 dagen +8 1/2 days: 8 1/2 dagen +9 days: 9 dagen +9 1/2 days: 9 1/2 dagen +10 days: 10 dagen +10 1/2 days: 10 1/2 dagen +11 days: 11 dagen +11 1/2 days: 11 1/2 dagen +12 days: 12 dagen +12 1/2 days: 12 1/2 dagen +13 days: 13 dagen +13 1/2 days: 13 1/2 dagen +14 days: 14 dagen +14 1/2 days: 14 1/2 dagen +15 days: 15 dagen +15 1/2 days: 15 1/2 dagen +16 days: 16 dagen +16 1/2 days: 16 1/2 dagen +17 days: 17 dagen +17 1/2 days: 17 1/2 dagen +18 days: 18 dagen +18 1/2 days: 18 1/2 dagen +19 days: 19 dagen +19 1/2 days: 19 1/2 dagen +20 days: 20 dagen +20 1/2 days: 20 1/2 dagen +21 days: 21 dagen +21 1/2 days: 21 1/2 dagen +22 days: 22 dagen +22 1/2 days: 22 1/2 dagen +23 days: 23 dagen +23 1/2 days: 23 1/2 dagen +24 days: 24 dagen +24 1/2 days: 24 1/2 dagen +25 days: 25 dagen +25 1/2 days: 25 1/2 dagen +26 days: 26 dagen +26 1/2 days: 26 1/2 dagen +27 days: 27 dagen +27 1/2 days: 27 1/2 dagen +28 days: 28 dagen +28 1/2 days: 28 1/2 dagen +29 days: 29 dagen +29 1/2 days: 29 1/2 dagen +30 days: 30 dagen + +#list +My aside activities: Mijn nevenactiviteiten +#Aside activity delete +Delete aside activity: Verwijder een nevenactiviteit +Are you sure you want to remove the aside activity concerning "%name%" ?: Bent u zeker deze nevenactiviteit voor "%name%" te willen verwijderen ? +The activity has been successfully removed.: De nevenactiviteit werd verwijdert. + +#Menu +Create an aside activity: "Maak een nevenactiviteit aan" +Aside activity categories: Categorieën van nevenactiviteiten +Aside activity configuration menu: "Configuratie menu voor nevenactiviteiten" +Phonecall: "Telefoon oproep" + +# admin +Aside activities: Nevenactiviteiten +Aside activity types: Types nevenactiviteiten +Aside activity type configuration: Configuratie categorieën nevenactiviteiten diff --git a/src/Bundle/ChillAsideActivityBundle/src/translations/validators.nl.yaml b/src/Bundle/ChillAsideActivityBundle/src/translations/validators.nl.yaml new file mode 100644 index 000000000..5e6933bd5 --- /dev/null +++ b/src/Bundle/ChillAsideActivityBundle/src/translations/validators.nl.yaml @@ -0,0 +1 @@ +You must not add twice the same category in the parent tree (previous result returned): Je mag niet tweemaal dezelfde entiteit aanduiden in de stamboom. (Het vorige resultaat werd hersteld) diff --git a/src/Bundle/ChillBudgetBundle/translations/messages+intl-icu.nl.yml b/src/Bundle/ChillBudgetBundle/translations/messages+intl-icu.nl.yml new file mode 100644 index 000000000..b38b157da --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/translations/messages+intl-icu.nl.yml @@ -0,0 +1,8 @@ +budget: + number of elements: >- + {nb_items, plural, + =0 {Geen element} + one {Één element} + many {# elementen} + other {# elementen} + } diff --git a/src/Bundle/ChillBudgetBundle/translations/messages.fr.yml b/src/Bundle/ChillBudgetBundle/translations/messages.fr.yml index 1ccdcf1e6..299fa295e 100644 --- a/src/Bundle/ChillBudgetBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillBudgetBundle/translations/messages.fr.yml @@ -37,7 +37,7 @@ No charges registered: Aucune charge enregistrée No past resources registered: Aucune ressource passée No past charges registered: Aucune charge passée No future resources registered: Aucune ressource future enregistrée -No future charges registered: Aucune ressource future enregistrée +No future charges registered: Aucune charge future enregistrée No current budget element registered: Pas des éléments de budget actuelles enregistrés New resource: Nouvelle ressource diff --git a/src/Bundle/ChillBudgetBundle/translations/messages.nl.yml b/src/Bundle/ChillBudgetBundle/translations/messages.nl.yml new file mode 100644 index 000000000..5fd21520d --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/translations/messages.nl.yml @@ -0,0 +1,76 @@ +Budget: Budget +Resource: Inkomsten +Charge: Onkosten +Budget for %name%: Budget van %name% +Budget for household %household%: Budget van gezin +Current budget household members: Actuele budget van gezinsleden +Show budget of %name%: Toon budget van %name% +See complete budget: Toon volledige budget +Hide budget: Verbergen +Hide budget of %name%: Verberg budget van %name% +Resource element type: Type inkomsten +Actual budget: Actuele elementen budget +Actual resources: Actuele inkomsten +Actual resources for %name%: Actuele inkomsten van %name% +Actual charges for %name%: Actuele onkosten van %name% +Actual charges: Actuele onkosten +Past budget: Elementen van afgelopen budget +Show past budget: Toon afgelopen budget +Show future budget: Toon toekomstig budget +Past resources: Afgelopen inkomsten +Past charges: Afgelopen onkosten +Future budget: Toekomstige elementen van budget +Future resources: Toekomstige inkomsten +Future charges: Toekomstige onkosten +Budget element type: Type +Validity period: Geldigheidsperiod +Start of validity period: Begin geldigheidsperiode +End of validity period: Eind geldigheidsperiode +Total: Totaal +Create new resource: Nieuwe inkomsten toevoegen +Create new charge: Nieuwe onkosten toevoegen +See person: Toon persoon + +There isn't any element recorded: Geen budget elementen geregistreerd +No resources registered: Geen inkomsten geregistreerd +No charges registered: Geen onkosten geregistreerd +No past resources registered: Geen afgelopen inkomsten geregistreerd +No past charges registered: Geen afgelopen onkosten geregistreerd +No future resources registered: Geen toekomstige inkomsten geregistreerd +No future charges registered: Geen toekomste onkosten geregistreerd +No current budget element registered: Geen actuele budget elementen geregistreerd + +New resource: Nieuwe inkomsten +New charge: Nieuwe onkosten +Edit resource: Wijzig inkomsten +Edit: Wijzigen +Edit charge: Wijzig onkosten +Remove resource: Verwijder inkomsten +Remove charge: Verwijder onkosten +Are you sure you want to remove the ressource "%type%" associated to "%name%" ?: Bent u zeker de inkomsten van het type "%type%" en geassocieerd met %name% te willen verwijderen? +Are you sure you want to remove the charge "%type%" associated to "%name%" ?: Bent u zeker de onkosten van het type "%type%" en geassocieerd met %name% te willen verwijderen? +Resource deleted: Inkomsten verwijdert +Charge deleted: Onkosten verwijdert +Charge created: Onkosten toegevoegd +Resource created: Inkomsten toegevoegd +Resource updated: Inkomsten bijgewerkt +Charge updated: Onkosten bijgewerkt + +Choose a resource type: Kies een type inkomsten +Choose a charge type: Kies een type onkosten +Amount: Bedrag +Comment: Opmerking + +Help to pay charges: Hulp bij afbetaling onkosten +Choose a status: Kies een status +charge.help.running: In uitvoering +charge.help.no: Niet gevraagd +charge.help.yes: Ja +charge.help.not-concerned: Niet betrokken + +Budget calculator: Berekeningen en indicatoren van budget +Budget calculator result: Resultaten +The balance: Verschil tussen inkomsten en onkosten + +Valid since %startDate% until %endDate%: Geldig sinds %startDate% tot %endDate% +Valid since %startDate%: Geldig sinds %startDate% diff --git a/src/Bundle/ChillBudgetBundle/translations/validators.nl.yml b/src/Bundle/ChillBudgetBundle/translations/validators.nl.yml new file mode 100644 index 000000000..7281b6380 --- /dev/null +++ b/src/Bundle/ChillBudgetBundle/translations/validators.nl.yml @@ -0,0 +1,2 @@ +The amount cannot be empty: Le montant ne peut pas être vide ou égal à zéro +The budget element's end date must be after the start date: La date de fin doit être après la date de début \ No newline at end of file diff --git a/src/Bundle/ChillCalendarBundle/Entity/Calendar.php b/src/Bundle/ChillCalendarBundle/Entity/Calendar.php index 11104cc6a..c40bddb44 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/Calendar.php +++ b/src/Bundle/ChillCalendarBundle/Entity/Calendar.php @@ -14,6 +14,7 @@ namespace Chill\CalendarBundle\Entity; use Chill\ActivityBundle\Entity\Activity; use Chill\CalendarBundle\Repository\CalendarRepository; use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable; +use Chill\MainBundle\Entity\Embeddable\PrivateCommentEmbeddable; use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\User; use Chill\PersonBundle\Entity\AccompanyingPeriod; @@ -115,6 +116,12 @@ class Calendar */ private Collection $persons; + /** + * @ORM\Embedded(class=PrivateCommentEmbeddable::class, columnPrefix="privateComment_") + * @Serializer\Groups({"calendar:read"}) + */ + private PrivateCommentEmbeddable $privateComment; + /** * @ORM\ManyToMany( * targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty", @@ -151,6 +158,7 @@ class Calendar public function __construct() { $this->comment = new CommentEmbeddable(); + $this->privateComment = new PrivateCommentEmbeddable(); $this->persons = new ArrayCollection(); $this->professionals = new ArrayCollection(); $this->invites = new ArrayCollection(); @@ -278,6 +286,11 @@ class Calendar return []; } + public function getPrivateComment(): PrivateCommentEmbeddable + { + return $this->privateComment; + } + /** * @return Collection|ThirdParty[] */ @@ -407,6 +420,13 @@ class Calendar return $this; } + public function setPrivateComment(PrivateCommentEmbeddable $privateComment): self + { + $this->privateComment = $privateComment; + + return $this; + } + public function setSendSMS(?bool $sendSMS): self { $this->sendSMS = $sendSMS; diff --git a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php index 05dc362b4..b1dccb5fd 100644 --- a/src/Bundle/ChillCalendarBundle/Form/CalendarType.php +++ b/src/Bundle/ChillCalendarBundle/Form/CalendarType.php @@ -18,6 +18,7 @@ use Chill\CalendarBundle\Entity\Invite; use Chill\MainBundle\Entity\Location; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\CommentType; +use Chill\MainBundle\Form\Type\PrivateCommentType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Chill\PersonBundle\Entity\Person; use Chill\ThirdPartyBundle\Entity\ThirdParty; @@ -51,6 +52,10 @@ class CalendarType extends AbstractType ->add('comment', CommentType::class, [ 'required' => false, ]) + ->add('privateComment', PrivateCommentType::class, [ + 'required' => false, + 'label' => 'private comment', + ]) // ->add('cancelReason', EntityType::class, [ // 'required' => false, // 'class' => CancelReason::class, diff --git a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig index d67202920..b96d12c06 100644 --- a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig +++ b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/edit.html.twig @@ -47,6 +47,10 @@ {{ form_row(form.comment) }} {% endif %} +{%- if form.privateComment is defined -%} + {{ form_row(form.privateComment) }} +{% endif %} + {%- if form.sendSMS is defined -%} {{ form_row(form.sendSMS) }} {% endif %} diff --git a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig index 255c2641b..41adb52cc 100644 --- a/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig +++ b/src/Bundle/ChillCalendarBundle/Resources/views/Calendar/new.html.twig @@ -43,6 +43,10 @@ {{ form_row(form.comment) }} {% endif %} +{%- if form.privateComment is defined -%} + {{ form_row(form.privateComment) }} +{% endif %} + {%- if form.sendSMS is defined -%} {{ form_row(form.sendSMS) }} {% endif %} @@ -50,22 +54,22 @@
    {{ form_end(form) }} diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20220527124558.php b/src/Bundle/ChillCalendarBundle/migrations/Version20220527124558.php new file mode 100644 index 000000000..39c4cb7c3 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20220527124558.php @@ -0,0 +1,33 @@ +addSql('ALTER TABLE chill_calendar.calendar DROP privateComment_comments'); + } + + public function getDescription(): string + { + return 'add private comment to calendar'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_calendar.calendar ADD privateComment_comments JSON DEFAULT NULL'); + } +} diff --git a/src/Bundle/ChillCalendarBundle/migrations/Version20220527234046.php b/src/Bundle/ChillCalendarBundle/migrations/Version20220527234046.php new file mode 100644 index 000000000..9cb68932e --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/migrations/Version20220527234046.php @@ -0,0 +1,36 @@ +addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments DROP NOT NULL'); + $this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET DEFAULT NULL'); + } + + public function getDescription(): string + { + return ''; + } + + public function up(Schema $schema): void + { + $this->addSql('UPDATE chill_calendar.calendar SET privateComment_comments=\'{}\' WHERE privateComment_comments IS NULL'); + $this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET NOT NULL'); + $this->addSql('ALTER TABLE chill_calendar.calendar ALTER COLUMN privateComment_comments SET DEFAULT \'{}\''); + } +} diff --git a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml index aafa26622..da244fd13 100644 --- a/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillCalendarBundle/translations/messages.fr.yml @@ -26,6 +26,7 @@ The calendar item has been successfully removed.: Le rendez-vous a été supprim From the day: Du to the day: au Transform to activity: Transformer en échange + canceledBy: supprimé par Canceled by: supprimé par Calendar configuration: Gestion des rendez-vous @@ -36,4 +37,4 @@ crud: title: Liste des motifs d'annulation add_new: Ajouter un nouveau title_new: Nouveau motif d'annulation - title_edit: Modifier le motif d'annulation \ No newline at end of file + title_edit: Modifier le motif d'annulation diff --git a/src/Bundle/ChillCalendarBundle/translations/messages.nl.yml b/src/Bundle/ChillCalendarBundle/translations/messages.nl.yml new file mode 100644 index 000000000..c832138a8 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/translations/messages.nl.yml @@ -0,0 +1,28 @@ +Calendar: Afspraken +Calendar list: Lijst van afspraken +My calendar list: Mijn afspraken +There is no calendar items.: Er zijn geen afspraken +Remove calendar item: Verwijder afspraak +Are you sure you want to remove the calendar item?: Bent u zeker deze afspraak te willen verwijderen +Concerned groups: Betrokken partijen +Calendar data: Gegevens afspraak +Update calendar: Wijzig afspraak +main user concerned: Betrokken gebruiker +Main user: Hoofdgebruiker +Calendar item creation: Maak afspraak aan +start date: Begin afspraak +end date: Einde afspraak +cancel reason: reden van annulatie +status: Status van afspraak +calendar location: Locatie afspraak +calendar comment: Opmerkingen over afspraak +sendSMS: Verzenden sms +Send s m s: Sms verzenden? +Cancel reason: Reden van annulatie +Add a new calendar: Nieuwe afspraak toevoegen +"Success : calendar item updated!": "Afspraak bijgewerkt" +"Success : calendar item created!": "Afspraak aangemaakt" +The calendar item has been successfully removed.: De afspraak is verwijdert +From the day: Vanaf +to the day: tot +Transform to activity: In activiteit omzetten diff --git a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php index 56380ec74..f852e9f14 100644 --- a/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php +++ b/src/Bundle/ChillDocStoreBundle/Entity/StoredObject.php @@ -71,6 +71,12 @@ class StoredObject implements AsyncFileInterface, Document */ private array $keyInfos = []; + /** + * @ORM\Column(type="text", name="title") + * @Serializer\Groups({"read", "write"}) + */ + private string $title = ''; + /** * @ORM\Column(type="text", name="type") * @Serializer\Groups({"read", "write"}) @@ -127,6 +133,11 @@ class StoredObject implements AsyncFileInterface, Document return $this->getFilename(); } + public function getTitle() + { + return $this->title; + } + public function getType() { return $this->type; @@ -177,6 +188,13 @@ class StoredObject implements AsyncFileInterface, Document return $this; } + public function setTitle(?string $title) + { + $this->title = (string) $title; + + return $this; + } + public function setType(?string $type) { $this->type = (string) $type; diff --git a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php index 41dc73154..3df9f261f 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php @@ -12,6 +12,7 @@ declare(strict_types=1); namespace Chill\DocStoreBundle\Form; use Chill\DocStoreBundle\Entity\Document; +use Chill\DocStoreBundle\Entity\DocumentCategory; use Chill\DocStoreBundle\Entity\PersonDocument; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillTextareaType; @@ -63,7 +64,7 @@ class PersonDocumentType extends AbstractType ->add('date', ChillDateType::class) ->add('category', EntityType::class, [ 'placeholder' => 'Choose a document category', - 'class' => 'ChillDocStoreBundle:DocumentCategory', + 'class' => DocumentCategory::class, 'query_builder' => static function (EntityRepository $er) { return $er->createQueryBuilder('c') ->where('c.documentClass = :docClass') diff --git a/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php b/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php index f9cb645f7..aaf1e80da 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/StoredObjectType.php @@ -17,6 +17,7 @@ use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Extension\Core\Type\HiddenType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -40,6 +41,13 @@ class StoredObjectType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { + if (true === $options['has_title']) { + $builder + ->add('title', TextType::class, [ + 'label' => 'Title', + ]); + } + $builder ->add('filename', AsyncUploaderType::class) ->add('type', HiddenType::class) @@ -70,6 +78,10 @@ class StoredObjectType extends AbstractType { $resolver ->setDefault('data_class', StoredObject::class); + + $resolver + ->setDefault('has_title', false) + ->setAllowedTypes('has_title', ['bool']); } public function getBlockPrefix() diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/Form/fields.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/Form/fields.html.twig index 3ab0ff255..e971e2aa0 100644 --- a/src/Bundle/ChillDocStoreBundle/Resources/views/Form/fields.html.twig +++ b/src/Bundle/ChillDocStoreBundle/Resources/views/Form/fields.html.twig @@ -1,9 +1,10 @@ {% block stored_object_widget %} -
    tempUrlGenerator = $tempUrlGenerator; } - public function read(StoredObject $document): string + public function getLastModified(StoredObject $document): DateTimeInterface { - try { - $response = $this - ->client - ->request( - Request::METHOD_GET, - $this - ->tempUrlGenerator - ->generate( - Request::METHOD_GET, - $document->getFilename() - ) - ->url - ); - } catch (Throwable $e) { - throw StoredObjectManagerException::errorDuringHttpRequest($e); + if ($this->hasCache($document)) { + $response = $this->getResponseFromCache($document); + } else { + try { + $response = $this + ->client + ->request( + Request::METHOD_HEAD, + $this + ->tempUrlGenerator + ->generate( + Request::METHOD_PUT, + $document->getFilename() + ) + ->url + ); + } catch (TransportExceptionInterface $exception) { + throw StoredObjectManagerException::errorDuringHttpRequest($exception); + } } - if ($response->getStatusCode() !== Response::HTTP_OK) { - throw StoredObjectManagerException::invalidStatusCode($response->getStatusCode()); - } + return $this->extractLastModifiedFromResponse($response); + } + + public function read(StoredObject $document): string + { + $response = $this->getResponseFromCache($document); try { $data = $response->getContent(); @@ -90,6 +104,10 @@ final class StoredObjectManager implements StoredObjectManagerInterface public function write(StoredObject $document, string $clearContent): void { + if ($this->hasCache($document)) { + unset($this->inMemory[$document->getUuid()->toString()]); + } + $encryptedContent = $this->hasKeysAndIv($document) ? openssl_encrypt( $clearContent, @@ -126,6 +144,63 @@ final class StoredObjectManager implements StoredObjectManagerInterface } } + private function extractLastModifiedFromResponse(ResponseInterface $response): DateTimeImmutable + { + $lastModifiedString = (($response->getHeaders()['last-modified'] ?? [])[0] ?? ''); + + $date = DateTimeImmutable::createFromFormat( + DateTimeImmutable::RFC7231, + $lastModifiedString + ); + + if (false === $date) { + throw new RuntimeException('the date from remote storage could not be parsed: ' + . $lastModifiedString); + } + + return $date; + } + + private function fillCache(StoredObject $document): void + { + try { + $response = $this + ->client + ->request( + Request::METHOD_GET, + $this + ->tempUrlGenerator + ->generate( + Request::METHOD_GET, + $document->getFilename() + ) + ->url + ); + } catch (Throwable $e) { + throw StoredObjectManagerException::errorDuringHttpRequest($e); + } + + if ($response->getStatusCode() !== Response::HTTP_OK) { + throw StoredObjectManagerException::invalidStatusCode($response->getStatusCode()); + } + + $this->inMemory[$document->getUuid()->toString()] = $response; + } + + private function getResponseFromCache(StoredObject $document): ResponseInterface + { + if (!$this->hasCache($document)) { + $this->fillCache($document); + } + + return $this->inMemory[$document->getUuid()->toString()]; + } + + private function hasCache(StoredObject $document): bool + { + return array_key_exists($document->getUuid()->toString(), $this->inMemory); + } + private function hasKeysAndIv(StoredObject $storedObject): bool { return ([] !== $storedObject->getKeyInfos()) && ([] !== $storedObject->getIv()); diff --git a/src/Bundle/ChillDocStoreBundle/Service/StoredObjectManagerInterface.php b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectManagerInterface.php index 3cf67cb0c..ad40b571c 100644 --- a/src/Bundle/ChillDocStoreBundle/Service/StoredObjectManagerInterface.php +++ b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectManagerInterface.php @@ -12,9 +12,12 @@ declare(strict_types=1); namespace Chill\DocStoreBundle\Service; use Chill\DocStoreBundle\Entity\StoredObject; +use DateTimeInterface; interface StoredObjectManagerInterface { + public function getLastModified(StoredObject $document): DateTimeInterface; + /** * Get the content of a StoredObject. * diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20220525141646.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20220525141646.php new file mode 100644 index 000000000..71f251db7 --- /dev/null +++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20220525141646.php @@ -0,0 +1,36 @@ +addSql('ALTER TABLE chill_doc.stored_object DROP title'); + } + + public function getDescription(): string + { + return 'Add title on storedObject'; + } + + public function up(Schema $schema): void + { + $this->addSql('ALTER TABLE chill_doc.stored_object ADD title TEXT NOT NULL DEFAULT \'\' '); + } +} diff --git a/src/Bundle/ChillMainBundle/Controller/NotificationController.php b/src/Bundle/ChillMainBundle/Controller/NotificationController.php index d717f01eb..c6ecdd873 100644 --- a/src/Bundle/ChillMainBundle/Controller/NotificationController.php +++ b/src/Bundle/ChillMainBundle/Controller/NotificationController.php @@ -20,6 +20,7 @@ use Chill\MainBundle\Notification\Exception\NotificationHandlerNotFound; use Chill\MainBundle\Notification\NotificationHandlerManager; use Chill\MainBundle\Pagination\PaginatorFactory; use Chill\MainBundle\Repository\NotificationRepository; +use Chill\MainBundle\Repository\UserRepository; use Chill\MainBundle\Security\Authorization\NotificationVoter; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; @@ -29,6 +30,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Security\Core\Security; use Symfony\Contracts\Translation\TranslatorInterface; @@ -55,6 +57,8 @@ class NotificationController extends AbstractController private TranslatorInterface $translator; + private UserRepository $userRepository; + public function __construct( EntityManagerInterface $em, LoggerInterface $chillLogger, @@ -63,7 +67,8 @@ class NotificationController extends AbstractController NotificationRepository $notificationRepository, NotificationHandlerManager $notificationHandlerManager, PaginatorFactory $paginatorFactory, - TranslatorInterface $translator + TranslatorInterface $translator, + UserRepository $userRepository ) { $this->em = $em; $this->logger = $logger; @@ -73,6 +78,7 @@ class NotificationController extends AbstractController $this->notificationHandlerManager = $notificationHandlerManager; $this->paginatorFactory = $paginatorFactory; $this->translator = $translator; + $this->userRepository = $userRepository; } /** @@ -100,6 +106,15 @@ class NotificationController extends AbstractController ->setRelatedEntityId($request->query->getInt('entityId')) ->setSender($this->security->getUser()); + if ($request->query->has('tos')) { + foreach ($request->query->get('tos') as $toId) { + if (null === $to = $this->userRepository->find($toId)) { + throw new NotFoundHttpException("user with id {$toId} is not found"); + } + $notification->addAddressee($to); + } + } + try { $handler = $this->notificationHandlerManager->getHandler($notification); } catch (NotificationHandlerNotFound $e) { diff --git a/src/Bundle/ChillMainBundle/Controller/UserController.php b/src/Bundle/ChillMainBundle/Controller/UserController.php index 068bd9f73..b6ded6653 100644 --- a/src/Bundle/ChillMainBundle/Controller/UserController.php +++ b/src/Bundle/ChillMainBundle/Controller/UserController.php @@ -23,6 +23,7 @@ use Chill\MainBundle\Repository\UserRepository; use Chill\MainBundle\Templating\Listing\FilterOrderHelper; use Psr\Log\LoggerInterface; use RuntimeException; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormInterface; @@ -37,6 +38,8 @@ class UserController extends CRUDController { public const FORM_GROUP_CENTER_COMPOSED = 'composed_groupcenter'; + protected ParameterBagInterface $parameterBag; + private LoggerInterface $logger; private UserPasswordEncoderInterface $passwordEncoder; @@ -49,12 +52,14 @@ class UserController extends CRUDController LoggerInterface $chillLogger, ValidatorInterface $validator, UserPasswordEncoderInterface $passwordEncoder, - UserRepository $userRepository + UserRepository $userRepository, + ParameterBagInterface $parameterBag ) { $this->logger = $chillLogger; $this->userRepository = $userRepository; $this->validator = $validator; $this->passwordEncoder = $passwordEncoder; + $this->parameterBag = $parameterBag; } /** @@ -104,6 +109,7 @@ class UserController extends CRUDController return $this->render('@ChillMain/User/edit.html.twig', [ 'entity' => $user, + 'access_permissions_group_list' => $this->parameterBag->get('chill_main.access_permissions_group_list'), 'edit_form' => $this->createEditForm($user)->createView(), 'add_groupcenter_form' => $this->createAddLinkGroupCenterForm($user, $request)->createView(), 'delete_groupcenter_form' => array_map( @@ -153,6 +159,73 @@ class UserController extends CRUDController return $this->redirect($this->generateUrl('chill_crud_admin_user_edit', ['id' => $uid])); } + public function edit(Request $request, $id): Response + { + $action = 'edit'; + $entity = $this->getEntity($action, $id, $request); + + if (null === $entity) { + throw $this->createNotFoundException( + sprintf( + 'The %s with id %s is not found', + $this->getCrudName(), + $id + ) + ); + } + + $response = $this->checkACL($action, $entity); + + if ($response instanceof Response) { + return $response; + } + + $response = $this->onPostCheckACL($action, $request, $entity); + + if ($response instanceof Response) { + return $response; + } + + $form = $this->createFormFor($action, $entity); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $this->onFormValid($action, $entity, $form, $request); + $em = $this->getDoctrine()->getManager(); + + $this->onPreFlush($action, $entity, $form, $request); + $em->flush(); + $this->onPostFlush($action, $entity, $form, $request); + + $this->addFlash('success', $this->generateFormSuccessMessage($action, $entity)); + + $result = $this->onBeforeRedirectAfterSubmission($action, $entity, $form, $request); + + if ($result instanceof Response) { + return $result; + } + + return $this->redirectToRoute('chill_crud_' . $this->getCrudName() . '_index'); + } + + if ($form->isSubmitted()) { + $this->addFlash('error', $this->generateFormErrorMessage($action, $form)); + } + + $defaultTemplateParameters = [ + 'form' => $form->createView(), + 'entity' => $entity, + 'crud_name' => $this->getCrudName(), + 'access_permissions_group_list' => $this->parameterBag->get('chill_main.access_permissions_group_list'), + ]; + + return $this->render( + $this->getTemplateFor($action, $entity, $request), + $this->generateTemplateParameter($action, $entity, $request, $defaultTemplateParameters) + ); + } + /** * Displays a form to edit the user current location. * @@ -271,6 +344,11 @@ class UserController extends CRUDController ), ] ); + } elseif ('index' === $action) { + return array_merge( + ['allow_change_password' => $this->parameterBag->get('chill_main.access_user_change_password')], + $defaultTemplateParameters + ); } // default behaviour @@ -307,7 +385,7 @@ class UserController extends CRUDController protected function onPrePersist(string $action, $entity, FormInterface $form, Request $request) { // for "new", encode the password - if ('new' === $action) { + if ('new' === $action && $this->parameterBag->get('chill_main.access_user_change_password')) { $entity->setPassword($this->passwordEncoder ->encodePassword($entity, $form['plainPassword']->getData())); } diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php index 0611b9848..929bffe14 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/ChillMainExtension.php @@ -129,6 +129,16 @@ class ChillMainExtension extends Extension implements $config['access_global_history'] ); + $container->setParameter( + 'chill_main.access_user_change_password', + $config['access_user_change_password'] + ); + + $container->setParameter( + 'chill_main.access_permissions_group_list', + $config['access_permissions_group_list'] + ); + $container->setParameter( 'chill_main.routing.resources', $config['routing']['resources'] diff --git a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php index 7ced6aac6..a9b3ffec0 100644 --- a/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillMainBundle/DependencyInjection/Configuration.php @@ -116,6 +116,12 @@ class Configuration implements ConfigurationInterface ->booleanNode('access_global_history') ->defaultTrue() ->end() + ->booleanNode('access_user_change_password') + ->defaultTrue() + ->end() + ->booleanNode('access_permissions_group_list') + ->defaultTrue() + ->end() ->arrayNode('redis') ->children() ->scalarNode('host') diff --git a/src/Bundle/ChillMainBundle/Entity/Embeddable/PrivateCommentEmbeddable.php b/src/Bundle/ChillMainBundle/Entity/Embeddable/PrivateCommentEmbeddable.php new file mode 100644 index 000000000..00e0f29d7 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Entity/Embeddable/PrivateCommentEmbeddable.php @@ -0,0 +1,70 @@ + + */ + private array $comments = []; + + public function getCommentForUser(User $user): string + { + return $this->comments[$user->getId()] ?? ''; + } + + public function getComments(): ?array + { + return $this->comments; + } + + public function hasCommentForUser(User $user): bool + { + return array_key_exists($user->getId(), $this->comments) + && '' !== $this->comments[$user->getId()]; + } + + public function merge(PrivateCommentEmbeddable $newComment): self + { + $currentComments = null === $this->getComments() ? [] : $this->getComments(); + + $mergedComments = $newComment->getComments() + $currentComments; + + $this->setComments($mergedComments); + + return $this; + } + + public function setCommentForUser(User $user, ?string $content): self + { + $this->comments[$user->getId()] = trim((string) $content); + + return $this; + } + + public function setComments($comments) + { + $this->comments = $comments; + + return $this; + } +} diff --git a/src/Bundle/ChillMainBundle/Entity/User.php b/src/Bundle/ChillMainBundle/Entity/User.php index ad4888d58..80848e2cf 100644 --- a/src/Bundle/ChillMainBundle/Entity/User.php +++ b/src/Bundle/ChillMainBundle/Entity/User.php @@ -47,6 +47,11 @@ class User implements AdvancedUserInterface */ private array $attributes = []; + /** + * @ORM\ManyToOne(targetEntity=Civility::class) + */ + private ?Civility $civility = null; + /** * @ORM\ManyToOne(targetEntity=Location::class) */ @@ -184,6 +189,11 @@ class User implements AdvancedUserInterface return $this->attributes; } + public function getCivility(): ?Civility + { + return $this->civility; + } + public function getCurrentLocation(): ?Location { return $this->currentLocation; @@ -363,6 +373,13 @@ class User implements AdvancedUserInterface return $this; } + public function setCivility(?Civility $civility): User + { + $this->civility = $civility; + + return $this; + } + public function setCurrentLocation(?Location $currentLocation): User { $this->currentLocation = $currentLocation; diff --git a/src/Bundle/ChillMainBundle/Form/DataMapper/PrivateCommentDataMapper.php b/src/Bundle/ChillMainBundle/Form/DataMapper/PrivateCommentDataMapper.php new file mode 100644 index 000000000..2c03c59f1 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/DataMapper/PrivateCommentDataMapper.php @@ -0,0 +1,50 @@ +security = $security; + } + + public function mapDataToForms($viewData, $forms) + { + if (null === $viewData) { + return null; + } + + if (!$viewData instanceof PrivateCommentEmbeddable) { + throw new UnexpectedTypeException($viewData, PrivateCommentEmbeddable::class); + } + + $forms = iterator_to_array($forms); + + $forms['comments']->setData($viewData->getCommentForUser($this->security->getUser())); + } + + public function mapFormsToData($forms, &$viewData) + { + $forms = iterator_to_array($forms); + + $viewData->setCommentForUser($this->security->getUser(), $forms['comments']->getData()); + } +} diff --git a/src/Bundle/ChillMainBundle/Form/Type/PrivateCommentType.php b/src/Bundle/ChillMainBundle/Form/Type/PrivateCommentType.php new file mode 100644 index 000000000..d4c0d1611 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Form/Type/PrivateCommentType.php @@ -0,0 +1,62 @@ +user = $tokenStorage->getToken()->getUser(); + $this->dataMapper = $dataMapper; + } + + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('comments', ChillTextareaType::class, [ + 'disable_editor' => $options['disable_editor'], + 'label' => false, + ]) + ->setDataMapper($this->dataMapper); + } + + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['hideLabel'] = true; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver + ->setDefined('disable_editor') + ->setAllowedTypes('disable_editor', 'bool') + ->setDefaults([ + 'data_class' => PrivateCommentEmbeddable::class, + 'disable_editor' => false, + ]); + } +} diff --git a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php index 4bdf61604..e7ae27b3a 100644 --- a/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php +++ b/src/Bundle/ChillMainBundle/Form/UserCurrentLocationType.php @@ -43,6 +43,7 @@ class UserCurrentLocationType extends AbstractType }, 'placeholder' => 'Pick a location', 'required' => false, + 'attr' => ['class' => 'select2'], ]); } } diff --git a/src/Bundle/ChillMainBundle/Form/UserType.php b/src/Bundle/ChillMainBundle/Form/UserType.php index 6662d0bab..34c49bc38 100644 --- a/src/Bundle/ChillMainBundle/Form/UserType.php +++ b/src/Bundle/ChillMainBundle/Form/UserType.php @@ -15,9 +15,11 @@ 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\PickCivilityType; use Chill\MainBundle\Templating\TranslatableStringHelper; use Doctrine\ORM\EntityRepository; use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\EmailType; @@ -32,11 +34,16 @@ use Symfony\Component\Validator\Constraints\Regex; class UserType extends AbstractType { + protected ParameterBagInterface $parameterBag; + private TranslatableStringHelper $translatableStringHelper; - public function __construct(TranslatableStringHelper $translatableStringHelper) - { + public function __construct( + TranslatableStringHelper $translatableStringHelper, + ParameterBagInterface $parameterBag + ) { $this->translatableStringHelper = $translatableStringHelper; + $this->parameterBag = $parameterBag; } public function buildForm(FormBuilderInterface $builder, array $options) @@ -47,6 +54,11 @@ class UserType extends AbstractType 'required' => true, ]) ->add('label', TextType::class) + ->add('civility', PickCivilityType::class, [ + 'required' => false, + 'label' => 'Civility', + 'placeholder' => 'choose civility', + ]) ->add('mainCenter', EntityType::class, [ 'label' => 'Main center', 'required' => false, @@ -76,6 +88,12 @@ class UserType extends AbstractType 'choice_label' => function (UserJob $c) { return $this->translatableStringHelper->localize($c->getLabel()); }, + 'query_builder' => static function (EntityRepository $er) { + $qb = $er->createQueryBuilder('uj'); + $qb->where('uj.active = TRUE'); + + return $qb; + }, ]) ->add('mainLocation', EntityType::class, [ 'label' => 'Main location', @@ -94,7 +112,8 @@ class UserType extends AbstractType }, ]); - if ($options['is_creation']) { + // @phpstan-ignore-next-line + if ($options['is_creation'] && $this->parameterBag->get('chill_main.access_user_change_password')) { $builder->add('plainPassword', RepeatedType::class, [ 'mapped' => false, 'type' => PasswordType::class, diff --git a/src/Bundle/ChillMainBundle/Form/WorkflowStepType.php b/src/Bundle/ChillMainBundle/Form/WorkflowStepType.php index 9a2fd1b6c..b70e7a55b 100644 --- a/src/Bundle/ChillMainBundle/Form/WorkflowStepType.php +++ b/src/Bundle/ChillMainBundle/Form/WorkflowStepType.php @@ -109,6 +109,7 @@ class WorkflowStepType extends AbstractType 'multiple' => false, 'expanded' => true, 'choices' => $choices, + 'constraints' => [new NotNull()], 'choice_label' => function (Transition $transition) use ($workflow) { $meta = $workflow->getMetadataStore()->getTransitionMetadata($transition); @@ -208,24 +209,28 @@ class WorkflowStepType extends AbstractType $transition = $form['transition']->getData(); $toFinal = true; - foreach ($transition->getTos() as $to) { - $meta = $workflow->getMetadataStore()->getPlaceMetadata($to); - - if ( - !array_key_exists('isFinal', $meta) || false === $meta['isFinal'] - ) { - $toFinal = false; - } - } - - $destUsers = $form['future_dest_users']->getData(); - $destEmails = $form['future_dest_emails']->getData(); - - if (!$toFinal && [] === $destUsers && [] === $destEmails) { + if (null === $transition) { $context - ->buildViolation('workflow.You must add at least one dest user or email') - ->atPath('future_dest_users') - ->addViolation(); + ->buildViolation('workflow.You must select a next step, pick another decision if no next steps are available'); + } else { + foreach ($transition->getTos() as $to) { + $meta = $workflow->getMetadataStore()->getPlaceMetadata($to); + + if ( + !array_key_exists('isFinal', $meta) || false === $meta['isFinal'] + ) { + $toFinal = false; + } + } + $destUsers = $form['future_dest_users']->getData(); + $destEmails = $form['future_dest_emails']->getData(); + + if (!$toFinal && [] === $destUsers && [] === $destEmails) { + $context + ->buildViolation('workflow.You must add at least one dest user or email') + ->atPath('future_dest_users') + ->addViolation(); + } } } ), diff --git a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss index 99376088e..f8bd42442 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss +++ b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss @@ -298,6 +298,10 @@ table.table-bordered { } } +.private-quote { + border-left: 10px solid $pink; +} + /// meta-data div.createdBy, div.updatedBy, diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue index 9dd85fa73..292b0de16 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/AddAddress/CitySelection.vue @@ -121,7 +121,9 @@ export default { this.entity.selected.city = value; this.entity.selected.postcode.name = value.name; this.entity.selected.postcode.code = value.code; - this.entity.selected.postcode.coordinates = value.center.coordinates; + if (value.center) { + this.entity.selected.postcode.coordinates = value.center.coordinates; + } this.entity.selected.writeNew.postcode = false; this.$emit('getReferenceAddresses', value); this.focusOnAddress(); diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/ShowPane.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/ShowPane.vue index 4be073991..7f7b1b529 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/ShowPane.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/components/ShowPane.vue @@ -15,26 +15,69 @@ {{ $t('wait_redirection') }}
    -
    -

    - {{ $t('not_yet_address') }} -

    +
    +
    + +

    + {{ $t('not_yet_address') }} +

    + + + + +
    +
    + +
    +
    +
    + +
    +
    + +
    + + + +
    + +
    +
    -
    - - - +
    + + + +
    @@ -58,6 +101,9 @@ export default { 'useDatePane' ], emits: ['openEditPane'], + mounted() { + console.log('context', this.context) + }, computed: { address() { return this.entity.address; @@ -91,13 +137,35 @@ export default { forceRedirect() { return (!(this.context.backUrl === null || typeof this.context.backUrl === 'undefined')); }, - showMessageWhenNoAddress() { - let showMessageWhenNoAddress = this.options.showMessageWhenNoAddress === undefined ? this.defaultz.showMessageWhenNoAddress : this.options.showMessageWhenNoAddress; - if (showMessageWhenNoAddress === true || showMessageWhenNoAddress === false) { - return !this.context.edit && !this.address.id && showMessageWhenNoAddress; - } - return !this.context.edit && !this.address.id && this.options.stickyActions; - } + // showMessageWhenNoAddress() { + // let showMessageWhenNoAddress = this.options.showMessageWhenNoAddress === undefined ? this.defaultz.showMessageWhenNoAddress : this.options.showMessageWhenNoAddress; + // if (showMessageWhenNoAddress === true || showMessageWhenNoAddress === false) { + // return !this.context.edit && !this.address.id && showMessageWhenNoAddress; + // } + // return !this.context.edit && !this.address.id && this.options.stickyActions; + // } } }; + + diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyTasks.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyTasks.vue index 572b8f83a..77a2bd34c 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyTasks.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/HomepageWidget/MyTasks.vue @@ -1,5 +1,5 @@ - +
    {{ $t('my_tasks.description_alert') }}
    {{ $t('no_data') }} @@ -49,7 +50,7 @@ - +