Merge branch 'master' of gitlab.com:Chill-Projet/chill-bundles

This commit is contained in:
Mathieu Jaumotte 2022-03-01 16:14:00 +01:00
commit 7b17dc692e
19 changed files with 211 additions and 81 deletions

View File

@ -11,6 +11,7 @@ and this project adheres to
## Unreleased ## Unreleased
<!-- write down unreleased development here --> <!-- write down unreleased development here -->
* [parcours] Toggle emergency/intensity only by referrer (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/442)
* [docstore] Add an API entrypoint for StoredObject (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466) * [docstore] Add an API entrypoint for StoredObject (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466)
* [person] Add the possibility of uploading existing documents to AccPeriodWorkEvaluationDocument (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466) * [person] Add the possibility of uploading existing documents to AccPeriodWorkEvaluationDocument (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466)
* [person] Add title to AccPeriodWorkEvaluationDocument (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466) * [person] Add title to AccPeriodWorkEvaluationDocument (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/466)
@ -48,10 +49,9 @@ and this project adheres to
* [thirdparty_contact]: in search results the 'qualité' is displayed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/465) * [thirdparty_contact]: in search results the 'qualité' is displayed (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/465)
* [bug]: fix confidential toggle of address in thirdpartyrenderbox (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/460) * [bug]: fix confidential toggle of address in thirdpartyrenderbox (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/460)
## Test releases ## Test releases
* Creation of PickCivilityType, and implementation in PersonType and ThirdpartyType * Creation of PickCivilityType, and implementation in PersonType and ThirdpartyType
* [renderbox]: Fix display of address (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/462)
* [renderbox]: Add email in personRenderBox, this was not yet displayed.
### test release 2022-02-14 ### test release 2022-02-14
@ -68,6 +68,7 @@ and this project adheres to
* [parcours]: Mes parcours brouillon added to user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/440) * [parcours]: Mes parcours brouillon added to user menu (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/440)
* [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414) * [Documents]: List view adapted to display more information (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/414)
* [person]: style fix in parcours listing per person. (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/432) * [person]: style fix in parcours listing per person. (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/432)
* [parcours]: Only the referrer can toggle the intensity of the parcours (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/442)
* [household]: display address of current household (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/415) * [household]: display address of current household (https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/415)
* ajoute un ordre dans les localisation (api) * ajoute un ordre dans les localisation (api)
* [pick entity]: fix translations in modal (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/419) * [pick entity]: fix translations in modal (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/419)
@ -316,6 +317,7 @@ and this project adheres to
* add an endpoint for checking permissions. See https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/232 * add an endpoint for checking permissions. See https://gitlab.com/Chill-Projet/chill-bundles/-/merge_requests/232
* [activity] for a new activity: suggest and create on-the-fly locations based on the accompanying course location + location of the suggested parties * [activity] for a new activity: suggest and create on-the-fly locations based on the accompanying course location + location of the suggested parties
* [calendar] for a new rdv: suggest and create on-the-fly locations based on the accompanying course location + location of the suggested parties * [calendar] for a new rdv: suggest and create on-the-fly locations based on the accompanying course location + location of the suggested parties
* [period] Validation added when period is confidential and confirmed -> user cannot be null.
## Test releases ## Test releases

BIN
composer Executable file

Binary file not shown.

View File

@ -72,7 +72,7 @@ section.chill-entity {
} }
} }
p { p {
// display: inline-block; display: inline-block;
margin: 0 0 0 1.5em; margin: 0 0 0 1.5em;
text-indent: -1.5em; text-indent: -1.5em;

View File

@ -1,7 +1,7 @@
/** /**
* Generic api method that can be adapted to any fetch request * Generic api method that can be adapted to any fetch request
*/ */
const makeFetch = (method, url, body) => { const makeFetch = (method, url, body) => {
return fetch(url, { return fetch(url, {
method: method, method: method,
headers: { headers: {
@ -11,19 +11,20 @@
}) })
.then(response => { .then(response => {
if (response.ok) { if (response.ok) {
console.log('200 error')
return response.json(); return response.json();
} }
if (response.status === 422) { if (response.status === 422) {
console.log('422 error')
return response.json().then(response => { return response.json().then(response => {
throw ValidationException(response) throw ValidationException(response)
}); });
} }
if (response.status === 403) { if (response.status === 403) {
return response.json().then(() => { console.log('403 error')
throw AccessException(); throw AccessException(response);
});
} }
throw { throw {
@ -88,14 +89,13 @@ const ValidationException = (response) => {
error.violations = response.violations.map((violation) => `${violation.title}: ${violation.propertyPath}`); error.violations = response.violations.map((violation) => `${violation.title}: ${violation.propertyPath}`);
error.titles = response.violations.map((violation) => violation.title); error.titles = response.violations.map((violation) => violation.title);
error.propertyPaths = response.violations.map((violation) => violation.propertyPath); error.propertyPaths = response.violations.map((violation) => violation.propertyPath);
return error; return error;
} }
const AccessException = () => { const AccessException = (response) => {
const error = {}; const error = {};
error.name = 'AccessException'; error.name = 'AccessException';
error.violations = ['You are no longer permitted to perform this action']; error.violations = ['You are not allowed to perform this action'];
return error; return error;
} }

View File

@ -322,19 +322,39 @@ final class AccompanyingCourseApiController extends ApiController
/** /**
* @Route("/api/1.0/person/accompanying-course/{id}/confidential.json", name="chill_api_person_accompanying_period_confidential") * @Route("/api/1.0/person/accompanying-course/{id}/confidential.json", name="chill_api_person_accompanying_period_confidential")
* @ParamConverter("accompanyingCourse", options={"id": "id"}) * @ParamConverter("accompanyingCourse", options={"id": "id"})
*
* @param mixed $id
*/ */
public function toggleConfidentialApi(AccompanyingPeriod $accompanyingCourse, Request $request) public function toggleConfidentialApi(AccompanyingPeriod $accompanyingCourse, $id, Request $request)
{ {
if ($request->getMethod() === 'POST') { if ($request->getMethod() === 'POST') {
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::TOGGLE_CONFIDENTIAL, $accompanyingCourse); $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::TOGGLE_CONFIDENTIAL, $accompanyingCourse);
$accompanyingCourse->setConfidential(!$accompanyingCourse->isConfidential()); $accompanyingCourse->setConfidential(!$accompanyingCourse->isConfidential());
$this->getDoctrine()->getManager()->flush(); $this->getDoctrine()->getManager()->flush();
} }
return $this->json($accompanyingCourse->isConfidential(), Response::HTTP_OK, [], ['groups' => ['read']]); return $this->json($accompanyingCourse->isConfidential(), Response::HTTP_OK, [], ['groups' => ['read']]);
} }
/**
* @Route("/api/1.0/person/accompanying-course/{id}/intensity.json", name="chill_api_person_accompanying_period_intensity")
* @ParamConverter("accompanyingCourse", options={"id": "id"})
*/
public function toggleIntensityApi(AccompanyingPeriod $accompanyingCourse, Request $request)
{
if ($request->getMethod() === 'POST') {
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::TOGGLE_INTENSITY, $accompanyingCourse);
$status = $accompanyingCourse->getIntensity() === 'regular' ? 'occasional' : 'regular';
$accompanyingCourse->setIntensity($status);
$this->getDoctrine()->getManager()->flush();
}
return $this->json($accompanyingCourse->getIntensity(), Response::HTTP_OK, [], ['groups' => ['read']]);
}
public function workApi($id, Request $request, string $_format): Response public function workApi($id, Request $request, string $_format): Response
{ {
return $this->addRemoveSomething( return $this->addRemoveSomething(

View File

@ -395,16 +395,16 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE,
], ],
], ],
'confidential' => [ // 'confidential' => [
'methods' => [ // 'methods' => [
Request::METHOD_POST => true, // Request::METHOD_POST => true,
Request::METHOD_GET => true, // Request::METHOD_GET => true,
], // ],
'controller_action' => 'toggleConfidentialApi', // 'controller_action' => 'toggleConfidentialApi',
'roles' => [ // 'roles' => [
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::TOGGLE_CONFIDENTIAL, // Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::TOGGLE_CONFIDENTIAL,
], // ],
], // ],
'findAccompanyingPeriodsByPerson' => [ 'findAccompanyingPeriodsByPerson' => [
'path' => '/by-person/{person_id}.{_format}', 'path' => '/by-person/{person_id}.{_format}',
'controller_action' => 'getAccompanyingPeriodsByPerson', 'controller_action' => 'getAccompanyingPeriodsByPerson',

View File

@ -30,6 +30,8 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource;
use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory; use Chill\PersonBundle\Entity\AccompanyingPeriod\UserHistory;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\AccompanyingPeriodValidity; use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\AccompanyingPeriodValidity;
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ConfidentialCourseMustHaveReferrer;
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\LocationValidity;
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap; use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ParticipationOverlap;
use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ResourceDuplicateCheck; use Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod\ResourceDuplicateCheck;
use Chill\ThirdPartyBundle\Entity\ThirdParty; use Chill\ThirdPartyBundle\Entity\ThirdParty;
@ -62,12 +64,9 @@ use const SORT_REGULAR;
* "accompanying_period": AccompanyingPeriod::class * "accompanying_period": AccompanyingPeriod::class
* }) * })
* @Assert\GroupSequenceProvider * @Assert\GroupSequenceProvider
* @Assert\Expression(
* "this.isConfidential and this.getUser === NULL",
* message="If the accompanying course is confirmed and confidential, a referrer must remain assigned."
* )
*
* @AccompanyingPeriodValidity(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED}) * @AccompanyingPeriodValidity(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED})
* @LocationValidity(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED})
* @ConfidentialCourseMustHaveReferrer(groups={AccompanyingPeriod::STEP_DRAFT, AccompanyingPeriod::STEP_CONFIRMED})
*/ */
class AccompanyingPeriod implements class AccompanyingPeriod implements
GroupSequenceProviderInterface, GroupSequenceProviderInterface,
@ -201,7 +200,7 @@ class AccompanyingPeriod implements
/** /**
* @var string * @var string
* @ORM\Column(type="string", nullable=true) * @ORM\Column(type="string", nullable=true)
* @Groups({"read", "write"}) * @Groups({"read"})
* @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED}) * @Assert\NotBlank(groups={AccompanyingPeriod::STEP_CONFIRMED})
*/ */
private $intensity = self::INTENSITY_OCCASIONAL; private $intensity = self::INTENSITY_OCCASIONAL;
@ -1000,7 +999,7 @@ class AccompanyingPeriod implements
} }
/** /**
* Validation function. * Validation functions.
*/ */
public function isDateConsistent(ExecutionContextInterface $context) public function isDateConsistent(ExecutionContextInterface $context)
{ {

View File

@ -58,7 +58,7 @@ export default {
this.$store.dispatch('toggleIntensity', value) this.$store.dispatch('toggleIntensity', value)
.catch(({name, violations}) => { .catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') { if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation})); this.$toast.open({message: this.$t('Only the referrer can toggle the intensity of an accompanying course')})
} else { } else {
this.$toast.open({message: 'An error occurred'}) this.$toast.open({message: 'An error occurred'})
} }
@ -75,16 +75,11 @@ export default {
}); });
}, },
toggleConfidential() { toggleConfidential() {
this.$store.dispatch('fetchPermissions').then(() => { this.$store.dispatch('toggleConfidential')
if (!this.$store.getters.canTogglePermission) { .catch(({name, violations}) => {
this.$toast.open({message: "Seul le référent peut modifier la confidentialité"}); console.log(name);
return Promise.resolve();
} else {
return this.$store.dispatch('toggleConfidential', (!this.isConfidential));
}
}).catch(({name, violations}) => {
if (name === 'ValidationException' || name === 'AccessException') { if (name === 'ValidationException' || name === 'AccessException') {
violations.forEach((violation) => this.$toast.open({message: violation})); this.$toast.open({message: this.$t('Only the referrer can toggle the confidentiality of an accompanying course')})
} else { } else {
this.$toast.open({message: 'An error occurred'}) this.$toast.open({message: 'An error occurred'})
} }

View File

@ -46,6 +46,12 @@ if (root === 'banner') {
}) })
.use(store) .use(store)
.use(i18n) .use(i18n)
.use(VueToast, {
position: "bottom-right",
type: "error",
duration: 5000,
dismissible: true
})
.component('banner', Banner) .component('banner', Banner)
.mount('#banner-accompanying-course'); .mount('#banner-accompanying-course');
}); });

View File

@ -167,6 +167,8 @@ const appMessages = {
'Error while retriving users.': "Erreur du serveur lors du chargement de la liste des travailleurs.", 'Error while retriving users.': "Erreur du serveur lors du chargement de la liste des travailleurs.",
'Error while getting whoami.': "Erreur du serveur lors de la requête 'qui suis-je ?'", 'Error while getting whoami.': "Erreur du serveur lors de la requête 'qui suis-je ?'",
'Error while retriving origin\'s list.': "Erreur du serveur lors du chargement de la liste des origines de la demande.", 'Error while retriving origin\'s list.': "Erreur du serveur lors du chargement de la liste des origines de la demande.",
'Only the referrer can toggle the intensity of an accompanying course': "Seul le référent peut modifier l'intensité d'un parcours.",
'Only the referrer can toggle the confidentiality of an accompanying course': "Seul le référent peut modifier la confidentialité d'un parcours."
} }
}; };

View File

@ -432,12 +432,12 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
* Update accompanying course intensity/emergency/confidentiality * Update accompanying course intensity/emergency/confidentiality
*/ */
toggleIntensity({ commit }, payload) { toggleIntensity({ commit }, payload) {
const url = `/api/1.0/person/accompanying-course/${id}.json` const url = `/api/1.0/person/accompanying-course/${id}/intensity.json`
const body = { type: "accompanying_period", 'intensity': payload } const body = { type: "accompanying_period", 'intensity': payload }
return makeFetch('PATCH', url, body) return makeFetch('POST', url, body)
.then((response) => { .then((response) => {
commit('toggleIntensity', response.intensity); commit('toggleIntensity', response);
}) })
.catch((error) => { .catch((error) => {
@ -459,14 +459,18 @@ let initPromise = (root) => Promise.all([getScopesPromise(root), accompanyingCou
}) })
}, },
toggleConfidential({ commit }, payload) { toggleConfidential({ commit }, payload) {
const url = `/api/1.0/person/accompanying-course/${id}.json` const url = `/api/1.0/person/accompanying-course/${id}/confidential.json`
const body = { type: "accompanying_period", confidential: payload } const body = { type: "accompanying_period", confidential: payload }
return makeFetch('PATCH', url, body) console.log('url', url, 'body', body);
return makeFetch('POST', url, body)
.then((response) => { .then((response) => {
commit('toggleConfidential', response.confidential); console.log('response', response);
commit('toggleConfidential', response);
}) })
.catch((error) => { .catch((error) => {
console.log('error', error)
commit('catchError', error); commit('catchError', error);
throw error; throw error;
}) })

View File

@ -113,15 +113,6 @@
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p> <p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li> </li>
<li v-if="person.email">
<i class="fa fa-li fa-envelope-o"></i>
<a :href="'mailto: ' + person.email">{{ person.email }}</a>
</li>
<li v-else-if="options.addNoData">
<i class="fa fa-li fa-envelope-o"></i>
<p class="chill-no-data-statement">{{ $t('renderbox.no_data') }}</p>
</li>
<li v-if="person.centers !== undefined && person.centers.length > 0 && options.addCenter"> <li v-if="person.centers !== undefined && person.centers.length > 0 && options.addCenter">
<i class="fa fa-li fa-long-arrow-right"></i> <i class="fa fa-li fa-long-arrow-right"></i>
<template v-for="c in person.centers">{{ c.name }}</template> <template v-for="c in person.centers">{{ c.name }}</template>

View File

@ -33,6 +33,7 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
self::DELETE, self::DELETE,
self::FULL, self::FULL,
self::TOGGLE_CONFIDENTIAL_ALL, self::TOGGLE_CONFIDENTIAL_ALL,
self::TOGGLE_INTENSITY,
]; ];
public const CREATE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_CREATE'; public const CREATE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_CREATE';
@ -62,6 +63,11 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
*/ */
public const TOGGLE_CONFIDENTIAL_ALL = 'CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL_ALL'; public const TOGGLE_CONFIDENTIAL_ALL = 'CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL_ALL';
/**
* Right to toggle urgency of parcours.
*/
public const TOGGLE_INTENSITY = 'CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_INTENSITY';
private Security $security; private Security $security;
private VoterHelperInterface $voterHelper; private VoterHelperInterface $voterHelper;
@ -125,11 +131,20 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
} }
if (self::TOGGLE_CONFIDENTIAL === $attribute) { if (self::TOGGLE_CONFIDENTIAL === $attribute) {
if ($subject->getUser() === $token->getUser()) { if (null !== $subject->getUser() && ($subject->getUser() === $token->getUser())) {
return true; return true;
} }
return $this->voterHelper->voteOnAttribute(self::TOGGLE_CONFIDENTIAL_ALL, $subject, $token); return false;
// return $this->voterHelper->voteOnAttribute(self::TOGGLE_CONFIDENTIAL_ALL, $subject, $token);
}
if (self::TOGGLE_INTENSITY === $attribute) {
if (null !== $subject->getUser() && ($subject->getUser() === $token->getUser())) {
return true;
}
return false;
} }
// if confidential, only the referent can see it // if confidential, only the referent can see it

View File

@ -13,9 +13,7 @@ namespace Chill\PersonBundle\Tests\AccompanyingPeriod;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;
/** /**
* @internal * @internal
@ -42,7 +40,7 @@ final class AccompanyingPeriodConfidentialTest extends WebTestCase
]); ]);
} }
public function dataGenerateRandomAccompanyingCourse() public function testConfidentialInvalid()
{ {
// Disabling this dataprovider to avoid having errors while running the test. // Disabling this dataprovider to avoid having errors while running the test.
return yield from []; return yield from [];
@ -88,10 +86,7 @@ final class AccompanyingPeriodConfidentialTest extends WebTestCase
} }
} }
/** public function testConfidentialValid()
* @dataProvider dataGenerateRandomAccompanyingCourse
*/
public function testRemoveUserWhenConfidential(int $periodId)
{ {
$this->markTestIncomplete( $this->markTestIncomplete(
'Marked as incomplete because of a problem in the dataprovider, at line 81.' 'Marked as incomplete because of a problem in the dataprovider, at line 81.'
@ -101,8 +96,7 @@ final class AccompanyingPeriodConfidentialTest extends WebTestCase
->find($periodId); ->find($periodId);
$em = self::$kernel->getContainer()->get('doctrine.orm.entity_manager'); $em = self::$kernel->getContainer()->get('doctrine.orm.entity_manager');
$isConfidential = $period->isConfidential(); $violations = self::$validator->validate($period, null, ['confirmed']);
$step = $period->getStep();
$initialUser = $period->getUser(); $initialUser = $period->getUser();

View File

@ -15,6 +15,7 @@ use Chill\ActivityBundle\Repository\ActivityRepository;
use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\PersonBundle\Entity\SocialWork\SocialIssue;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender; use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedTypeException;
@ -28,10 +29,13 @@ class AccompanyingPeriodValidityValidator extends ConstraintValidator
private SocialIssueRender $socialIssueRender; private SocialIssueRender $socialIssueRender;
public function __construct(ActivityRepository $activityRepository, SocialIssueRender $socialIssueRender) private TokenStorageInterface $token;
public function __construct(ActivityRepository $activityRepository, SocialIssueRender $socialIssueRender, TokenStorageInterface $token)
{ {
$this->activityRepository = $activityRepository; $this->activityRepository = $activityRepository;
$this->socialIssueRender = $socialIssueRender; $this->socialIssueRender = $socialIssueRender;
$this->token = $token;
} }
public function validate($period, Constraint $constraint) public function validate($period, Constraint $constraint)
@ -44,6 +48,7 @@ class AccompanyingPeriodValidityValidator extends ConstraintValidator
throw new UnexpectedValueException($period, AccompanyingPeriod::class); throw new UnexpectedValueException($period, AccompanyingPeriod::class);
} }
/** Check if a social issue can be deleted (is not linked to an action or activity within the parcours) */
$socialIssues = []; $socialIssues = [];
$activities = $this->activityRepository->findBy(['accompanyingPeriod' => $period]); $activities = $this->activityRepository->findBy(['accompanyingPeriod' => $period]);

View File

@ -0,0 +1,27 @@
<?php
/**
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod;
use Symfony\Component\Validator\Constraint;
/**
* @Annotation
*/
class ConfidentialCourseMustHaveReferrer extends Constraint
{
public string $message = 'A confidential parcours must have a referrer';
public function getTargets()
{
return [self::CLASS_CONSTRAINT];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
class ConfidentialCourseMustHaveReferrerValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if (!$value instanceof AccompanyingPeriod) {
throw new UnexpectedTypeException($value, AccompanyingPeriod::class);
}
if (!$constraint instanceof ConfidentialCourseMustHaveReferrer) {
throw new UnexpectedTypeException($constraint, ConfidentialCourseMustHaveReferrer::class);
}
if ($value->isConfidential() && null === $value->getUser()) {
$this->context
->buildViolation($constraint->message)
->atPath('user')
->addViolation();
}
}
}

View File

@ -1177,6 +1177,44 @@ paths:
422: 422:
description: "object with validation errors" description: "object with validation errors"
/1.0/person/accompanying-course/{id}/intensity.json:
post:
tags:
- person
summary: "Toggle intensity status of accompanying course"
parameters:
- name: id
in: path
required: true
description: The accompanying period's id
schema:
type: integer
format: integer
minimum: 1
requestBody:
description: "Intensity toggle"
required: true
content:
application/json:
schema:
type: object
properties:
type:
type: string
enum:
- "accompanying_period"
intensity:
type: string
responses:
401:
description: "Unauthorized"
404:
description: "Not found"
200:
description: "OK"
422:
description: "object with validation errors"
/1.0/person/accompanying-course/by-person/{person_id}.json: /1.0/person/accompanying-course/by-person/{person_id}.json:
get: get:
tags: tags:

View File

@ -20,6 +20,7 @@ Two addresses has the same validFrom date: La date de validité est identique à
The firstname cannot be empty: Le prénom ne peut pas être vide The firstname cannot be empty: Le prénom ne peut pas être vide
The lastname cannot be empty: Le nom de famille ne peut pas être vide The lastname cannot be empty: Le nom de famille ne peut pas être vide
The gender must be set: Le genre doit être renseigné The gender must be set: Le genre doit être renseigné
You are not allowed to perform this action: Vous n'avez pas le droit de changer cette valeur.
#export list #export list
You must select at least one element: Vous devez sélectionner au moins un élément You must select at least one element: Vous devez sélectionner au moins un élément
@ -51,6 +52,8 @@ household_membership:
A course must contains at least one social issue: 'Un parcours doit être associé à au moins une problématique sociale' A course must contains at least one social issue: 'Un parcours doit être associé à au moins une problématique sociale'
A course must be associated to at least one scope: 'Un parcours doit être associé à au moins un service' A course must be associated to at least one scope: 'Un parcours doit être associé à au moins un service'
The social %name% issue cannot be deleted because it is associated with an activity or an action: 'La problématique sociale "%name%" ne peut pas être supprimée car elle est associée à une activité ou une action' The social %name% issue cannot be deleted because it is associated with an activity or an action: 'La problématique sociale "%name%" ne peut pas être supprimée car elle est associée à une activité ou une action'
A confidential parcours must have a referrer: 'Un parcours confidentiel doit avoir un référent'
Only the referrer can change the confidentiality of a parcours: 'Seul le référent peut modifier la confidentialité'
# resource # resource
You must associate at least one entity: Associez un usager, un tiers ou indiquez une description libre You must associate at least one entity: Associez un usager, un tiers ou indiquez une description libre