mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Merge branch 'master' into 295_resume_retouches
This commit is contained in:
commit
aca1d1f9e9
12
CHANGELOG.md
12
CHANGELOG.md
@ -11,6 +11,10 @@ and this project adheres to
|
|||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
<!-- write down unreleased development here -->
|
<!-- write down unreleased development here -->
|
||||||
|
* [person] suggest entities (person | thirdparty) when creating/editing the accompanying course (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/119)
|
||||||
|
* [activity] add custom validation on the Activity class, based on what is required from the ActivityType (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/188)
|
||||||
|
* [main] translate multiselect messages when selecting/creating address
|
||||||
|
* [main] set the coordinates of the city when creating a new address OR choosing "pas d'adresse complète"
|
||||||
* Use the user.label in accompanying course banner, instead of username;
|
* Use the user.label in accompanying course banner, instead of username;
|
||||||
* fix: show validation message when closing accompanying course;
|
* fix: show validation message when closing accompanying course;
|
||||||
* [thirdparty] link from modal to thirdparty detail page fixed (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/228)
|
* [thirdparty] link from modal to thirdparty detail page fixed (https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/228)
|
||||||
@ -23,6 +27,14 @@ and this project adheres to
|
|||||||
* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/101
|
* https://gitlab.com/champs-libres/departement-de-la-vendee/accent-suivi-developpement/-/issues/101
|
||||||
* https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/295
|
* https://gitlab.com/champs-libres/departement-de-la-vendee/chill/-/issues/295
|
||||||
* [activity/calendar] on show page, concerned groups of persons table adapt itself to isVisibles options
|
* [activity/calendar] on show page, concerned groups of persons table adapt itself to isVisibles options
|
||||||
|
* [activity] remove the "plus" button in activity list
|
||||||
|
* [activity] check ACL on activity list in person context
|
||||||
|
* [list for accompanying course in person] filter list using ACL
|
||||||
|
* [validation] toasts are displayed for errors when modifying accompanying course (generalization required).
|
||||||
|
* [period] only the user can enable confidentiality
|
||||||
|
* 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
|
||||||
|
* [calendar] for a new rdv: suggest and create on-the-fly locations based on the accompanying course location + location of the suggested parties
|
||||||
|
|
||||||
## Test releases
|
## Test releases
|
||||||
|
|
||||||
|
@ -70,11 +70,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php
|
path: src/Bundle/ChillPersonBundle/Serializer/Normalizer/MembersEditorNormalizer.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Undefined variable\\: \\$value$#"
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Validator/Constraints/AccompanyingPeriod/LocationValidityValidator.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Undefined variable\\: \\$choiceSlug$#"
|
message: "#^Undefined variable\\: \\$choiceSlug$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
@ -1330,14 +1330,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php
|
path: src/Bundle/ChillPersonBundle/Search/SimilarPersonMatcher.php
|
||||||
|
|
||||||
-
|
|
||||||
message:
|
|
||||||
"""
|
|
||||||
#^Parameter \\$centerResolverDispatcher of method Chill\\\\PersonBundle\\\\Validator\\\\Constraints\\\\Person\\\\PersonHasCenterValidator\\:\\:__construct\\(\\) has typehint with deprecated interface Chill\\\\MainBundle\\\\Security\\\\Resolver\\\\CenterResolverDispatcherInterface\\:
|
|
||||||
Use CenterResolverManager and its interface CenterResolverManagerInterface$#
|
|
||||||
"""
|
|
||||||
count: 1
|
|
||||||
path: src/Bundle/ChillPersonBundle/Validator/Constraints/Person/PersonHasCenterValidator.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message:
|
message:
|
||||||
|
@ -105,18 +105,19 @@ final class ActivityController extends AbstractController
|
|||||||
|
|
||||||
[$person, $accompanyingPeriod] = $this->getEntity($request);
|
[$person, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
|
||||||
$view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig';
|
|
||||||
} elseif ($person instanceof Person) {
|
|
||||||
$view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig';
|
|
||||||
}
|
|
||||||
|
|
||||||
$activity = $this->activityRepository->find($id);
|
$activity = $this->activityRepository->find($id);
|
||||||
|
|
||||||
if (!$activity) {
|
if (!$activity) {
|
||||||
throw $this->createNotFoundException('Unable to find Activity entity.');
|
throw $this->createNotFoundException('Unable to find Activity entity.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($activity->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
|
||||||
|
$view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig';
|
||||||
|
$accompanyingPeriod = $activity->getAccompanyingPeriod();
|
||||||
|
} else {
|
||||||
|
$view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig';
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
|
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity);
|
||||||
|
|
||||||
@ -137,7 +138,7 @@ final class ActivityController extends AbstractController
|
|||||||
static fn (ActivityReason $ar): int => $ar->getId()
|
static fn (ActivityReason $ar): int => $ar->getId()
|
||||||
)
|
)
|
||||||
->toArray(),
|
->toArray(),
|
||||||
'type_id' => $activity->getType()->getId(),
|
'type_id' => $activity->getActivityType()->getId(),
|
||||||
'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null,
|
'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null,
|
||||||
'date' => $activity->getDate()->format('Y-m-d'),
|
'date' => $activity->getDate()->format('Y-m-d'),
|
||||||
'attendee' => $activity->getAttendee(),
|
'attendee' => $activity->getAttendee(),
|
||||||
@ -176,25 +177,25 @@ final class ActivityController extends AbstractController
|
|||||||
|
|
||||||
[$person, $accompanyingPeriod] = $this->getEntity($request);
|
[$person, $accompanyingPeriod] = $this->getEntity($request);
|
||||||
|
|
||||||
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
|
||||||
$view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig';
|
|
||||||
} elseif ($person instanceof Person) {
|
|
||||||
$view = 'ChillActivityBundle:Activity:editPerson.html.twig';
|
|
||||||
}
|
|
||||||
|
|
||||||
$entity = $this->activityRepository->find($id);
|
$entity = $this->activityRepository->find($id);
|
||||||
|
|
||||||
if (null === $entity) {
|
if (null === $entity) {
|
||||||
throw $this->createNotFoundException('Unable to find Activity entity.');
|
throw $this->createNotFoundException('Unable to find Activity entity.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($entity->getAccompanyingPeriod() instanceof AccompanyingPeriod) {
|
||||||
|
$view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig';
|
||||||
|
$accompanyingPeriod = $entity->getAccompanyingPeriod();
|
||||||
|
} else {
|
||||||
|
$view = 'ChillActivityBundle:Activity:editPerson.html.twig';
|
||||||
|
}
|
||||||
// TODO
|
// TODO
|
||||||
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
|
// $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity);
|
||||||
|
|
||||||
$form = $this->createForm(ActivityType::class, $entity, [
|
$form = $this->createForm(ActivityType::class, $entity, [
|
||||||
'center' => $entity->getCenter(),
|
'center' => $entity->getCenter(),
|
||||||
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
|
'role' => new Role('CHILL_ACTIVITY_UPDATE'),
|
||||||
'activityType' => $entity->getType(),
|
'activityType' => $entity->getActivityType(),
|
||||||
'accompanyingPeriod' => $accompanyingPeriod,
|
'accompanyingPeriod' => $accompanyingPeriod,
|
||||||
])->handleRequest($request);
|
])->handleRequest($request);
|
||||||
|
|
||||||
@ -327,7 +328,7 @@ final class ActivityController extends AbstractController
|
|||||||
$entity->setAccompanyingPeriod($accompanyingPeriod);
|
$entity->setAccompanyingPeriod($accompanyingPeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
$entity->setType($activityType);
|
$entity->setActivityType($activityType);
|
||||||
$entity->setDate(new DateTime('now'));
|
$entity->setDate(new DateTime('now'));
|
||||||
|
|
||||||
if ($request->query->has('activityData')) {
|
if ($request->query->has('activityData')) {
|
||||||
@ -385,7 +386,7 @@ final class ActivityController extends AbstractController
|
|||||||
$form = $this->createForm(ActivityType::class, $entity, [
|
$form = $this->createForm(ActivityType::class, $entity, [
|
||||||
'center' => $entity->getCenter(),
|
'center' => $entity->getCenter(),
|
||||||
'role' => new Role('CHILL_ACTIVITY_CREATE'),
|
'role' => new Role('CHILL_ACTIVITY_CREATE'),
|
||||||
'activityType' => $entity->getType(),
|
'activityType' => $entity->getActivityType(),
|
||||||
'accompanyingPeriod' => $accompanyingPeriod,
|
'accompanyingPeriod' => $accompanyingPeriod,
|
||||||
])->handleRequest($request);
|
])->handleRequest($request);
|
||||||
|
|
||||||
@ -408,7 +409,7 @@ final class ActivityController extends AbstractController
|
|||||||
|
|
||||||
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
|
$activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']);
|
||||||
|
|
||||||
$defaultLocationId = $this->getUser()->getCurrentLocation()->getId();
|
$defaultLocation = $this->getUser()->getCurrentLocation();
|
||||||
|
|
||||||
return $this->render($view, [
|
return $this->render($view, [
|
||||||
'person' => $person,
|
'person' => $person,
|
||||||
@ -416,7 +417,7 @@ final class ActivityController extends AbstractController
|
|||||||
'entity' => $entity,
|
'entity' => $entity,
|
||||||
'form' => $form->createView(),
|
'form' => $form->createView(),
|
||||||
'activity_json' => $activity_array,
|
'activity_json' => $activity_array,
|
||||||
'default_location_id' => $defaultLocationId,
|
'default_location' => $defaultLocation,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ class AdminActivityTypeController extends CRUDController
|
|||||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||||
{
|
{
|
||||||
/** @var \Doctrine\ORM\QueryBuilder $query */
|
/** @var \Doctrine\ORM\QueryBuilder $query */
|
||||||
return $query->orderBy('e.ordering', 'ASC');
|
return $query->orderBy('e.ordering', 'ASC')
|
||||||
|
->addOrderBy('e.id', 'ASC');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace Chill\ActivityBundle\Entity;
|
namespace Chill\ActivityBundle\Entity;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Validator\Constraints as ActivityValidator;
|
||||||
use Chill\DocStoreBundle\Entity\Document;
|
use Chill\DocStoreBundle\Entity\Document;
|
||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\Center;
|
||||||
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
use Chill\MainBundle\Entity\Embeddable\CommentEmbeddable;
|
||||||
@ -41,6 +42,7 @@ use Symfony\Component\Serializer\Annotation\SerializedName;
|
|||||||
* @DiscriminatorMap(typeProperty="type", mapping={
|
* @DiscriminatorMap(typeProperty="type", mapping={
|
||||||
* "activity": Activity::class
|
* "activity": Activity::class
|
||||||
* })
|
* })
|
||||||
|
* @ActivityValidator\ActivityValidity
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -202,7 +204,9 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer
|
|||||||
public function addPerson(?Person $person): self
|
public function addPerson(?Person $person): self
|
||||||
{
|
{
|
||||||
if (null !== $person) {
|
if (null !== $person) {
|
||||||
$this->persons[] = $person;
|
if (!$this->persons->contains($person)) {
|
||||||
|
$this->persons[] = $person;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -236,7 +240,9 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer
|
|||||||
public function addThirdParty(?ThirdParty $thirdParty): self
|
public function addThirdParty(?ThirdParty $thirdParty): self
|
||||||
{
|
{
|
||||||
if (null !== $thirdParty) {
|
if (null !== $thirdParty) {
|
||||||
$this->thirdParties[] = $thirdParty;
|
if (!$this->thirdParties->contains($thirdParty)) {
|
||||||
|
$this->thirdParties[] = $thirdParty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
@ -245,7 +251,9 @@ class Activity implements HasCenterInterface, HasScopeInterface, AccompanyingPer
|
|||||||
public function addUser(?User $user): self
|
public function addUser(?User $user): self
|
||||||
{
|
{
|
||||||
if (null !== $user) {
|
if (null !== $user) {
|
||||||
$this->users[] = $user;
|
if (!$this->users->contains($user)) {
|
||||||
|
$this->users[] = $user;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -12,6 +12,7 @@ namespace Chill\ActivityBundle\Entity;
|
|||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ActivityType.
|
* Class ActivityType.
|
||||||
@ -29,11 +30,13 @@ class ActivityType
|
|||||||
public const FIELD_REQUIRED = 2;
|
public const FIELD_REQUIRED = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated not in use
|
||||||
* @ORM\Column(type="string", nullable=false, options={"default": ""})
|
* @ORM\Column(type="string", nullable=false, options={"default": ""})
|
||||||
*/
|
*/
|
||||||
private string $accompanyingPeriodLabel = '';
|
private string $accompanyingPeriodLabel = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @deprecated not in use
|
||||||
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
||||||
*/
|
*/
|
||||||
private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE;
|
private int $accompanyingPeriodVisible = self::FIELD_INVISIBLE;
|
||||||
@ -195,16 +198,21 @@ class ActivityType
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
||||||
|
* @Assert\EqualTo(propertyPath="socialIssuesVisible", message="This parameter must be equal to social issue parameter")
|
||||||
*/
|
*/
|
||||||
private int $socialActionsVisible = self::FIELD_INVISIBLE;
|
private int $socialActionsVisible = self::FIELD_INVISIBLE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="string", nullable=false, options={"default": ""})
|
* @ORM\Column(type="string", nullable=false, options={"default": ""})
|
||||||
|
*
|
||||||
|
* @deprecated not in use
|
||||||
*/
|
*/
|
||||||
private string $socialDataLabel = '';
|
private string $socialDataLabel = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
* @ORM\Column(type="smallint", nullable=false, options={"default": 1})
|
||||||
|
*
|
||||||
|
* @deprecated not in use
|
||||||
*/
|
*/
|
||||||
private int $socialDataVisible = self::FIELD_INVISIBLE;
|
private int $socialDataVisible = self::FIELD_INVISIBLE;
|
||||||
|
|
||||||
@ -260,16 +268,6 @@ class ActivityType
|
|||||||
*/
|
*/
|
||||||
private int $userVisible = self::FIELD_REQUIRED;
|
private int $userVisible = self::FIELD_REQUIRED;
|
||||||
|
|
||||||
public function getAccompanyingPeriodLabel(): string
|
|
||||||
{
|
|
||||||
return $this->accompanyingPeriodLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getAccompanyingPeriodVisible(): int
|
|
||||||
{
|
|
||||||
return $this->accompanyingPeriodVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get active
|
* Get active
|
||||||
* return true if the type is active.
|
* return true if the type is active.
|
||||||
@ -446,16 +444,6 @@ class ActivityType
|
|||||||
return $this->socialActionsVisible;
|
return $this->socialActionsVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSocialDataLabel(): string
|
|
||||||
{
|
|
||||||
return $this->socialDataLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSocialDataVisible(): int
|
|
||||||
{
|
|
||||||
return $this->socialDataVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSocialIssuesLabel(): ?string
|
public function getSocialIssuesLabel(): ?string
|
||||||
{
|
{
|
||||||
return $this->socialIssuesLabel;
|
return $this->socialIssuesLabel;
|
||||||
@ -537,20 +525,6 @@ class ActivityType
|
|||||||
return self::FIELD_INVISIBLE !== $this->{$property};
|
return self::FIELD_INVISIBLE !== $this->{$property};
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setAccompanyingPeriodLabel(string $accompanyingPeriodLabel): self
|
|
||||||
{
|
|
||||||
$this->accompanyingPeriodLabel = $accompanyingPeriodLabel;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setAccompanyingPeriodVisible(int $accompanyingPeriodVisible): self
|
|
||||||
{
|
|
||||||
$this->accompanyingPeriodVisible = $accompanyingPeriodVisible;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set active
|
* Set active
|
||||||
* set to true if the type is active.
|
* set to true if the type is active.
|
||||||
@ -768,20 +742,6 @@ class ActivityType
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setSocialDataLabel(string $socialDataLabel): self
|
|
||||||
{
|
|
||||||
$this->socialDataLabel = $socialDataLabel;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setSocialDataVisible(int $socialDataVisible): self
|
|
||||||
{
|
|
||||||
$this->socialDataVisible = $socialDataVisible;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setSocialIssuesLabel(string $socialIssuesLabel): self
|
public function setSocialIssuesLabel(string $socialIssuesLabel): self
|
||||||
{
|
{
|
||||||
$this->socialIssuesLabel = $socialIssuesLabel;
|
$this->socialIssuesLabel = $socialIssuesLabel;
|
||||||
|
@ -56,7 +56,7 @@ class ActivityTypeType extends AbstractType
|
|||||||
'persons', 'user', 'date', 'place', 'persons',
|
'persons', 'user', 'date', 'place', 'persons',
|
||||||
'thirdParties', 'durationTime', 'travelTime', 'attendee',
|
'thirdParties', 'durationTime', 'travelTime', 'attendee',
|
||||||
'reasons', 'comment', 'sentReceived', 'documents',
|
'reasons', 'comment', 'sentReceived', 'documents',
|
||||||
'emergency', 'accompanyingPeriod', 'socialData', 'users',
|
'emergency', 'socialIssues', 'socialActions', 'users',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<concerned-groups></concerned-groups>
|
<concerned-groups v-if="hasPerson"></concerned-groups>
|
||||||
<social-issues-acc></social-issues-acc>
|
<social-issues-acc v-if="hasSocialIssues"></social-issues-acc>
|
||||||
<location></location>
|
<location v-if="hasLocation"></location>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -11,6 +11,7 @@ import Location from './components/Location.vue';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
|
props: ['hasSocialIssues', 'hasLocation', 'hasPerson'],
|
||||||
components: {
|
components: {
|
||||||
ConcernedGroups,
|
ConcernedGroups,
|
||||||
SocialIssuesAcc,
|
SocialIssuesAcc,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { getSocialIssues } from 'ChillPersonAssets/vuejs/AccompanyingCourse/api.js';
|
import { getSocialIssues } from 'ChillPersonAssets/vuejs/AccompanyingCourse/api.js';
|
||||||
|
import { fetchResults } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load socialActions by socialIssue (id)
|
* Load socialActions by socialIssue (id)
|
||||||
@ -12,33 +13,20 @@ const getSocialActionByIssue = (id) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
const getLocations = () => fetchResults('/api/1.0/main/location.json');
|
||||||
* Load Locations
|
|
||||||
*/
|
const getLocationTypes = () => fetchResults('/api/1.0/main/location-type.json');
|
||||||
const getLocations = () => {
|
|
||||||
const url = `/api/1.0/main/location.json`;
|
|
||||||
return fetch(url)
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw Error('Error with request resource response');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load Location Types
|
* Load Location Type by defaultFor
|
||||||
|
* @param {string} entity - can be "person" or "thirdparty"
|
||||||
*/
|
*/
|
||||||
const getLocationTypes = () => {
|
const getLocationTypeByDefaultFor = (entity) => {
|
||||||
const url = `/api/1.0/main/location-type.json`;
|
return getLocationTypes().then(results =>
|
||||||
return fetch(url)
|
results.filter(t => t.defaultFor === entity)[0]
|
||||||
.then(response => {
|
);
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw Error('Error with request resource response');
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Post a Location
|
|
||||||
*/
|
|
||||||
const postLocation = (body) => {
|
const postLocation = (body) => {
|
||||||
const url = `/api/1.0/main/location.json`;
|
const url = `/api/1.0/main/location.json`;
|
||||||
return fetch(url, {
|
return fetch(url, {
|
||||||
@ -59,5 +47,6 @@ export {
|
|||||||
getSocialActionByIssue,
|
getSocialActionByIssue,
|
||||||
getLocations,
|
getLocations,
|
||||||
getLocationTypes,
|
getLocationTypes,
|
||||||
|
getLocationTypeByDefaultFor,
|
||||||
postLocation
|
postLocation
|
||||||
};
|
};
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
<teleport to="#location">
|
<teleport to="#location">
|
||||||
<div class="mb-3 row">
|
<div class="mb-3 row">
|
||||||
<label class="col-form-label col-sm-4">
|
<label class="col-form-label col-sm-4">
|
||||||
{{ $t('activity.location') }}
|
{{ $t("activity.location") }}
|
||||||
</label>
|
</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
|
|
||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
name="selectLocation"
|
name="selectLocation"
|
||||||
id="selectLocation"
|
id="selectLocation"
|
||||||
@ -17,7 +16,10 @@
|
|||||||
:placeholder="$t('activity.choose_location')"
|
:placeholder="$t('activity.choose_location')"
|
||||||
:custom-label="customLabel"
|
:custom-label="customLabel"
|
||||||
:options="locations"
|
:options="locations"
|
||||||
v-model="location">
|
group-values="locations"
|
||||||
|
group-label="locationGroup"
|
||||||
|
v-model="location"
|
||||||
|
>
|
||||||
</VueMultiselect>
|
</VueMultiselect>
|
||||||
|
|
||||||
<new-location v-bind:locations="locations"></new-location>
|
<new-location v-bind:locations="locations"></new-location>
|
||||||
@ -27,49 +29,146 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from "vuex";
|
import { mapState, mapGetters } from "vuex";
|
||||||
import VueMultiselect from 'vue-multiselect';
|
import VueMultiselect from "vue-multiselect";
|
||||||
import NewLocation from './Location/NewLocation.vue';
|
import NewLocation from "./Location/NewLocation.vue";
|
||||||
import { getLocations } from '../api.js';
|
import { getLocations, getLocationTypeByDefaultFor } from "../api.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Location",
|
name: "Location",
|
||||||
components: {
|
components: {
|
||||||
NewLocation,
|
NewLocation,
|
||||||
VueMultiselect
|
VueMultiselect,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
locations: []
|
locations: [],
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['activity']),
|
...mapState(["activity"]),
|
||||||
|
...mapGetters(["suggestedEntities"]),
|
||||||
location: {
|
location: {
|
||||||
get() {
|
get() {
|
||||||
return this.activity.location;
|
return this.activity.location;
|
||||||
},
|
},
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$store.dispatch('updateLocation', value);
|
this.$store.dispatch("updateLocation", value);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
getLocations().then(response => new Promise(resolve => {
|
getLocations().then(
|
||||||
console.log('getLocations', response);
|
(results) => {
|
||||||
this.locations = response.results;
|
getLocationTypeByDefaultFor('person').then(
|
||||||
if (window.default_location_id) {
|
(personLocationType) => {
|
||||||
let location = this.locations.filter(l => l.id === window.default_location_id);
|
if (personLocationType) {
|
||||||
this.$store.dispatch('updateLocation', location);
|
const personLocation = this.makeAccompanyingPeriodLocation(personLocationType);
|
||||||
}
|
const concernedPersonsLocation =
|
||||||
resolve();
|
this.makeConcernedPersonsLocation(personLocationType);
|
||||||
}))
|
getLocationTypeByDefaultFor('thirdparty').then(
|
||||||
|
thirdpartyLocationType => {
|
||||||
|
const concernedThirdPartiesLocation =
|
||||||
|
this.makeConcernedThirdPartiesLocation(thirdpartyLocationType);
|
||||||
|
this.locations = [
|
||||||
|
{
|
||||||
|
locationGroup: 'Localisation du parcours',
|
||||||
|
locations: [personLocation]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
locationGroup: 'Parties concernées',
|
||||||
|
locations: [...concernedPersonsLocation, ...concernedThirdPartiesLocation]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
locationGroup: 'Autres localisations',
|
||||||
|
locations: results
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this.locations = [
|
||||||
|
{
|
||||||
|
locationGroup: 'Localisations',
|
||||||
|
locations: response.results
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (window.default_location_id) {
|
||||||
|
let location = this.locations.filter(
|
||||||
|
(l) => l.id === window.default_location_id
|
||||||
|
);
|
||||||
|
this.$store.dispatch("updateLocation", location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
labelAccompanyingCourseLocation(value) {
|
||||||
|
return `${value.address.text} (${value.locationType.title.fr})`
|
||||||
|
},
|
||||||
customLabel(value) {
|
customLabel(value) {
|
||||||
return `${value.locationType.title.fr} ${value.name ? value.name : ''}`;
|
return value.locationType
|
||||||
|
? value.name
|
||||||
|
? value.name === '__AccompanyingCourseLocation__'
|
||||||
|
? this.labelAccompanyingCourseLocation(value)
|
||||||
|
: `${value.name} (${value.locationType.title.fr})`
|
||||||
|
: value.locationType.title.fr
|
||||||
|
: '';
|
||||||
|
},
|
||||||
|
makeConcernedPersonsLocation(locationType) {
|
||||||
|
let locations = [];
|
||||||
|
this.suggestedEntities.forEach(
|
||||||
|
(e) => {
|
||||||
|
if (e.type === 'person' && e.current_household_address !== null){
|
||||||
|
locations.push({
|
||||||
|
type: 'location',
|
||||||
|
id: -this.suggestedEntities.indexOf(e)*10,
|
||||||
|
onthefly: true,
|
||||||
|
name: e.text,
|
||||||
|
address: {
|
||||||
|
id: e.current_household_address.address_id,
|
||||||
|
},
|
||||||
|
locationType: locationType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return locations;
|
||||||
|
},
|
||||||
|
makeConcernedThirdPartiesLocation(locationType) {
|
||||||
|
let locations = [];
|
||||||
|
this.suggestedEntities.forEach(
|
||||||
|
(e) => {
|
||||||
|
if (e.type === 'thirdparty' && e.address !== null){
|
||||||
|
locations.push({
|
||||||
|
type: 'location',
|
||||||
|
id: -this.suggestedEntities.indexOf(e)*10,
|
||||||
|
onthefly: true,
|
||||||
|
name: e.text,
|
||||||
|
address: { id: e.address.address_id },
|
||||||
|
locationType: locationType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return locations;
|
||||||
|
},
|
||||||
|
makeAccompanyingPeriodLocation(locationType) {
|
||||||
|
const accPeriodLocation = this.activity.accompanyingPeriod.location;
|
||||||
|
return {
|
||||||
|
type: 'location',
|
||||||
|
id: -1,
|
||||||
|
onthefly: true,
|
||||||
|
name: '__AccompanyingCourseLocation__',
|
||||||
|
address: {
|
||||||
|
id: accPeriodLocation.address_id,
|
||||||
|
text: `${accPeriodLocation.text} - ${accPeriodLocation.postcode.code} ${accPeriodLocation.postcode.name}`
|
||||||
|
},
|
||||||
|
locationType: locationType
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -214,11 +214,9 @@ export default {
|
|||||||
return cond;
|
return cond;
|
||||||
},
|
},
|
||||||
getLocationTypesList() {
|
getLocationTypesList() {
|
||||||
getLocationTypes().then(response => new Promise(resolve => {
|
getLocationTypes().then(results => {
|
||||||
console.log('getLocationTypes', response);
|
this.locationTypes = results.filter(t => t.availableForUsers === true);
|
||||||
this.locationTypes = response.results.filter(t => t.availableForUsers === true);
|
})
|
||||||
resolve();
|
|
||||||
}))
|
|
||||||
},
|
},
|
||||||
openModal() {
|
openModal() {
|
||||||
this.modal.showModal = true;
|
this.modal.showModal = true;
|
||||||
@ -247,7 +245,6 @@ export default {
|
|||||||
postLocation(body)
|
postLocation(body)
|
||||||
.then(
|
.then(
|
||||||
location => new Promise(resolve => {
|
location => new Promise(resolve => {
|
||||||
console.log('postLocation', location);
|
|
||||||
this.locations.push(location);
|
this.locations.push(location);
|
||||||
this.$store.dispatch('updateLocation', location);
|
this.$store.dispatch('updateLocation', location);
|
||||||
resolve();
|
resolve();
|
||||||
|
@ -7,8 +7,19 @@ import App from './App.vue';
|
|||||||
|
|
||||||
const i18n = _createI18n(activityMessages);
|
const i18n = _createI18n(activityMessages);
|
||||||
|
|
||||||
|
const hasSocialIssues = document.querySelector('#social-issues-acc') !== null;
|
||||||
|
const hasLocation = document.querySelector('#location') !== null;
|
||||||
|
const hasPerson = document.querySelector('#add-persons') !== null;
|
||||||
|
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
template: `<app></app>`,
|
template: `<app :hasSocialIssues="hasSocialIssues", :hasLocation="hasLocation", :hasPerson="hasPerson"></app>`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
hasSocialIssues,
|
||||||
|
hasLocation,
|
||||||
|
hasPerson,
|
||||||
|
};
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.use(store)
|
.use(store)
|
||||||
.use(i18n)
|
.use(i18n)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'es6-promise/auto';
|
import 'es6-promise/auto';
|
||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
|
import { postLocation } from './api';
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
//console.log('window.activity', window.activity);
|
//console.log('window.activity', window.activity);
|
||||||
@ -27,7 +28,6 @@ const store = createStore({
|
|||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
suggestedEntities(state) {
|
suggestedEntities(state) {
|
||||||
console.log(state.activity);
|
|
||||||
if (typeof state.activity.accompanyingPeriod === "undefined") {
|
if (typeof state.activity.accompanyingPeriod === "undefined") {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -303,7 +303,33 @@ const store = createStore({
|
|||||||
let hiddenLocation = document.getElementById(
|
let hiddenLocation = document.getElementById(
|
||||||
"chill_activitybundle_activity_location"
|
"chill_activitybundle_activity_location"
|
||||||
);
|
);
|
||||||
hiddenLocation.value = value.id;
|
if (value.onthefly) {
|
||||||
|
const body = {
|
||||||
|
"type": "location",
|
||||||
|
"name": value.name === '__AccompanyingCourseLocation__' ? null : value.name,
|
||||||
|
"locationType": {
|
||||||
|
"id": value.locationType.id,
|
||||||
|
"type": "location-type"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (value.address.id) {
|
||||||
|
Object.assign(body, {
|
||||||
|
"address": {
|
||||||
|
"id": value.address.id
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
postLocation(body)
|
||||||
|
.then(
|
||||||
|
location => hiddenLocation.value = location.id
|
||||||
|
).catch(
|
||||||
|
err => {
|
||||||
|
console.log(err.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
hiddenLocation.value = value.id;
|
||||||
|
}
|
||||||
commit("updateLocation", value);
|
commit("updateLocation", value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -28,7 +28,9 @@
|
|||||||
{{ form_row(edit_form.socialActions) }}
|
{{ form_row(edit_form.socialActions) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{%- if edit_form.socialIssues is defined or edit_form.socialIssues is defined -%}
|
||||||
<div id="social-issues-acc"></div>
|
<div id="social-issues-acc"></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{%- if edit_form.reasons is defined -%}
|
{%- if edit_form.reasons is defined -%}
|
||||||
{{ form_row(edit_form.reasons) }}
|
{{ form_row(edit_form.reasons) }}
|
||||||
@ -46,9 +48,10 @@
|
|||||||
{%- if edit_form.users is defined -%}
|
{%- if edit_form.users is defined -%}
|
||||||
{{ form_widget(edit_form.users) }}
|
{{ form_widget(edit_form.users) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<div id="add-persons"></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="add-persons"></div>
|
|
||||||
|
|
||||||
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
|
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
{% if activities|length == 0 %}
|
{% if activities|length == 0 %}
|
||||||
<p class="chill-no-data-statement">
|
<p class="chill-no-data-statement">
|
||||||
{{ "There isn't any activities."|trans }}
|
{{ "There isn't any activities."|trans }}
|
||||||
<a href="{{ path('chill_activity_activity_new', {'person_id': person_id, 'accompanying_period_id': accompanying_course_id}) }}" class="btn btn-sm btn-create"></a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -36,12 +36,14 @@
|
|||||||
|
|
||||||
{% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'person'} %}
|
{% include 'ChillActivityBundle:Activity:list.html.twig' with {'context': 'person'} %}
|
||||||
|
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_CREATE', person) %}
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ path('chill_activity_activity_new', {'person_id': person_id, 'accompanying_period_id': accompanying_course_id}) }}"
|
<a href="{{ path('chill_activity_activity_new', {'person_id': person_id, 'accompanying_period_id': accompanying_course_id}) }}"
|
||||||
class="btn btn-create disabled" tabindex="-1" role="button" aria-disabled="true">{{ 'Add a new activity' | trans }}
|
class="btn btn-create" tabindex="-1" role="button" aria-disabled="true">{{ 'Create'|trans }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -29,25 +29,29 @@
|
|||||||
{{ form_row(form.socialActions) }}
|
{{ form_row(form.socialActions) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div id="social-issues-acc"></div>
|
{%- if edit_form.socialIssues is defined or edit_form.socialIssues is defined -%}
|
||||||
|
<div id="social-issues-acc"></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{%- if form.reasons is defined -%}
|
{%- if form.reasons is defined -%}
|
||||||
{{ form_row(form.reasons) }}
|
{{ form_row(form.reasons) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
|
{%- if edit_form.persons is defined or edit_form.thirdParties is defined or edit_form.users is defined -%}
|
||||||
|
<h2 class="chill-red">{{ 'Concerned groups'|trans }}</h2>
|
||||||
|
|
||||||
{%- if form.persons is defined -%}
|
{%- if form.persons is defined -%}
|
||||||
{{ form_widget(form.persons) }}
|
{{ form_widget(form.persons) }}
|
||||||
|
{% endif %}
|
||||||
|
{%- if form.thirdParties is defined -%}
|
||||||
|
{{ form_widget(form.thirdParties) }}
|
||||||
|
{% endif %}
|
||||||
|
{%- if form.users is defined -%}
|
||||||
|
{{ form_widget(form.users) }}
|
||||||
|
{% endif %}
|
||||||
|
<div id="add-persons"></div>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- if form.thirdParties is defined -%}
|
|
||||||
{{ form_widget(form.thirdParties) }}
|
|
||||||
{% endif %}
|
|
||||||
{%- if form.users is defined -%}
|
|
||||||
{{ form_widget(form.users) }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div id="add-persons"></div>
|
|
||||||
|
|
||||||
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
|
<h2 class="chill-red">{{ 'Activity data'|trans }}</h2>
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
|
'{{ "You are going to leave a page with unsubmitted data. Are you sure you want to leave ?"|trans }}');
|
||||||
});
|
});
|
||||||
window.activity = {{ activity_json|json_encode|raw }};
|
window.activity = {{ activity_json|json_encode|raw }};
|
||||||
window.default_location_id = {{ default_location_id }};
|
{% if default_location is not null %}window.default_location_id = {{ default_location.id }}{% endif %};
|
||||||
</script>
|
</script>
|
||||||
{{ encore_entry_script_tags('vue_activity') }}
|
{{ encore_entry_script_tags('vue_activity') }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<dt class="inline">{{ 'Social issues'|trans }}</dt>
|
<dt class="inline">{{ 'Social issues'|trans }}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if entity.socialIssues|length == 0 %}
|
{% if entity.socialIssues|length == 0 %}
|
||||||
<p class="chill-no-data-statement">{{ 'Any social issues'|trans }}</p>
|
<p class="chill-no-data-statement">{{ 'No social issues associated'|trans }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for si in entity.socialIssues %}{{ si|chill_entity_render_box }}{% endfor %}
|
{% for si in entity.socialIssues %}{{ si|chill_entity_render_box }}{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -38,7 +38,7 @@
|
|||||||
<dt class="inline">{{ 'Social actions'|trans }}</dt>
|
<dt class="inline">{{ 'Social actions'|trans }}</dt>
|
||||||
<dd>
|
<dd>
|
||||||
{% if entity.socialActions|length == 0 %}
|
{% if entity.socialActions|length == 0 %}
|
||||||
<p class="chill-no-data-statement">{{ 'Any social actions'|trans }}</p>
|
<p class="chill-no-data-statement">{{ 'No social actions associated'|trans }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% for sa in entity.socialActions %}{{ sa|chill_entity_render_box }}{% endfor %}
|
{% for sa in entity.socialActions %}{{ sa|chill_entity_render_box }}{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -67,8 +67,8 @@
|
|||||||
<dd>
|
<dd>
|
||||||
{% if entity.location is not null %}
|
{% if entity.location is not null %}
|
||||||
<p>
|
<p>
|
||||||
<span>{{ entity.location.locationType.title|localize_translatable_string }}</span>
|
|
||||||
{{ entity.location.name }}
|
{{ entity.location.name }}
|
||||||
|
<span> ({{ entity.location.locationType.title|localize_translatable_string }})</span>
|
||||||
</p>
|
</p>
|
||||||
{{ entity.location.address|chill_entity_render_box }}
|
{{ entity.location.address|chill_entity_render_box }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
<?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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Validator\Constraints;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
*/
|
||||||
|
class ActivityValidity extends Constraint
|
||||||
|
{
|
||||||
|
public const IS_REQUIRED_MESSAGE = ' is required';
|
||||||
|
|
||||||
|
public const ROOT_MESSAGE = 'For this type of activity, ';
|
||||||
|
|
||||||
|
public $noPersonsMessage = 'For this type of activity, you must add at least one person';
|
||||||
|
|
||||||
|
public $noThirdPartiesMessage = 'For this type of activity, you must add at least one third party';
|
||||||
|
|
||||||
|
public $noUsersMessage = 'For this type of activity, you must add at least one user';
|
||||||
|
|
||||||
|
public $socialActionsMessage = 'For this type of activity, you must add at least one social action';
|
||||||
|
|
||||||
|
public $socialIssuesMessage = 'For this type of activity, you must add at least one social issue';
|
||||||
|
|
||||||
|
public function getTargets()
|
||||||
|
{
|
||||||
|
return self::CLASS_CONSTRAINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function makeIsRequiredMessage(string $property)
|
||||||
|
{
|
||||||
|
return self::ROOT_MESSAGE . $property . self::IS_REQUIRED_MESSAGE;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
<?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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\ActivityBundle\Validator\Constraints;
|
||||||
|
|
||||||
|
use Chill\ActivityBundle\Entity\Activity;
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Validator\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
|
class ActivityValidityValidator extends ConstraintValidator
|
||||||
|
{
|
||||||
|
public function validate($activity, Constraint $constraint)
|
||||||
|
{
|
||||||
|
if (!$constraint instanceof ActivityValidity) {
|
||||||
|
throw new UnexpectedTypeException($constraint, ActivityValidity::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$activity instanceof Activity) {
|
||||||
|
throw new UnexpectedValueException($activity, Activity::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getPersonsVisible() === 2 && count($activity->getPersons()) === 0) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->noPersonsMessage)
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getUsersVisible() === 2 && count($activity->getUsers()) === 0) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->noUsersMessage)
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getThirdPartiesVisible() === 2 && count($activity->getThirdParties()) === 0) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->noThirdPartiesMessage)
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getUserVisible() === 2 && null === $activity->getUser()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('user'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getDateVisible() === 2 && null === $activity->getDate()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('date'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getLocationVisible() === 2 && null === $activity->getLocation()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('location'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getDurationTimeVisible() === 2 && null === $activity->getDurationTime()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('duration time'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getTravelTimeVisible() === 2 && null === $activity->getTravelTime()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('travel time'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getAttendeeVisible() === 2 && null === $activity->getAttendee()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('attendee'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getReasonsVisible() === 2 && null === $activity->getReasons()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('reasons'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getCommentVisible() === 2 && null === $activity->getComment()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('comment'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getSentReceivedVisible() === 2 && null === $activity->getSentReceived()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('sent/received'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getDocumentsVisible() === 2 && null === $activity->getDocuments()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('document'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getEmergencyVisible() === 2 && null === $activity->getEmergency()) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->makeIsRequiredMessage('emergency'))
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getSocialIssuesVisible() === 2 && $activity->getSocialIssues()->count() === 0) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->socialIssuesMessage)
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($activity->getActivityType()->getSocialActionsVisible() === 2 && $activity->getSocialActions()->count() === 0) {
|
||||||
|
$this->context
|
||||||
|
->buildViolation($constraint->socialActionsMessage)
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -27,3 +27,8 @@ services:
|
|||||||
|
|
||||||
Chill\ActivityBundle\Repository\:
|
Chill\ActivityBundle\Repository\:
|
||||||
resource: '../Repository/'
|
resource: '../Repository/'
|
||||||
|
|
||||||
|
Chill\ActivityBundle\Validator\Constraints\:
|
||||||
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
|
resource: '../Validator/Constraints/'
|
||||||
|
@ -43,6 +43,7 @@ Sent: Envoyer
|
|||||||
Received: Recevoir
|
Received: Recevoir
|
||||||
by: 'Par '
|
by: 'Par '
|
||||||
location: Lieu
|
location: Lieu
|
||||||
|
Reasons: Sujets
|
||||||
|
|
||||||
|
|
||||||
#forms
|
#forms
|
||||||
@ -139,34 +140,40 @@ ActivityReasonCategory is inactive and won't be proposed: La catégorie est inac
|
|||||||
# activity type type admin
|
# activity type type admin
|
||||||
ActivityType list: Types d'activités
|
ActivityType list: Types d'activités
|
||||||
Create a new activity type: Créer un nouveau type d'activité
|
Create a new activity type: Créer un nouveau type d'activité
|
||||||
Persons visible: Visibilté du champ Personnes
|
Persons visible: Visibilité du champ Personnes
|
||||||
Persons label: Libellé du champ Personnes
|
Persons label: Libellé du champ Personnes
|
||||||
User visible: Visibilté du champ Utilisateur
|
User visible: Visibilité du champ Utilisateur
|
||||||
User label: Libellé du champ Utilisateur
|
User label: Libellé du champ Utilisateur
|
||||||
Date visible: Visibilté du champ Date
|
Date visible: Visibilité du champ Date
|
||||||
Date label: Libellé du champ Date
|
Date label: Libellé du champ Date
|
||||||
Place visible: Visibilté du champ Lieu
|
Place visible: Visibilité du champ Lieu
|
||||||
Place label: Libellé du champ Lieu
|
Place label: Libellé du champ Lieu
|
||||||
Third parties visible: Visibilté du champ Tiers
|
Third parties visible: Visibilité du champ Tiers
|
||||||
Third parties label: Libellé du champ Tiers
|
Third parties label: Libellé du champ Tiers
|
||||||
Duration time visible: Visibilté du champ Durée
|
Duration time visible: Visibilité du champ Durée
|
||||||
Duration time label: Libellé du champ Durée
|
Duration time label: Libellé du champ Durée
|
||||||
Travel time visible: Visibilté du champ Durée de déplacement
|
Travel time visible: Visibilité du champ Durée de déplacement
|
||||||
Travel time label: Libellé du champ Durée de déplacement
|
Travel time label: Libellé du champ Durée de déplacement
|
||||||
Attendee visible: Visibilté du champ Présence de l'usager
|
Attendee visible: Visibilité du champ Présence de l'usager
|
||||||
Attendee label: Libellé du champ Présence de l'usager
|
Attendee label: Libellé du champ Présence de l'usager
|
||||||
Reasons visible: Visibilté du champ Sujet
|
Reasons visible: Visibilité du champ Sujet
|
||||||
Reasons label: Libellé du champ Sujet
|
Reasons label: Libellé du champ Sujet
|
||||||
Comment visible: Visibilté du champ Commentaire
|
Comment visible: Visibilité du champ Commentaire
|
||||||
Comment label: Libellé du champ Commentaire
|
Comment label: Libellé du champ Commentaire
|
||||||
Emergency visible: Visibilté du champ Urgent
|
Emergency visible: Visibilité du champ Urgent
|
||||||
Emergency label: Libellé du champ Urgent
|
Emergency label: Libellé du champ Urgent
|
||||||
Accompanying period visible: Visibilté du champ Période d'accompagnement
|
Accompanying period visible: Visibilité du champ Période d'accompagnement
|
||||||
Accompanying period label: Libellé du champ Période d'accompagnement
|
Accompanying period label: Libellé du champ Période d'accompagnement
|
||||||
Social data visible: Visibilté du champ Données sociales
|
Social issues visible: Visibilité du champ Problématiques sociales
|
||||||
Social data label: Libellé du champ Données sociales
|
Social issues label: Libellé du champ Problématiques sociales
|
||||||
Users visible: Visibilté du champ Utilisateurs
|
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
|
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
|
# activity type category admin
|
||||||
ActivityTypeCategory list: Liste des catégories des types d'activité
|
ActivityTypeCategory list: Liste des catégories des types d'activité
|
||||||
|
@ -1,2 +1,22 @@
|
|||||||
The reasons's level should not be empty: Le niveau du sujet ne peut pas être vide
|
The reasons's level should not be empty: Le niveau du sujet ne peut pas être vide
|
||||||
At least one reason must be choosen: Au moins un sujet doit être choisi
|
At least one reason must be choosen: Au moins un sujet doit être choisi
|
||||||
|
For this type of activity, you must add at least one person: Pour ce type d'activité, vous devez ajouter au moins un usager
|
||||||
|
For this type of activity, you must add at least one user: Pour ce type d'activité, vous devez ajouter au moins un utilisateur
|
||||||
|
For this type of activity, you must add at least one third party: Pour ce type d'activité, vous devez ajouter au moins un tiers
|
||||||
|
For this type of activity, user is required: Pour ce type d'activité, l'utilisateur est requis
|
||||||
|
For this type of activity, date is required: Pour ce type d'activité, la date est requise
|
||||||
|
For this type of activity, location is required: Pour ce type d'activité, la localisation est requise
|
||||||
|
For this type of activity, attendee is required: Pour ce type d'activité, le champ "Présence de la personne" est requis
|
||||||
|
For this type of activity, duration time is required: Pour ce type d'activité, la durée est requise
|
||||||
|
For this type of activity, travel time is required: Pour ce type d'activité, la durée du trajet est requise
|
||||||
|
For this type of activity, reasons is required: Pour ce type d'activité, le champ "sujet" est requis
|
||||||
|
For this type of activity, comment is required: Pour ce type d'activité, un commentaire est requis
|
||||||
|
For this type of activity, sent/received is required: Pour ce type d'activité, le champ Entrant/Sortant est requis
|
||||||
|
For this type of activity, document is required: Pour ce type d'activité, un document est requis
|
||||||
|
For this type of activity, emergency is required: Pour ce type d'activité, le champ "Urgent" est requis
|
||||||
|
For this type of activity, accompanying period is required: Pour ce type d'activité, le parcours d'accompagnement est requis
|
||||||
|
For this type of activity, you must add at least one social issue: Pour ce type d'activité, vous devez ajouter au moins une problématique sociale
|
||||||
|
For this type of activity, you must add at least one social action: Pour ce type d'activité, vous devez indiquez au moins une action sociale
|
||||||
|
|
||||||
|
# admin
|
||||||
|
This parameter must be equal to social issue parameter: Ce paramètre doit être égal au paramètre "Visibilité du champs Problématiques sociales"
|
||||||
|
@ -332,12 +332,12 @@ class CalendarController extends AbstractController
|
|||||||
|
|
||||||
$personsId = array_map(
|
$personsId = array_map(
|
||||||
static fn (Person $p): int => $p->getId(),
|
static fn (Person $p): int => $p->getId(),
|
||||||
$entity->getPersons()
|
$entity->getPersons()->toArray()
|
||||||
);
|
);
|
||||||
|
|
||||||
$professionalsId = array_map(
|
$professionalsId = array_map(
|
||||||
static fn (ThirdParty $thirdParty): ?int => $thirdParty->getId(),
|
static fn (ThirdParty $thirdParty): ?int => $thirdParty->getId(),
|
||||||
$entity->getProfessionals()
|
$entity->getProfessionals()->toArray()
|
||||||
);
|
);
|
||||||
|
|
||||||
$durationTime = $entity->getEndDate()->diff($entity->getStartDate());
|
$durationTime = $entity->getEndDate()->diff($entity->getStartDate());
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'es6-promise/auto';
|
import 'es6-promise/auto';
|
||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
|
import { postLocation } from 'ChillActivityAssets/vuejs/Activity/api';
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
@ -33,7 +34,6 @@ const store = createStore({
|
|||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
suggestedEntities(state) {
|
suggestedEntities(state) {
|
||||||
console.log(state.activity)
|
|
||||||
if (typeof(state.activity.accompanyingPeriod) === 'undefined') {
|
if (typeof(state.activity.accompanyingPeriod) === 'undefined') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -189,8 +189,35 @@ const store = createStore({
|
|||||||
updateLocation({ commit }, value) {
|
updateLocation({ commit }, value) {
|
||||||
console.log('### action: updateLocation', value);
|
console.log('### action: updateLocation', value);
|
||||||
let hiddenLocation = document.getElementById("chill_calendarbundle_calendar_location");
|
let hiddenLocation = document.getElementById("chill_calendarbundle_calendar_location");
|
||||||
hiddenLocation.value = value.id;
|
if (value.onthefly) {
|
||||||
commit('updateLocation', value);
|
const body = {
|
||||||
|
"type": "location",
|
||||||
|
"name": value.name === '__AccompanyingCourseLocation__' ? null : value.name,
|
||||||
|
"locationType": {
|
||||||
|
"id": value.locationType.id,
|
||||||
|
"type": "location-type"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (value.address.id) {
|
||||||
|
Object.assign(body, {
|
||||||
|
"address": {
|
||||||
|
"id": value.address.id
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
postLocation(body)
|
||||||
|
.then(
|
||||||
|
location => hiddenLocation.value = location.id
|
||||||
|
).catch(
|
||||||
|
err => {
|
||||||
|
console.log(err.message);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
hiddenLocation.value = value.id;
|
||||||
|
}
|
||||||
|
commit("updateLocation", value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -41,8 +41,8 @@
|
|||||||
<dd>
|
<dd>
|
||||||
{% if entity.location is not null %}
|
{% if entity.location is not null %}
|
||||||
<p>
|
<p>
|
||||||
<span>{{ entity.location.locationType.title|localize_translatable_string }}</span>
|
|
||||||
{{ entity.location.name }}
|
{{ entity.location.name }}
|
||||||
|
<span> ({{ entity.location.locationType.title|localize_translatable_string }})</span>
|
||||||
</p>
|
</p>
|
||||||
{{ entity.location.address|chill_entity_render_box }}
|
{{ entity.location.address|chill_entity_render_box }}
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
namespace Chill\MainBundle\Controller;
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
use DateInterval;
|
|
||||||
use DateTime;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,22 +19,11 @@ class LocationApiController extends ApiController
|
|||||||
{
|
{
|
||||||
public function customizeQuery(string $action, Request $request, $query): void
|
public function customizeQuery(string $action, Request $request, $query): void
|
||||||
{
|
{
|
||||||
$query->andWhere($query->expr()->orX(
|
$query->andWhere(
|
||||||
$query->expr()->andX(
|
|
||||||
$query->expr()->eq('e.createdBy', ':user'),
|
|
||||||
$query->expr()->gte('e.createdAt', ':dateBefore')
|
|
||||||
),
|
|
||||||
$query->expr()->andX(
|
$query->expr()->andX(
|
||||||
$query->expr()->eq('e.availableForUsers', "'TRUE'"),
|
$query->expr()->eq('e.availableForUsers', "'TRUE'"),
|
||||||
$query->expr()->eq('e.active', "'TRUE'"),
|
$query->expr()->eq('e.active', "'TRUE'"),
|
||||||
$query->expr()->isNotNull('e.name'),
|
|
||||||
$query->expr()->neq('e.name', ':emptyString'),
|
|
||||||
)
|
)
|
||||||
))
|
);
|
||||||
->setParameters([
|
|
||||||
'user' => $this->getUser(),
|
|
||||||
'dateBefore' => (new DateTime())->sub(new DateInterval('P6M')),
|
|
||||||
'emptyString' => '',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
<?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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||||
|
use function array_key_exists;
|
||||||
|
use function json_decode;
|
||||||
|
|
||||||
|
class PermissionApiController extends AbstractController
|
||||||
|
{
|
||||||
|
private DenormalizerInterface $denormalizer;
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
DenormalizerInterface $denormalizer,
|
||||||
|
Security $security
|
||||||
|
) {
|
||||||
|
$this->denormalizer = $denormalizer;
|
||||||
|
$this->security = $security;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api/1.0/main/permissions/info.json", methods={"POST"})
|
||||||
|
*
|
||||||
|
* @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
|
||||||
|
*/
|
||||||
|
public function getPermissions(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('ROLE_USER');
|
||||||
|
|
||||||
|
$data = json_decode($request->getContent(), true);
|
||||||
|
|
||||||
|
if (null === $data) {
|
||||||
|
throw new BadRequestHttpException(sprintf(
|
||||||
|
'Could not decode json received, or data invalid: %s, %s',
|
||||||
|
json_last_error(),
|
||||||
|
json_last_error_msg()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!array_key_exists('object', $data)) {
|
||||||
|
throw new BadRequestHttpException('the object key is not present');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!array_key_exists('class', $data)) {
|
||||||
|
throw new BadRequestHttpException('the class key is not present');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $data['object']) {
|
||||||
|
$object = $this->denormalizer->denormalize($data['object'], $data['class'], 'json');
|
||||||
|
} else {
|
||||||
|
$object = null;
|
||||||
|
}
|
||||||
|
$roles = [];
|
||||||
|
|
||||||
|
foreach (($data['roles'] ?? []) as $role) {
|
||||||
|
$roles[$role] = $this->security->isGranted($role, $object);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json(
|
||||||
|
['roles' => $roles],
|
||||||
|
200,
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ namespace Chill\MainBundle\Entity;
|
|||||||
|
|
||||||
use Chill\MainBundle\Repository\LocationTypeRepository;
|
use Chill\MainBundle\Repository\LocationTypeRepository;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||||
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
||||||
|
|
||||||
@ -20,9 +21,14 @@ use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
|
|||||||
* @DiscriminatorMap(typeProperty="type", mapping={
|
* @DiscriminatorMap(typeProperty="type", mapping={
|
||||||
* "location-type": LocationType::class
|
* "location-type": LocationType::class
|
||||||
* })
|
* })
|
||||||
|
* @UniqueEntity({"defaultFor"})
|
||||||
*/
|
*/
|
||||||
class LocationType
|
class LocationType
|
||||||
{
|
{
|
||||||
|
public const DEFAULT_FOR_3PARTY = 'thirdparty';
|
||||||
|
|
||||||
|
public const DEFAULT_FOR_PERSON = 'person';
|
||||||
|
|
||||||
public const STATUS_NEVER = 'never';
|
public const STATUS_NEVER = 'never';
|
||||||
|
|
||||||
public const STATUS_OPTIONAL = 'optional';
|
public const STATUS_OPTIONAL = 'optional';
|
||||||
@ -53,6 +59,12 @@ class LocationType
|
|||||||
*/
|
*/
|
||||||
private string $contactData = self::STATUS_OPTIONAL;
|
private string $contactData = self::STATUS_OPTIONAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="string", nullable=true, length=32, unique=true)
|
||||||
|
* @Serializer\Groups({"read"})
|
||||||
|
*/
|
||||||
|
private ?string $defaultFor = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue
|
* @ORM\GeneratedValue
|
||||||
@ -87,6 +99,11 @@ class LocationType
|
|||||||
return $this->contactData;
|
return $this->contactData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDefaultFor(): ?string
|
||||||
|
{
|
||||||
|
return $this->defaultFor;
|
||||||
|
}
|
||||||
|
|
||||||
public function getId(): ?int
|
public function getId(): ?int
|
||||||
{
|
{
|
||||||
return $this->id;
|
return $this->id;
|
||||||
@ -125,6 +142,13 @@ class LocationType
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setDefaultFor(?string $defaultFor): self
|
||||||
|
{
|
||||||
|
$this->defaultFor = $defaultFor;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function setTitle(array $title): self
|
public function setTitle(array $title): self
|
||||||
{
|
{
|
||||||
$this->title = $title;
|
$this->title = $title;
|
||||||
|
@ -71,6 +71,18 @@ final class LocationTypeType extends AbstractType
|
|||||||
],
|
],
|
||||||
'expanded' => true,
|
'expanded' => true,
|
||||||
]
|
]
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
'defaultFor',
|
||||||
|
ChoiceType::class,
|
||||||
|
[
|
||||||
|
'choices' => [
|
||||||
|
'none' => null,
|
||||||
|
'person' => LocationType::DEFAULT_FOR_PERSON,
|
||||||
|
'thirdparty' => LocationType::DEFAULT_FOR_3PARTY,
|
||||||
|
],
|
||||||
|
'expanded' => true,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* Generic api method that can be adapted to any fetch request
|
||||||
|
*/
|
||||||
|
const makeFetch = (method, url, body) => {
|
||||||
|
return fetch(url, {
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8'
|
||||||
|
},
|
||||||
|
body: (body !== null) ? JSON.stringify(body) : null
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.status === 422) {
|
||||||
|
return response.json().then(response => {
|
||||||
|
throw ValidationException(response)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.status === 403) {
|
||||||
|
return response.json().then(() => {
|
||||||
|
throw AccessException();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw {
|
||||||
|
name: 'Exception',
|
||||||
|
sta: response.status,
|
||||||
|
txt: response.statusText,
|
||||||
|
err: new Error(),
|
||||||
|
violations: response.body
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch results with certain parameters
|
||||||
|
*/
|
||||||
|
const _fetchAction = (page, uri, params) => {
|
||||||
|
const item_per_page = 50;
|
||||||
|
if (params === undefined) {
|
||||||
|
params = {};
|
||||||
|
}
|
||||||
|
let url = uri + '?' + new URLSearchParams({ item_per_page, page, ...params });
|
||||||
|
|
||||||
|
return fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json;charset=utf-8'
|
||||||
|
},
|
||||||
|
}).then(response => {
|
||||||
|
if (response.ok) { return response.json(); }
|
||||||
|
throw Error({ m: response.statusText });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchResults = async (uri, params) => {
|
||||||
|
let promises = [],
|
||||||
|
page = 1;
|
||||||
|
let firstData = await _fetchAction(page, uri, params);
|
||||||
|
|
||||||
|
promises.push(Promise.resolve(firstData.results));
|
||||||
|
|
||||||
|
if (firstData.pagination.more) {
|
||||||
|
do {
|
||||||
|
page = ++page;
|
||||||
|
promises.push(_fetchAction(page, uri, params).then(r => Promise.resolve(r.results)));
|
||||||
|
} while (page * firstData.pagination.items_per_page < firstData.count)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises).then(values => values.flat());
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchScopes = () => {
|
||||||
|
return fetchResults('/api/1.0/main/scope.json');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error objects to be thrown
|
||||||
|
*/
|
||||||
|
const ValidationException = (response) => {
|
||||||
|
const error = {};
|
||||||
|
error.name = 'ValidationException';
|
||||||
|
error.violations = response.violations.map((violation) => `${violation.title}`);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AccessException = () => {
|
||||||
|
const error = {};
|
||||||
|
error.name = 'AccessException';
|
||||||
|
error.violations = ['You are no longer permitted to perform this action'];
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
makeFetch,
|
||||||
|
fetchResults,
|
||||||
|
fetchScopes
|
||||||
|
}
|
@ -1,39 +1,39 @@
|
|||||||
|
|
||||||
const _fetchAction = (page, uri, params) => {
|
// const _fetchAction = (page, uri, params) => {
|
||||||
const item_per_page = 50;
|
// const item_per_page = 50;
|
||||||
if (params === undefined) {
|
// if (params === undefined) {
|
||||||
params = {};
|
// params = {};
|
||||||
}
|
// }
|
||||||
let url = uri + '?' + new URLSearchParams({ item_per_page, page, ...params });
|
// let url = uri + '?' + new URLSearchParams({ item_per_page, page, ...params });
|
||||||
|
|
||||||
return fetch(url, {
|
// return fetch(url, {
|
||||||
method: 'GET',
|
// method: 'GET',
|
||||||
headers: {
|
// headers: {
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
// 'Content-Type': 'application/json;charset=utf-8'
|
||||||
},
|
// },
|
||||||
}).then(response => {
|
// }).then(response => {
|
||||||
if (response.ok) { return response.json(); }
|
// if (response.ok) { return response.json(); }
|
||||||
throw Error({ m: response.statusText });
|
// throw Error({ m: response.statusText });
|
||||||
});
|
// });
|
||||||
};
|
// };
|
||||||
|
|
||||||
const fetchResults = async (uri, params) => {
|
// const fetchResults = async (uri, params) => {
|
||||||
let promises = [],
|
// let promises = [],
|
||||||
page = 1;
|
// page = 1;
|
||||||
let firstData = await _fetchAction(page, uri, params);
|
// let firstData = await _fetchAction(page, uri, params);
|
||||||
|
|
||||||
promises.push(Promise.resolve(firstData.results));
|
// promises.push(Promise.resolve(firstData.results));
|
||||||
|
|
||||||
if (firstData.pagination.more) {
|
// if (firstData.pagination.more) {
|
||||||
do {
|
// do {
|
||||||
page = ++page;
|
// page = ++page;
|
||||||
promises.push(_fetchAction(page, uri, params).then(r => Promise.resolve(r.results)));
|
// promises.push(_fetchAction(page, uri, params).then(r => Promise.resolve(r.results)));
|
||||||
} while (page * firstData.pagination.items_per_page < firstData.count)
|
// } while (page * firstData.pagination.items_per_page < firstData.count)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return Promise.all(promises).then(values => values.flat());
|
// return Promise.all(promises).then(values => values.flat());
|
||||||
};
|
// };
|
||||||
|
|
||||||
export {
|
// export {
|
||||||
fetchResults
|
// fetchResults
|
||||||
};
|
// };
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { fetchResults } from 'ChillMainAssets/lib/api/download.js';
|
// import { fetchResults } from 'ChillMainAssets/lib/api/download.js';
|
||||||
|
|
||||||
const fetchScopes = () => {
|
// const fetchScopes = () => {
|
||||||
return fetchResults('/api/1.0/main/scope.json');
|
// return fetchResults('/api/1.0/main/scope.json');
|
||||||
};
|
// };
|
||||||
|
|
||||||
export {
|
// export {
|
||||||
fetchScopes
|
// fetchScopes
|
||||||
};
|
// };
|
||||||
|
@ -588,6 +588,12 @@ export default {
|
|||||||
newAddress = Object.assign(newAddress, {
|
newAddress = Object.assign(newAddress, {
|
||||||
'point': this.entity.selected.address.point.coordinates
|
'point': this.entity.selected.address.point.coordinates
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
if (this.entity.selected.postcode.coordinates) {
|
||||||
|
newAddress = Object.assign(newAddress, {
|
||||||
|
'point': this.entity.selected.postcode.coordinates
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the address reference, if any
|
// add the address reference, if any
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
<VueMultiselect
|
<VueMultiselect
|
||||||
id="addressSelector"
|
id="addressSelector"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
|
:placeholder="$t('select_address')"
|
||||||
|
:tag-placeholder="$t('create_address')"
|
||||||
|
:select-label="$t('press_enter_to_select')"
|
||||||
|
:deselect-label="$t('create_address')"
|
||||||
@search-change="listenInputSearch"
|
@search-change="listenInputSearch"
|
||||||
ref="addressSelector"
|
ref="addressSelector"
|
||||||
@select="selectAddress"
|
@select="selectAddress"
|
||||||
@ -14,8 +18,6 @@
|
|||||||
:taggable="true"
|
:taggable="true"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
@tag="addAddress"
|
@tag="addAddress"
|
||||||
:placeholder="$t('select_address')"
|
|
||||||
:tagPlaceholder="$t('create_address')"
|
|
||||||
:options="addresses">
|
:options="addresses">
|
||||||
</VueMultiselect>
|
</VueMultiselect>
|
||||||
</div>
|
</div>
|
||||||
@ -141,7 +143,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
addAddress() {
|
addAddress() {
|
||||||
console.log('addAddress: pass here ?? never, it seems');
|
|
||||||
this.entity.selected.writeNew.address = true;
|
this.entity.selected.writeNew.address = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
label="value"
|
label="value"
|
||||||
:custom-label="transName"
|
:custom-label="transName"
|
||||||
:placeholder="$t('select_city')"
|
:placeholder="$t('select_city')"
|
||||||
|
:select-label="$t('press_enter_to_select')"
|
||||||
|
:deselect-label="$t('create_postal_code')"
|
||||||
:taggable="true"
|
:taggable="true"
|
||||||
:multiple="false"
|
:multiple="false"
|
||||||
@tag="addPostcode"
|
@tag="addPostcode"
|
||||||
@ -101,6 +103,7 @@ export default {
|
|||||||
this.entity.selected.city = value;
|
this.entity.selected.city = value;
|
||||||
this.entity.selected.postcode.name = value.name;
|
this.entity.selected.postcode.name = value.name;
|
||||||
this.entity.selected.postcode.code = value.code;
|
this.entity.selected.postcode.code = value.code;
|
||||||
|
this.entity.selected.postcode.coordinates = value.center.coordinates;
|
||||||
this.entity.selected.writeNew.postcode = false;
|
this.entity.selected.writeNew.postcode = false;
|
||||||
console.log('writeNew.postcode false, in selectCity');
|
console.log('writeNew.postcode false, in selectCity');
|
||||||
this.$emit('getReferenceAddresses', value);
|
this.$emit('getReferenceAddresses', value);
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
v-bind:placeholder="$t('select_country')"
|
v-bind:placeholder="$t('select_country')"
|
||||||
v-bind:options="sortedCountries"
|
v-bind:options="sortedCountries"
|
||||||
v-model="value"
|
v-model="value"
|
||||||
|
:select-label="$t('press_enter_to_select')"
|
||||||
|
:deselect-label="$t('press_enter_to_remove')"
|
||||||
@select="selectCountry">
|
@select="selectCountry">
|
||||||
</VueMultiselect>
|
</VueMultiselect>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
const addressMessages = {
|
const addressMessages = {
|
||||||
fr: {
|
fr: {
|
||||||
|
press_enter_to_select: 'Appuyer sur Entrée pour sélectionner',
|
||||||
|
press_enter_to_remove: 'Appuyer sur Entrée pour désélectionner',
|
||||||
add_an_address_title: 'Créer une adresse',
|
add_an_address_title: 'Créer une adresse',
|
||||||
edit_an_address_title: 'Modifier une adresse',
|
edit_an_address_title: 'Modifier une adresse',
|
||||||
create_a_new_address: 'Créer une nouvelle adresse',
|
create_a_new_address: 'Créer une nouvelle adresse',
|
||||||
|
@ -13,7 +13,6 @@ export default {
|
|||||||
methods : {
|
methods : {
|
||||||
toggleBlur: function(e){
|
toggleBlur: function(e){
|
||||||
if(e.target.matches('.toggle')){
|
if(e.target.matches('.toggle')){
|
||||||
console.log(e);
|
|
||||||
e.target.previousElementSibling.classList.toggle("blur");
|
e.target.previousElementSibling.classList.toggle("blur");
|
||||||
e.target.classList.toggle("fa-eye");
|
e.target.classList.toggle("fa-eye");
|
||||||
e.target.classList.toggle("fa-eye-slash");
|
e.target.classList.toggle("fa-eye-slash");
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
<th>{{ 'Address required'|trans }}</th>
|
<th>{{ 'Address required'|trans }}</th>
|
||||||
<th>{{ 'Contact data'|trans }}</th>
|
<th>{{ 'Contact data'|trans }}</th>
|
||||||
<th>{{ 'Active'|trans }}</th>
|
<th>{{ 'Active'|trans }}</th>
|
||||||
|
<th>{{ 'Default for'|trans }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -33,6 +34,7 @@
|
|||||||
<i class="fa fa-square-o"></i>
|
<i class="fa fa-square-o"></i>
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</td>
|
</td>
|
||||||
|
<td>{{ entity.defaultFor|trans }}</td>
|
||||||
<td>
|
<td>
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
<li>
|
<li>
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
<?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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Test\PrepareClientTrait;
|
||||||
|
use DateTime;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class PermissionApiControllerTest extends WebTestCase
|
||||||
|
{
|
||||||
|
use PrepareClientTrait;
|
||||||
|
|
||||||
|
public function testDenormalizingObject()
|
||||||
|
{
|
||||||
|
$client = $this->getClientAuthenticated();
|
||||||
|
|
||||||
|
$client->request(
|
||||||
|
'POST',
|
||||||
|
'/api/1.0/main/permissions/info.json',
|
||||||
|
[], // parameters
|
||||||
|
[], // files
|
||||||
|
[], // server
|
||||||
|
json_encode([
|
||||||
|
'object' => [
|
||||||
|
'datetime' => '1969-07-09T00:00:00+0100',
|
||||||
|
],
|
||||||
|
'class' => DateTime::class,
|
||||||
|
'roles' => ['FOO_ROLE'],
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful();
|
||||||
|
|
||||||
|
$data = json_decode($client->getResponse()->getContent(), true);
|
||||||
|
$this->assertFalse($data['roles']['FOO_ROLE']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNullObject()
|
||||||
|
{
|
||||||
|
$client = $this->getClientAuthenticated();
|
||||||
|
|
||||||
|
$client->request(
|
||||||
|
'POST',
|
||||||
|
'/api/1.0/main/permissions/info.json',
|
||||||
|
[], // parameters
|
||||||
|
[], // files
|
||||||
|
[], // server
|
||||||
|
json_encode([
|
||||||
|
'object' => null,
|
||||||
|
'class' => null,
|
||||||
|
'roles' => ['ROLE_USER', 'ROLE_ADMIN'],
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertResponseIsSuccessful();
|
||||||
|
|
||||||
|
$data = json_decode($client->getResponse()->getContent(), true);
|
||||||
|
$this->assertTrue($data['roles']['ROLE_USER']);
|
||||||
|
$this->assertFalse($data['roles']['ROLE_ADMIN']);
|
||||||
|
}
|
||||||
|
}
|
@ -624,3 +624,40 @@ paths:
|
|||||||
401:
|
401:
|
||||||
description: "Unauthorized"
|
description: "Unauthorized"
|
||||||
|
|
||||||
|
/1.0/main/permissions/info.json:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- permissions
|
||||||
|
summary: Return info about permissions on entity
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "ok"
|
||||||
|
401:
|
||||||
|
description: "Unauthorized"
|
||||||
|
400:
|
||||||
|
description: "Bad request"
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
object:
|
||||||
|
type: object
|
||||||
|
class:
|
||||||
|
type: string
|
||||||
|
roles:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
examples:
|
||||||
|
an-accompanying-period:
|
||||||
|
value:
|
||||||
|
object:
|
||||||
|
type: accompanying_period
|
||||||
|
id: 1
|
||||||
|
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod'
|
||||||
|
roles:
|
||||||
|
- 'CHILL_PERSON_ACCOMPANYING_PERIOD_SEE'
|
||||||
|
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
<?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\Migrations\Main;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add defaultFor to LocationType.
|
||||||
|
*/
|
||||||
|
final class Version20211123093355 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('DROP INDEX UNIQ_A459B5CADD3E4105');
|
||||||
|
$this->addSql('ALTER TABLE chill_main_location_type DROP defaultFor');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Add defaultFor to LocationType';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE chill_main_location_type ADD defaultFor VARCHAR(32) DEFAULT NULL');
|
||||||
|
$this->addSql('CREATE UNIQUE INDEX UNIQ_A459B5CADD3E4105 ON chill_main_location_type (defaultFor)');
|
||||||
|
}
|
||||||
|
}
|
@ -212,6 +212,10 @@ Location type: Type de localisation
|
|||||||
Phonenumber1: Numéro de téléphone
|
Phonenumber1: Numéro de téléphone
|
||||||
Phonenumber2: Autre numéro de téléphone
|
Phonenumber2: Autre numéro de téléphone
|
||||||
Configure location and location type: Configuration des localisations
|
Configure location and location type: Configuration des localisations
|
||||||
|
Default for: Type de localisation par défaut pour
|
||||||
|
none: aucun
|
||||||
|
person: usager
|
||||||
|
thirdparty: tiers
|
||||||
|
|
||||||
# circles / scopes
|
# circles / scopes
|
||||||
Choose the circle: Choisir le cercle
|
Choose the circle: Choisir le cercle
|
||||||
|
@ -249,6 +249,22 @@ final class AccompanyingCourseApiController extends ApiController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/api/1.0/person/accompanying-course/{id}/confidential.json", name="chill_api_person_accompanying_period_confidential")
|
||||||
|
* @ParamConverter("accompanyingCourse", options={"id": "id"})
|
||||||
|
*/
|
||||||
|
public function toggleConfidentialApi(AccompanyingPeriod $accompanyingCourse, Request $request)
|
||||||
|
{
|
||||||
|
if ($request->getMethod() === 'POST') {
|
||||||
|
$this->denyAccessUnlessGranted(AccompanyingPeriodVoter::CONFIDENTIAL, $accompanyingCourse);
|
||||||
|
|
||||||
|
$accompanyingCourse->setConfidential(!$accompanyingCourse->isConfidential());
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json($accompanyingCourse->isConfidential(), 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(
|
||||||
|
@ -213,9 +213,14 @@ class AccompanyingPeriodController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
|
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
|
||||||
|
|
||||||
$accompanyingPeriods = $this->accompanyingPeriodACLAwareRepository
|
$accompanyingPeriodsRaw = $this->accompanyingPeriodACLAwareRepository
|
||||||
->findByPerson($person, AccompanyingPeriodVoter::SEE);
|
->findByPerson($person, AccompanyingPeriodVoter::SEE);
|
||||||
|
|
||||||
|
// filter visible or not visible
|
||||||
|
$accompanyingPeriods = array_filter($accompanyingPeriodsRaw, function (AccompanyingPeriod $ap) {
|
||||||
|
return $this->isGranted(AccompanyingPeriodVoter::SEE, $ap);
|
||||||
|
});
|
||||||
|
|
||||||
return $this->render('@ChillPerson/AccompanyingPeriod/list.html.twig', [
|
return $this->render('@ChillPerson/AccompanyingPeriod/list.html.twig', [
|
||||||
'accompanying_periods' => $accompanyingPeriods,
|
'accompanying_periods' => $accompanyingPeriods,
|
||||||
'person' => $person,
|
'person' => $person,
|
||||||
|
@ -378,7 +378,6 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
|
|||||||
Request::METHOD_DELETE => 'ALWAYS_FAILS',
|
Request::METHOD_DELETE => 'ALWAYS_FAILS',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
'confirm' => [
|
'confirm' => [
|
||||||
'methods' => [
|
'methods' => [
|
||||||
Request::METHOD_POST => true,
|
Request::METHOD_POST => true,
|
||||||
@ -389,6 +388,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' => [
|
||||||
|
'methods' => [
|
||||||
|
Request::METHOD_POST => true,
|
||||||
|
Request::METHOD_GET => true,
|
||||||
|
],
|
||||||
|
'controller_action' => 'toggleConfidentialApi',
|
||||||
|
'roles' => [
|
||||||
|
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',
|
||||||
|
@ -49,6 +49,10 @@ use UnexpectedValueException;
|
|||||||
* "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."
|
||||||
|
* )
|
||||||
*/
|
*/
|
||||||
class AccompanyingPeriod implements
|
class AccompanyingPeriod implements
|
||||||
TrackCreationInterface,
|
TrackCreationInterface,
|
||||||
@ -277,7 +281,7 @@ class AccompanyingPeriod implements
|
|||||||
* inverseJoinColumns={@ORM\JoinColumn(name="scope_id", referencedColumnName="id")}
|
* inverseJoinColumns={@ORM\JoinColumn(name="scope_id", referencedColumnName="id")}
|
||||||
* )
|
* )
|
||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
* @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED})
|
* @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}, minMessage="A course must be associated to at least one scope")
|
||||||
*/
|
*/
|
||||||
private $scopes;
|
private $scopes;
|
||||||
|
|
||||||
@ -289,7 +293,7 @@ class AccompanyingPeriod implements
|
|||||||
* name="chill_person_accompanying_period_social_issues"
|
* name="chill_person_accompanying_period_social_issues"
|
||||||
* )
|
* )
|
||||||
* @Groups({"read"})
|
* @Groups({"read"})
|
||||||
* @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED})
|
* @Assert\Count(min=1, groups={AccompanyingPeriod::STEP_CONFIRMED}, minMessage="A course must contains at least one social issue")
|
||||||
*/
|
*/
|
||||||
private Collection $socialIssues;
|
private Collection $socialIssues;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { fetchResults } from 'ChillMainAssets/lib/api/download.js';
|
import { fetchResults } from 'ChillMainAssets/lib/api/apiMethods.js';
|
||||||
|
|
||||||
const fetchHouseholdByAddressReference = async (reference) => {
|
const fetchHouseholdByAddressReference = async (reference) => {
|
||||||
const url = `/api/1.0/person/household/by-address-reference/${reference.id}.json`
|
const url = `/api/1.0/person/household/by-address-reference/${reference.id}.json`
|
||||||
|
@ -59,7 +59,7 @@ export default {
|
|||||||
'accompanyingCourse',
|
'accompanyingCourse',
|
||||||
'addressContext'
|
'addressContext'
|
||||||
]),
|
]),
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { fetchResults } from 'ChillMainAssets/lib/api/download.js';
|
import { fetchResults } from 'ChillMainAssets/lib/api/apiMethods.js';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Endpoint v.2 chill_api_single_accompanying_course__entity
|
* Endpoint v.2 chill_api_single_accompanying_course__entity
|
||||||
@ -15,44 +15,17 @@ const getAccompanyingCourse = (id) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
const getUsers = () => {
|
||||||
* Endpoint v.2 chill_api_single_accompanying_course__entity
|
const url = `/api/1.0/main/user.json`;
|
||||||
* method PATCH, patch AccompanyingCourse Instance
|
|
||||||
*
|
return fetchResults(url);
|
||||||
* @id integer - id of accompanyingCourse
|
|
||||||
* @body Object - dictionary with changes to post
|
|
||||||
*/
|
|
||||||
const patchAccompanyingCourse = (id, body) => {
|
|
||||||
//console.log('body', body);
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}.json`;
|
|
||||||
return fetch(url, {
|
|
||||||
method: 'PATCH',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
console.log(response);
|
|
||||||
throw { msg: 'Error while updating AccompanyingPeriod Course.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
const getReferrersSuggested = (course) => {
|
||||||
* Endpoint to change 'DRAFT' step to 'CONFIRMED'
|
const url = `/api/1.0/person/accompanying-course/${course.id}/referrers-suggested.json`;
|
||||||
*/
|
|
||||||
const confirmAccompanyingCourse = (id) => {
|
return fetchResults(url);
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}/confirm.json`
|
}
|
||||||
return fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {'Content-Type': 'application/json;charset=utf-8'}
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw { msg: 'Error while confirming AccompanyingPeriod Course.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Endpoint
|
* Endpoint
|
||||||
@ -66,115 +39,6 @@ const getSocialIssues = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Endpoint v.2 chill_api_single_accompanying_course_participation,
|
|
||||||
* method POST/DELETE, add/close a participation to the accompanyingCourse
|
|
||||||
*
|
|
||||||
* @id integer - id of accompanyingCourse
|
|
||||||
* @payload integer - id of person
|
|
||||||
* @method string - POST or DELETE
|
|
||||||
*/
|
|
||||||
const postParticipation = (id, payload, method) => {
|
|
||||||
const body = { type: payload.type, id: payload.id };
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}/participation.json`;
|
|
||||||
return fetch(url, {
|
|
||||||
method: method,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
// TODO: adjust message according to status code? Or how to access the message from the violation array?
|
|
||||||
throw { msg: 'Error while sending AccompanyingPeriod Course participation', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Endpoint v.2 chill_api_single_accompanying_course_requestor,
|
|
||||||
* method POST/DELETE, add/close a requestor to the accompanyingCourse
|
|
||||||
*
|
|
||||||
* @id integer - id of accompanyingCourse
|
|
||||||
* @payload object of type person|thirdparty
|
|
||||||
* @method string - POST or DELETE
|
|
||||||
*/
|
|
||||||
const postRequestor = (id, payload, method) => {
|
|
||||||
//console.log('payload', payload);
|
|
||||||
const body = (payload)? { type: payload.type, id: payload.id } : {};
|
|
||||||
//console.log('body', body);
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}/requestor.json`;
|
|
||||||
return fetch(url, {
|
|
||||||
method: method,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw { msg: 'Error while sending AccompanyingPeriod Course requestor', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Endpoint v.2 chill_api_single_accompanying_course_resource,
|
|
||||||
* method POST/DELETE, add/remove a resource to the accompanyingCourse
|
|
||||||
*
|
|
||||||
* @id integer - id of accompanyingCourse
|
|
||||||
* @payload object of type person|thirdparty
|
|
||||||
* @method string - POST or DELETE
|
|
||||||
*/
|
|
||||||
const postResource = (id, payload, method) => {
|
|
||||||
//console.log('payload', payload);
|
|
||||||
const body = { type: "accompanying_period_resource" };
|
|
||||||
switch (method) {
|
|
||||||
case 'DELETE':
|
|
||||||
body['id'] = payload.id;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
body['resource'] = { type: payload.type, id: payload.id };
|
|
||||||
}
|
|
||||||
//console.log('body', body);
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}/resource.json`;
|
|
||||||
return fetch(url, {
|
|
||||||
method: method,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw { msg: 'Error while sending AccompanyingPeriod Course resource.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Endpoint to Add/remove SocialIssue
|
|
||||||
*/
|
|
||||||
const postSocialIssue = (id, body, method) => {
|
|
||||||
//console.log('api body and method', body, method);
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}/socialissue.json`;
|
|
||||||
return fetch(url, {
|
|
||||||
method: method,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body)
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw { msg: 'Error while updating SocialIssue.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUsers = () => {
|
|
||||||
const url = `/api/1.0/main/user.json`;
|
|
||||||
|
|
||||||
return fetchResults(url);
|
|
||||||
};
|
|
||||||
|
|
||||||
const whoami = () => {
|
const whoami = () => {
|
||||||
const url = `/api/1.0/main/whoami.json`;
|
const url = `/api/1.0/main/whoami.json`;
|
||||||
return fetch(url)
|
return fetch(url)
|
||||||
@ -184,74 +48,10 @@ const whoami = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const getListOrigins = () => {
|
|
||||||
const url = `/api/1.0/person/accompanying-period/origin.json`;
|
|
||||||
return fetch(url)
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw { msg: 'Error while retriving origin\'s list.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const addScope = (id, scope) => {
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}/scope.json`;
|
|
||||||
console.log(url);
|
|
||||||
console.log(scope);
|
|
||||||
|
|
||||||
return fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({
|
|
||||||
id: scope.id,
|
|
||||||
type: scope.type,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw { msg: 'Error while adding scope', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeScope = (id, scope) => {
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${id}/scope.json`;
|
|
||||||
|
|
||||||
return fetch(url, {
|
|
||||||
method: 'DELETE',
|
|
||||||
body: JSON.stringify({
|
|
||||||
id: scope.id,
|
|
||||||
type: scope.type,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json;charset=utf-8'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (response.ok) { return response.json(); }
|
|
||||||
throw { msg: 'Error while adding scope', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const getReferrersSuggested = (course) => {
|
|
||||||
const url = `/api/1.0/person/accompanying-course/${course.id}/referrers-suggested.json`;
|
|
||||||
|
|
||||||
return fetchResults(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getAccompanyingCourse,
|
|
||||||
patchAccompanyingCourse,
|
|
||||||
confirmAccompanyingCourse,
|
|
||||||
getSocialIssues,
|
|
||||||
postParticipation,
|
|
||||||
postRequestor,
|
|
||||||
postResource,
|
|
||||||
getUsers,
|
|
||||||
whoami,
|
whoami,
|
||||||
getListOrigins,
|
getSocialIssues,
|
||||||
postSocialIssue,
|
getAccompanyingCourse,
|
||||||
addScope,
|
getUsers,
|
||||||
removeScope,
|
|
||||||
getReferrersSuggested,
|
getReferrersSuggested,
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ToggleFlags",
|
name: "ToggleFlags",
|
||||||
computed: {
|
computed: {
|
||||||
@ -28,6 +29,7 @@ export default {
|
|||||||
intensity: state => state.accompanyingCourse.intensity,
|
intensity: state => state.accompanyingCourse.intensity,
|
||||||
emergency: state => state.accompanyingCourse.emergency,
|
emergency: state => state.accompanyingCourse.emergency,
|
||||||
confidential: state => state.accompanyingCourse.confidential,
|
confidential: state => state.accompanyingCourse.confidential,
|
||||||
|
permissions: state => state.permissions,
|
||||||
}),
|
}),
|
||||||
isRegular() {
|
isRegular() {
|
||||||
return (this.intensity === 'regular') ? true : false;
|
return (this.intensity === 'regular') ? true : false;
|
||||||
@ -37,7 +39,7 @@ export default {
|
|||||||
},
|
},
|
||||||
isConfidential() {
|
isConfidential() {
|
||||||
return (this.confidential) ? true : false;
|
return (this.confidential) ? true : false;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleIntensity() {
|
toggleIntensity() {
|
||||||
@ -53,15 +55,42 @@ export default {
|
|||||||
//temporaire (modif backend)
|
//temporaire (modif backend)
|
||||||
value = "occasional";
|
value = "occasional";
|
||||||
}
|
}
|
||||||
this.$store.dispatch('toggleIntensity', value);
|
this.$store.dispatch('toggleIntensity', value)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
toggleEmergency() {
|
toggleEmergency() {
|
||||||
this.$store.dispatch('toggleEmergency', (!this.isEmergency));
|
this.$store.dispatch('toggleEmergency', (!this.isEmergency))
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
toggleConfidential() {
|
toggleConfidential() {
|
||||||
this.$store.dispatch('toggleConfidential', (!this.isConfidential));
|
this.$store.dispatch('fetchPermissions').then(() => {
|
||||||
}
|
if (!this.$store.getters.canTogglePermission) {
|
||||||
}
|
this.$toast.open({message: "Seul le référent peut modifier la confidentialité"});
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return this.$store.dispatch('toggleConfidential', (!this.isConfidential));
|
||||||
|
}
|
||||||
|
}).catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -59,7 +59,15 @@ export default {
|
|||||||
locationStatusTo: 'person',
|
locationStatusTo: 'person',
|
||||||
personId: this.person.id
|
personId: this.person.id
|
||||||
};
|
};
|
||||||
this.$store.dispatch('updateLocation', payload);
|
this.$store.dispatch('updateLocation', payload)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
window.location.assign('#section-20');
|
window.location.assign('#section-20');
|
||||||
this.modal.showModal = false;
|
this.modal.showModal = false;
|
||||||
}
|
}
|
||||||
|
@ -83,12 +83,24 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
submitform() {
|
submitform() {
|
||||||
//console.log('submit');
|
this.$store.dispatch('postFirstComment', this.formdata)
|
||||||
this.$store.dispatch('postFirstComment', this.formdata);
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
removeComment() {
|
removeComment() {
|
||||||
//console.log('remove');
|
this.$store.dispatch('postFirstComment', {})
|
||||||
this.$store.dispatch('postFirstComment', {});
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,9 +115,14 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
confirmCourse() {
|
confirmCourse() {
|
||||||
//console.log('@@ CLICK confirmCourse');
|
this.$store.dispatch('confirmAccompanyingCourse')
|
||||||
this.$store.dispatch('confirmAccompanyingCourse');
|
.catch(({name, violations}) => {
|
||||||
//console.log('confirm last');
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,14 @@ export default {
|
|||||||
locationStatusTo: 'none'
|
locationStatusTo: 'none'
|
||||||
};
|
};
|
||||||
//console.log('remove address');
|
//console.log('remove address');
|
||||||
this.$store.dispatch('updateLocation', payload);
|
this.$store.dispatch('updateLocation', payload)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
displayErrors() {
|
displayErrors() {
|
||||||
return this.$refs.addAddress.errorMsg;
|
return this.$refs.addAddress.errorMsg;
|
||||||
@ -195,7 +202,15 @@ export default {
|
|||||||
submitTemporaryAddress(payload) {
|
submitTemporaryAddress(payload) {
|
||||||
//console.log('@@@ click on Submit Temporary Address Button', payload);
|
//console.log('@@@ click on Submit Temporary Address Button', payload);
|
||||||
payload['locationStatusTo'] = 'address'; // <== temporary, not none, not person
|
payload['locationStatusTo'] = 'address'; // <== temporary, not none, not person
|
||||||
this.$store.dispatch('updateLocation', payload);
|
this.$store.dispatch('updateLocation', payload)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.$store.commit('setEditContextTrue', payload);
|
this.$store.commit('setEditContextTrue', payload);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import VueMultiselect from 'vue-multiselect';
|
import VueMultiselect from 'vue-multiselect';
|
||||||
import { getListOrigins } from '../api';
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
import { mapState, mapGetters } from 'vuex';
|
import { mapState, mapGetters } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -53,14 +53,26 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getOptions() {
|
getOptions() {
|
||||||
getListOrigins().then(response => new Promise((resolve, reject) => {
|
const url = `/api/1.0/person/accompanying-period/origin.json`;
|
||||||
this.options = response.results;
|
makeFetch('GET', url)
|
||||||
resolve();
|
.then(response => {
|
||||||
}));
|
this.options = response.results;
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
this.$toast.open({message: error.txt})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
updateOrigin(value) {
|
updateOrigin(value) {
|
||||||
console.log('value', value);
|
this.$store.dispatch('updateOrigin', value)
|
||||||
this.$store.dispatch('updateOrigin', value);
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
transText ({ text }) {
|
transText ({ text }) {
|
||||||
const parsedText = JSON.parse(text);
|
const parsedText = JSON.parse(text);
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<button class="btn btn-update" type="submit">{{ $t('persons_associated.update_household') }}</button>
|
<button class="btn btn-update" type="submit">{{ $t('persons_associated.update_household') }}</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="mb-3">{{ $t('persons_associated.person_without_household_warning') }}</p>
|
<p class="mb-3">{{ $t('persons_associated.person_without_household_warning') }}</p>
|
||||||
<div class="form-check" v-for="p in participationWithoutHousehold">
|
<div class="form-check" v-for="p in participationWithoutHousehold" :key="p.id">
|
||||||
<input type="checkbox"
|
<input type="checkbox"
|
||||||
class="form-check-input"
|
class="form-check-input"
|
||||||
v-model="hasNoHousehold"
|
v-model="hasNoHousehold"
|
||||||
@ -47,6 +47,14 @@
|
|||||||
</participation-item>
|
</participation-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="suggestedPersons.length > 0">
|
||||||
|
<ul class="list-suggest add-items">
|
||||||
|
<li v-for="p in suggestedPersons" :key="p.id" @click="addSuggestedPerson(p)">
|
||||||
|
<span>{{ p.text }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<add-persons
|
<add-persons
|
||||||
buttonTitle="persons_associated.add_persons"
|
buttonTitle="persons_associated.add_persons"
|
||||||
@ -66,8 +74,8 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {mapGetters, mapState} from 'vuex';
|
import {mapGetters, mapState} from 'vuex';
|
||||||
import ParticipationItem from "./PersonsAssociated/ParticipationItem.vue"
|
import ParticipationItem from "./PersonsAssociated/ParticipationItem.vue";
|
||||||
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue'
|
import AddPersons from 'ChillPersonAssets/vuejs/_components/AddPersons.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PersonsAssociated',
|
name: 'PersonsAssociated',
|
||||||
@ -90,7 +98,28 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
courseId: state => state.accompanyingCourse.id,
|
courseId: state => state.accompanyingCourse.id,
|
||||||
participations: state => state.accompanyingCourse.participations
|
participations: state => state.accompanyingCourse.participations,
|
||||||
|
suggestedPersons: state => [
|
||||||
|
state.accompanyingCourse.requestor,
|
||||||
|
...state.accompanyingCourse.resources.map(r => r.resource)
|
||||||
|
]
|
||||||
|
.filter((e) => e !== null)
|
||||||
|
.filter((e) => e.type === 'person')
|
||||||
|
.filter(
|
||||||
|
(p) => !state.accompanyingCourse.participations.filter(pa => pa.endDate === null).map((pa) => pa.person.id).includes(p.id)
|
||||||
|
)
|
||||||
|
// filter persons appearing twice in requestor and resources
|
||||||
|
.filter(
|
||||||
|
(e, index, suggested) => {
|
||||||
|
for (let i = 0; i < suggested.length; i = i+1) {
|
||||||
|
if (i < index && e.id === suggested[i].id) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
'isParticipationValid'
|
'isParticipationValid'
|
||||||
@ -106,26 +135,54 @@ export default {
|
|||||||
},
|
},
|
||||||
getReturnPath() {
|
getReturnPath() {
|
||||||
return window.location.pathname + window.location.search + window.location.hash;
|
return window.location.pathname + window.location.search + window.location.hash;
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
removeParticipation(item) {
|
removeParticipation(item) {
|
||||||
//console.log('@@ CLICK remove participation: item', item);
|
this.$store.dispatch('removeParticipation', item)
|
||||||
this.$store.dispatch('removeParticipation', item);
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
closeParticipation(item) {
|
closeParticipation(item) {
|
||||||
//console.log('@@ CLICK close participation: item', item);
|
this.$store.dispatch('closeParticipation', item)
|
||||||
this.$store.dispatch('closeParticipation', item);
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
addNewPersons({ selected, modal }) {
|
addNewPersons({ selected, modal }) {
|
||||||
//console.log('@@@ CLICK button addNewPersons', selected);
|
|
||||||
selected.forEach(function(item) {
|
selected.forEach(function(item) {
|
||||||
this.$store.dispatch('addParticipation', item);
|
this.$store.dispatch('addParticipation', item)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
}, this
|
}, this
|
||||||
);
|
);
|
||||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||||
modal.showModal = false;
|
modal.showModal = false;
|
||||||
}
|
},
|
||||||
|
addSuggestedPerson(person) {
|
||||||
|
this.$store.dispatch('addParticipation', { result: person, type: 'person' })
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -110,7 +110,14 @@ export default {
|
|||||||
saveFormOnTheFly(payload) {
|
saveFormOnTheFly(payload) {
|
||||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||||
payload.target = 'participation';
|
payload.target = 'participation';
|
||||||
this.$store.dispatch('patchOnTheFly', payload);
|
this.$store.dispatch('patchOnTheFly', payload)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import VueMultiselect from 'vue-multiselect';
|
import VueMultiselect from 'vue-multiselect';
|
||||||
import { getUsers, whoami } from '../api';
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
import { mapState } from 'vuex';
|
import { mapState } from 'vuex';
|
||||||
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge";
|
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge";
|
||||||
|
|
||||||
@ -76,14 +76,26 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
updateReferrer(value) {
|
updateReferrer(value) {
|
||||||
//console.log('value', value);
|
//console.log('value', value);
|
||||||
this.$store.dispatch('updateReferrer', value);
|
this.$store.dispatch('updateReferrer', value)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
assignMe() {
|
assignMe() {
|
||||||
//console.log('assign me');
|
const url = `/api/1.0/main/whoami.json`;
|
||||||
whoami().then(me => new Promise((resolve, reject) => {
|
makeFetch('GET', url)
|
||||||
this.$store.dispatch('updateReferrer', me);
|
.then(response => {
|
||||||
resolve();
|
this.$store.dispatch('updateReferrer', response);
|
||||||
}));
|
return response;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
this.$toast.open({message: error.body})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
</third-party-render-box>
|
</third-party-render-box>
|
||||||
</template>
|
</template>
|
||||||
</confidential>
|
</confidential>
|
||||||
|
|
||||||
<confidential v-else-if="accompanyingCourse.requestor.type === 'person'">
|
<confidential v-else-if="accompanyingCourse.requestor.type === 'person'">
|
||||||
<template v-slot:confidential-content>
|
<template v-slot:confidential-content>
|
||||||
<person-render-box render="bloc"
|
<person-render-box render="bloc"
|
||||||
@ -117,12 +117,30 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
</person-render-box>
|
</person-render-box>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li>
|
||||||
|
<button class="btn btn-remove"
|
||||||
|
:title="$t('action.remove')"
|
||||||
|
@click="removeRequestor">
|
||||||
|
{{ $t('action.remove') }}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<label class="chill-no-data-statement">{{ $t('requestor.counter') }}</label>
|
<label class="chill-no-data-statement">{{ $t('requestor.counter') }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="accompanyingCourse.requestor === null && suggestedEntities.length > 0">
|
||||||
|
<ul class="list-suggest add-items">
|
||||||
|
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
|
||||||
|
<span>{{ p.text }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<add-persons v-if="accompanyingCourse.requestor === null"
|
<add-persons v-if="accompanyingCourse.requestor === null"
|
||||||
buttonTitle="requestor.add_requestor"
|
buttonTitle="requestor.add_requestor"
|
||||||
@ -143,6 +161,7 @@ import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
|
|||||||
import PersonRenderBox from '../../_components/Entity/PersonRenderBox.vue';
|
import PersonRenderBox from '../../_components/Entity/PersonRenderBox.vue';
|
||||||
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/ThirdPartyRenderBox.vue';
|
||||||
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
|
import Confidential from 'ChillMainAssets/vuejs/_components/Confidential.vue';
|
||||||
|
import { mapState } from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Requestor',
|
name: 'Requestor',
|
||||||
@ -167,12 +186,30 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
suggestedEntities: state => {
|
||||||
|
return [
|
||||||
|
...state.accompanyingCourse.participations.map(p => p.person),
|
||||||
|
...state.accompanyingCourse.resources.map(r => r.resource)
|
||||||
|
]
|
||||||
|
.filter((e) => e !== null)
|
||||||
|
// filter for same entity appearing twice
|
||||||
|
.filter((e, index, suggested) => {
|
||||||
|
for (let i = 0; i < suggested.length; i = i+1) {
|
||||||
|
if (i < index && e.id === suggested[i].id && e.type === suggested[i].type) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}),
|
||||||
accompanyingCourse() {
|
accompanyingCourse() {
|
||||||
return this.$store.state.accompanyingCourse
|
return this.$store.state.accompanyingCourse
|
||||||
},
|
},
|
||||||
isAnonymous: {
|
isAnonymous: {
|
||||||
set(value) {
|
set(value) {
|
||||||
//console.log('requestorIsAnonymous value',value);
|
|
||||||
this.$store.dispatch('requestorIsAnonymous', value);
|
this.$store.dispatch('requestorIsAnonymous', value);
|
||||||
},
|
},
|
||||||
get() {
|
get() {
|
||||||
@ -183,18 +220,53 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
removeRequestor() {
|
removeRequestor() {
|
||||||
//console.log('@@ CLICK remove requestor: item');
|
//console.log('@@ CLICK remove requestor: item');
|
||||||
this.$store.dispatch('removeRequestor');
|
this.$store.dispatch('removeRequestor')
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
addNewPersons({ selected, modal }) {
|
addNewPersons({ selected, modal }) {
|
||||||
//console.log('@@@ CLICK button addNewPersons', selected);
|
//console.log('@@@ CLICK button addNewPersons', selected);
|
||||||
this.$store.dispatch('addRequestor', selected.shift());
|
this.$store.dispatch('addRequestor', selected.shift())
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||||
modal.showModal = false;
|
modal.showModal = false;
|
||||||
},
|
},
|
||||||
saveFormOnTheFly(payload) {
|
saveFormOnTheFly(payload) {
|
||||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||||
payload.target = 'requestor';
|
payload.target = 'requestor';
|
||||||
this.$store.dispatch('patchOnTheFly', payload);
|
this.$store.dispatch('patchOnTheFly', payload)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
addSuggestedEntity(e) {
|
||||||
|
this.$store.dispatch('addRequestor', { result: e, type: e.type })
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
uniqueId(e) {
|
||||||
|
return `${e.type}-${e.id}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,15 @@
|
|||||||
@remove="removeResource">
|
@remove="removeResource">
|
||||||
</resource-item>
|
</resource-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="suggestedEntities.length > 0">
|
||||||
|
<ul class="list-suggest add-items">
|
||||||
|
<li v-for="p in suggestedEntities" :key="uniqueId(p)" @click="addSuggestedEntity(p)">
|
||||||
|
<span>{{ p.text }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<add-persons
|
<add-persons
|
||||||
buttonTitle="resources.add_resources"
|
buttonTitle="resources.add_resources"
|
||||||
@ -57,21 +66,79 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: mapState({
|
computed: mapState({
|
||||||
resources: state => state.accompanyingCourse.resources,
|
resources: state => state.accompanyingCourse.resources,
|
||||||
counter: state => state.accompanyingCourse.resources.length
|
counter: state => state.accompanyingCourse.resources.length,
|
||||||
|
suggestedEntities: state => [
|
||||||
|
state.accompanyingCourse.requestor,
|
||||||
|
...state.accompanyingCourse.participations.map(p => p.person),
|
||||||
|
]
|
||||||
|
.filter((e) => e !== null)
|
||||||
|
.filter(
|
||||||
|
(e) => {
|
||||||
|
if (e.type === 'person') {
|
||||||
|
return !state.accompanyingCourse.resources
|
||||||
|
.filter((r) => r.resource.type === 'person')
|
||||||
|
.map((r) => r.resource.id).includes(e.id)
|
||||||
|
}
|
||||||
|
if (e.type === 'thirdparty') {
|
||||||
|
return !state.accompanyingCourse.resources
|
||||||
|
.filter((r) => r.resource.type === 'thirdparty')
|
||||||
|
.map((r) => r.resource.id).includes(e.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// filter persons appearing twice in requestor and resources
|
||||||
|
.filter(
|
||||||
|
(e, index, suggested) => {
|
||||||
|
for (let i = 0; i < suggested.length; i = i+1) {
|
||||||
|
if (i < index && e.id === suggested[i].id) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
methods: {
|
methods: {
|
||||||
removeResource(item) {
|
removeResource(item) {
|
||||||
//console.log('@@ CLICK remove resource: item', item);
|
//console.log('@@ CLICK remove resource: item', item);
|
||||||
this.$store.dispatch('removeResource', item);
|
this.$store.dispatch('removeResource', item)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
addNewPersons({ selected, modal }) {
|
addNewPersons({ selected, modal }) {
|
||||||
//console.log('@@@ CLICK button addNewPersons', selected);
|
//console.log('@@@ CLICK button addNewPersons', selected);
|
||||||
selected.forEach(function(item) {
|
selected.forEach(function(item) {
|
||||||
this.$store.dispatch('addResource', item);
|
this.$store.dispatch('addResource', item)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: violations})
|
||||||
|
}
|
||||||
|
});
|
||||||
}, this
|
}, this
|
||||||
);
|
);
|
||||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||||
modal.showModal = false;
|
modal.showModal = false;
|
||||||
|
},
|
||||||
|
addSuggestedEntity(e) {
|
||||||
|
this.$store.dispatch('addResource', { result: e, type: e.type})
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
uniqueId(e) {
|
||||||
|
return `${e.type}-${e.id}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,14 @@ export default {
|
|||||||
saveFormOnTheFly(payload) {
|
saveFormOnTheFly(payload) {
|
||||||
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
console.log('saveFormOnTheFly: type', payload.type, ', data', payload.data);
|
||||||
payload.target = 'resource';
|
payload.target = 'resource';
|
||||||
this.$store.dispatch('patchOnTheFly', payload);
|
this.$store.dispatch('patchOnTheFly', payload)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
<h2><a id="section-60"></a>{{ $t('scopes.title') }}</h2>
|
<h2><a id="section-60"></a>{{ $t('scopes.title') }}</h2>
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="form-check" v-for="s in scopes">
|
<div class="form-check" v-for="s in scopes" :key="s.id">
|
||||||
<input class="form-check-input" type="checkbox" v-model="checkedScopes" :value="s" />
|
<input class="form-check-input" type="checkbox" v-model="checkedScopes" :value="s"/>
|
||||||
<label class="form-check-label">
|
<label class="form-check-label">
|
||||||
{{ s.name.fr }}
|
{{ s.name.fr }}
|
||||||
</label>
|
</label>
|
||||||
@ -37,10 +37,22 @@ export default {
|
|||||||
return this.$store.state.accompanyingCourse.scopes;
|
return this.$store.state.accompanyingCourse.scopes;
|
||||||
},
|
},
|
||||||
set: function(v) {
|
set: function(v) {
|
||||||
this.$store.dispatch('setScopes', v);
|
this.$store.dispatch('setScopes', v)
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
methods: {
|
||||||
|
restore() {
|
||||||
|
console.log('restore');
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import VueMultiselect from 'vue-multiselect';
|
import VueMultiselect from 'vue-multiselect';
|
||||||
import { getSocialIssues } from '../api';
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
import {mapGetters, mapState} from 'vuex';
|
import {mapGetters, mapState} from 'vuex';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -54,14 +54,26 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getOptions() {
|
getOptions() {
|
||||||
getSocialIssues().then(response => new Promise((resolve, reject) => {
|
const url = `/api/1.0/person/social-work/social-issue.json`;
|
||||||
//console.log('get socialIssues', response.results);
|
makeFetch('GET', url)
|
||||||
this.options = response.results;
|
.then(response => {
|
||||||
resolve();
|
this.options = response.results;
|
||||||
})).catch(error => this.$store.commit('catchError', error));
|
return response;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
this.$toast.open({message: error.txt})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
updateSocialIssues(value) {
|
updateSocialIssues(value) {
|
||||||
this.$store.dispatch('updateSocialIssues', this.transformValue(value));
|
this.$store.dispatch('updateSocialIssues', this.transformValue(value))
|
||||||
|
.catch(({name, violations}) => {
|
||||||
|
if (name === 'ValidationException' || name === 'AccessException') {
|
||||||
|
violations.forEach((violation) => this.$toast.open({message: violation}));
|
||||||
|
} else {
|
||||||
|
this.$toast.open({message: 'An error occurred'})
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
transformValue(updated) {
|
transformValue(updated) {
|
||||||
let stored = this.value;
|
let stored = this.value;
|
||||||
@ -70,8 +82,6 @@ export default {
|
|||||||
let method = (typeof removed === 'undefined') ? 'POST' : 'DELETE';
|
let method = (typeof removed === 'undefined') ? 'POST' : 'DELETE';
|
||||||
let changed = (typeof removed === 'undefined') ? added : removed;
|
let changed = (typeof removed === 'undefined') ? added : removed;
|
||||||
let body = { type: "social_issue", id: changed.id };
|
let body = { type: "social_issue", id: changed.id };
|
||||||
//console.log('body', body);
|
|
||||||
//console.log('@@@', method, changed.text);
|
|
||||||
let payload = updated;
|
let payload = updated;
|
||||||
return { payload, body, method };
|
return { payload, body, method };
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,8 @@ import { createApp } from 'vue'
|
|||||||
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
|
import { _createI18n } from 'ChillMainAssets/vuejs/_js/i18n'
|
||||||
import { appMessages } from './js/i18n'
|
import { appMessages } from './js/i18n'
|
||||||
import { initPromise } from './store'
|
import { initPromise } from './store'
|
||||||
|
import VueToast from 'vue-toast-notification';
|
||||||
|
import 'vue-toast-notification/dist/theme-sugar.css';
|
||||||
import App from './App.vue';
|
import App from './App.vue';
|
||||||
import Banner from './components/Banner.vue';
|
import Banner from './components/Banner.vue';
|
||||||
|
|
||||||
@ -21,8 +22,14 @@ if (root === 'app') {
|
|||||||
})
|
})
|
||||||
.use(store)
|
.use(store)
|
||||||
.use(i18n)
|
.use(i18n)
|
||||||
|
.use(VueToast, {
|
||||||
|
position: "top",
|
||||||
|
type: "error",
|
||||||
|
duration: 5000,
|
||||||
|
dismissible: true
|
||||||
|
})
|
||||||
.component('app', App)
|
.component('app', App)
|
||||||
.mount('#accompanying-course');
|
.mount('#accompanying-course')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,20 +1,13 @@
|
|||||||
import 'es6-promise/auto';
|
import 'es6-promise/auto';
|
||||||
import { createStore } from 'vuex';
|
import { createStore } from 'vuex';
|
||||||
import { fetchScopes } from 'ChillMainAssets/lib/api/scope.js';
|
import { fetchScopes } from 'ChillMainAssets/lib/api/apiMethods.js';
|
||||||
import { getAccompanyingCourse,
|
import { getAccompanyingCourse,
|
||||||
patchAccompanyingCourse,
|
|
||||||
confirmAccompanyingCourse,
|
|
||||||
postParticipation,
|
|
||||||
postRequestor,
|
|
||||||
postResource,
|
|
||||||
postSocialIssue,
|
|
||||||
addScope,
|
|
||||||
removeScope,
|
|
||||||
getReferrersSuggested,
|
getReferrersSuggested,
|
||||||
getUsers,
|
getUsers,
|
||||||
} from '../api';
|
} from '../api';
|
||||||
import { patchPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
import { patchPerson } from "ChillPersonAssets/vuejs/_api/OnTheFly";
|
||||||
import { patchThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
import { patchThirdparty } from "ChillThirdPartyAssets/vuejs/_api/OnTheFly";
|
||||||
|
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
|
||||||
|
|
||||||
|
|
||||||
const debug = process.env.NODE_ENV !== 'production';
|
const debug = process.env.NODE_ENV !== 'production';
|
||||||
@ -44,6 +37,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
referrersSuggested: [],
|
referrersSuggested: [],
|
||||||
// all the users available
|
// all the users available
|
||||||
users: [],
|
users: [],
|
||||||
|
permissions: {}
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
isParticipationValid(state) {
|
isParticipationValid(state) {
|
||||||
@ -77,7 +71,14 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
|
canTogglePermission(state) {
|
||||||
|
if (state.permissions.roles) {
|
||||||
|
return state.permissions.roles['CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
catchError(state, error) {
|
catchError(state, error) {
|
||||||
@ -88,11 +89,11 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
//console.log('### mutation: remove participation', participation.id);
|
//console.log('### mutation: remove participation', participation.id);
|
||||||
state.accompanyingCourse.participations = state.accompanyingCourse.participations.filter(element => element !== participation);
|
state.accompanyingCourse.participations = state.accompanyingCourse.participations.filter(element => element !== participation);
|
||||||
},
|
},
|
||||||
closeParticipation(state, { participation, payload }) {
|
closeParticipation(state, { response, payload }) {
|
||||||
//console.log('### mutation: close item', { participation, payload });
|
//console.log('### mutation: close item', { participation, payload });
|
||||||
// find row position and replace by closed participation
|
// find row position and replace by closed participation
|
||||||
state.accompanyingCourse.participations.splice(
|
state.accompanyingCourse.participations.splice(
|
||||||
state.accompanyingCourse.participations.findIndex(element => element === payload), 1, participation
|
state.accompanyingCourse.participations.findIndex(element => element === payload), 1, response
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
addParticipation(state, participation) {
|
addParticipation(state, participation) {
|
||||||
@ -208,6 +209,10 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
return u;
|
return u;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setPermissions(state, permissions) {
|
||||||
|
state.permissions = permissions;
|
||||||
|
// console.log('permissions', state.permissions);
|
||||||
|
},
|
||||||
updateLocation(state, r) {
|
updateLocation(state, r) {
|
||||||
//console.log('### mutation: set location attributes', r);
|
//console.log('### mutation: set location attributes', r);
|
||||||
state.accompanyingCourse.locationStatus = r.locationStatus;
|
state.accompanyingCourse.locationStatus = r.locationStatus;
|
||||||
@ -240,67 +245,117 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
//QUESTION: does this serve a purpose? Participations can be closed...
|
||||||
removeParticipation({ commit }, payload) {
|
removeParticipation({ commit }, payload) {
|
||||||
commit('removeParticipation', payload);
|
commit('removeParticipation', payload);
|
||||||
// fetch DELETE request...
|
// fetch DELETE request...
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Add/close participation
|
||||||
|
*/
|
||||||
closeParticipation({ commit }, payload) {
|
closeParticipation({ commit }, payload) {
|
||||||
//console.log('## action: fetch delete participation: payload', payload);
|
const body = { type: payload.person.type, id: payload.person.id };
|
||||||
postParticipation(id, payload.person, 'DELETE')
|
const url = `/api/1.0/person/accompanying-course/${id}/participation.json`;
|
||||||
.then(participation => new Promise((resolve, reject) => {
|
|
||||||
commit('closeParticipation', { participation, payload });
|
return makeFetch('DELETE', url, body)
|
||||||
resolve();
|
.then((response) => {
|
||||||
})).catch((error) => { commit('catchError', error) });
|
commit('closeParticipation', { response, payload });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
addParticipation({ commit }, payload) {
|
addParticipation({ commit }, payload) {
|
||||||
//console.log('## action: fetch post participation (select item): payload', payload);
|
const body = { type: payload.result.type, id: payload.result.id };
|
||||||
postParticipation(id, payload.result, 'POST')
|
const url = `/api/1.0/person/accompanying-course/${id}/participation.json`;
|
||||||
.then(participation => new Promise((resolve, reject) => {
|
|
||||||
commit('addParticipation', participation);
|
return makeFetch('POST', url, body)
|
||||||
resolve();
|
.then((response) => {
|
||||||
})).catch((error) => { commit('catchError', error) });
|
commit('addParticipation', response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Add/remove/display anonymous requestor
|
||||||
|
*/
|
||||||
removeRequestor({ commit, dispatch }) {
|
removeRequestor({ commit, dispatch }) {
|
||||||
//console.log('## action: fetch delete requestor');
|
const body = {};
|
||||||
postRequestor(id, null, 'DELETE')
|
const url = `/api/1.0/person/accompanying-course/${id}/requestor.json`;
|
||||||
.then(requestor => new Promise((resolve, reject) => {
|
|
||||||
commit('removeRequestor');
|
return makeFetch('DELETE', url, body)
|
||||||
dispatch('requestorIsAnonymous', false);
|
.then((response) => {
|
||||||
resolve();
|
commit('removeRequestor');
|
||||||
})).catch((error) => { commit('catchError', error) });
|
dispatch('requestorIsAnonymous', false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
addRequestor({ commit }, payload) {
|
addRequestor({ commit }, payload) {
|
||||||
//console.log('## action: fetch post requestor: payload', payload);
|
const body = payload ? { type: payload.result.type, id: payload.result.id } : {};
|
||||||
postRequestor(id, payload.result, 'POST')
|
const url = `/api/1.0/person/accompanying-course/${id}/requestor.json`;
|
||||||
.then(requestor => new Promise((resolve, reject) => {
|
|
||||||
commit('addRequestor', requestor);
|
return makeFetch('POST', url, body)
|
||||||
resolve();
|
.then((response) => {
|
||||||
})).catch((error) => { commit('catchError', error) });
|
commit('addRequestor', response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
requestorIsAnonymous({ commit }, payload) {
|
requestorIsAnonymous({ commit }, payload) {
|
||||||
//console.log('## action: fetch patch AccompanyingCourse: payload', payload);
|
const url = `/api/1.0/person/accompanying-course/${id}.json`
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", requestorAnonymous: payload })
|
const body = { type: "accompanying_period", requestorAnonymous: payload }
|
||||||
.then(course => new Promise((resolve, reject) => {
|
|
||||||
commit('requestorIsAnonymous', course.requestorAnonymous)
|
return makeFetch('PATCH', url, body)
|
||||||
resolve();
|
.then((response) => {
|
||||||
})).catch((error) => { commit('catchError', error) });
|
commit('requestorIsAnonymous', response.requestorAnonymous);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Add/remove resource
|
||||||
|
*/
|
||||||
removeResource({ commit }, payload) {
|
removeResource({ commit }, payload) {
|
||||||
//console.log('## action: fetch postResource: payload', payload);
|
const body = { type: "accompanying_period_resource" };
|
||||||
postResource(id, payload, 'DELETE')
|
body['id'] = payload.id;
|
||||||
.then(resource => new Promise((resolve, reject) => {
|
const url = `/api/1.0/person/accompanying-course/${id}/resource.json`;
|
||||||
commit('removeResource', payload) // mieux un retour de l'objet !
|
|
||||||
resolve();
|
return makeFetch('DELETE', url, body)
|
||||||
})).catch((error) => { commit('catchError', error) });
|
.then((response) => {
|
||||||
|
commit('removeResource', payload)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
addResource({ commit }, payload) {
|
addResource({ commit }, payload) {
|
||||||
//console.log('## action: fetch postResource: payload', payload);
|
const body = { type: "accompanying_period_resource" };
|
||||||
postResource(id, payload.result, 'POST')
|
body['resource'] = { type: payload.result.type, id: payload.result.id };
|
||||||
.then(resource => new Promise((resolve, reject) => {
|
const url = `/api/1.0/person/accompanying-course/${id}/resource.json`;
|
||||||
commit('addResource', resource)
|
|
||||||
resolve();
|
return makeFetch('POST', url, body)
|
||||||
})).catch((error) => { commit('catchError', error) });
|
.then((response) => {
|
||||||
|
commit('addResource', response);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* On The Fly
|
||||||
|
*/
|
||||||
patchOnTheFly({ commit }, payload) {
|
patchOnTheFly({ commit }, payload) {
|
||||||
// TODO should be into the dedicated component, no ? JF
|
// TODO should be into the dedicated component, no ? JF
|
||||||
console.log('## action: patch OnTheFly', payload);
|
console.log('## action: patch OnTheFly', payload);
|
||||||
@ -334,29 +389,48 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Update accompanying course intensity/emergency/confidentiality
|
||||||
|
*/
|
||||||
toggleIntensity({ commit }, payload) {
|
toggleIntensity({ commit }, payload) {
|
||||||
//console.log(payload);
|
const url = `/api/1.0/person/accompanying-course/${id}.json`
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", intensity: payload })
|
const body = { type: "accompanying_period", 'intensity': payload }
|
||||||
.then(course => new Promise((resolve, reject) => {
|
|
||||||
commit('toggleIntensity', course.intensity);
|
return makeFetch('PATCH', url, body)
|
||||||
resolve();
|
.then((response) => {
|
||||||
})).catch((error) => { commit('catchError', error) });
|
commit('toggleIntensity', response.intensity);
|
||||||
|
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
toggleEmergency({ commit }, payload) {
|
toggleEmergency({ commit }, payload) {
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", emergency: payload })
|
const url = `/api/1.0/person/accompanying-course/${id}.json`
|
||||||
.then(course => new Promise((resolve, reject) => {
|
const body = { type: "accompanying_period", emergency: payload }
|
||||||
commit('toggleEmergency', course.emergency);
|
|
||||||
return dispatch('setRefererresAvailable');
|
return makeFetch('PATCH', url, body)
|
||||||
}))
|
.then((response) => {
|
||||||
.then(() => Promise.resolve())
|
commit('toggleEmergency', response.emergency);
|
||||||
.catch((error) => { commit('catchError', error) });
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
toggleConfidential({ commit }, payload) {
|
toggleConfidential({ commit }, payload) {
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", confidential: payload })
|
const url = `/api/1.0/person/accompanying-course/${id}.json`
|
||||||
.then(course => new Promise((resolve, reject) => {
|
const body = { type: "accompanying_period", confidential: payload }
|
||||||
commit('toggleConfidential', course.confidential);
|
|
||||||
resolve();
|
return makeFetch('PATCH', url, body)
|
||||||
})).catch((error) => { commit('catchError', error) });
|
.then((response) => {
|
||||||
|
commit('toggleConfidential', response.confidential);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Handle the checked/unchecked scopes
|
* Handle the checked/unchecked scopes
|
||||||
@ -411,19 +485,24 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
let lengthAfterOperation = currentServerScopesIds.length + addedScopesIds.length
|
let lengthAfterOperation = currentServerScopesIds.length + addedScopesIds.length
|
||||||
- removedScopesIds.length;
|
- removedScopesIds.length;
|
||||||
|
|
||||||
if (lengthAfterOperation > 0 || (lengthAfterOperation === 0 && state.scopesAtStart.length === 0) ) {
|
return dispatch('updateScopes', {
|
||||||
return dispatch('updateScopes', {
|
addedScopesIds, removedScopesIds
|
||||||
addedScopesIds, removedScopesIds
|
})
|
||||||
}).then(() => {
|
.catch(error => {
|
||||||
// warning: when the operation of dispatch are too slow, the user may check / uncheck before
|
throw error;
|
||||||
// the end of the synchronisation with the server (done by dispatch operation). Then, it leads to
|
})
|
||||||
// check/uncheck in the UI. I do not know of to avoid it.
|
.then(() => {
|
||||||
commit('setScopes', scopes);
|
// warning: when the operation of dispatch are too slow, the user may check / uncheck before
|
||||||
return Promise.resolve();
|
// the end of the synchronisation with the server (done by dispatch operation). Then, it leads to
|
||||||
}).then(() => {
|
// check/uncheck in the UI. I do not know of to avoid it.
|
||||||
return dispatch('fetchReferrersSuggested');
|
commit('setScopes', scopes);
|
||||||
});
|
return Promise.resolve();
|
||||||
} else {
|
})
|
||||||
|
.then(() => {
|
||||||
|
return dispatch('fetchReferrersSuggested');
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
else {
|
||||||
return dispatch('setScopes', state.scopesAtStart).then(() => {
|
return dispatch('setScopes', state.scopesAtStart).then(() => {
|
||||||
commit('setScopes', scopes);
|
commit('setScopes', scopes);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@ -431,6 +510,7 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
return dispatch('fetchReferrersSuggested');
|
return dispatch('fetchReferrersSuggested');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* Internal function for the store to effectively update scopes.
|
* Internal function for the store to effectively update scopes.
|
||||||
@ -446,59 +526,99 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
*/
|
*/
|
||||||
updateScopes({ state, commit }, { addedScopesIds, removedScopesIds }) {
|
updateScopes({ state, commit }, { addedScopesIds, removedScopesIds }) {
|
||||||
let promises = [];
|
let promises = [];
|
||||||
|
const url = `/api/1.0/person/accompanying-course/${state.accompanyingCourse.id}/scope.json`;
|
||||||
state.scopes.forEach(scope => {
|
state.scopes.forEach(scope => {
|
||||||
|
const body = {
|
||||||
|
id: scope.id,
|
||||||
|
type: scope.type
|
||||||
|
};
|
||||||
|
|
||||||
if (addedScopesIds.includes(scope.id)) {
|
if (addedScopesIds.includes(scope.id)) {
|
||||||
promises.push(addScope(state.accompanyingCourse.id, scope).then(() => {
|
promises.push(
|
||||||
commit('addScopeAtBackend', scope);
|
makeFetch('POST', url, body)
|
||||||
return Promise.resolve();
|
.then((response) => {
|
||||||
}));
|
commit('addScopeAtBackend', scope);
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (removedScopesIds.includes(scope.id)) {
|
if (removedScopesIds.includes(scope.id)) {
|
||||||
promises.push(removeScope(state.accompanyingCourse.id, scope).then(() => {
|
promises.push(
|
||||||
commit('removeScopeAtBackend', scope);
|
makeFetch('DELETE', url, body)
|
||||||
return Promise.resolve();
|
.then((response) => {
|
||||||
}));
|
commit('removeScopeAtBackend', scope);
|
||||||
|
return response;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
},
|
},
|
||||||
postFirstComment({ commit }, payload) {
|
postFirstComment({ commit }, payload) {
|
||||||
//console.log('## action: postFirstComment: payload', payload);
|
const url = `/api/1.0/person/accompanying-course/${id}.json`
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", initialComment: payload })
|
const body = { type: "accompanying_period", initialComment: payload }
|
||||||
.then(course => new Promise((resolve, reject) => {
|
|
||||||
commit('postFirstComment', course.initialComment);
|
return makeFetch('PATCH', url, body)
|
||||||
resolve();
|
.then((response) => {
|
||||||
})).catch((error) => { commit('catchError', error) });
|
commit('postFirstComment', response.initialComment);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
updateSocialIssues({ state, commit, dispatch }, { payload, body, method }) {
|
updateSocialIssues({ state, commit, dispatch }, { payload, body, method }) {
|
||||||
//console.log('## action: payload', { payload, body, method });
|
const url = `/api/1.0/person/accompanying-course/${id}/socialissue.json`;
|
||||||
postSocialIssue(id, body, method)
|
return makeFetch(method, url, body)
|
||||||
.then(response => new Promise((resolve, reject) => {
|
.then((response) => {
|
||||||
//console.log('response', response);
|
commit('updateSocialIssues', payload);
|
||||||
commit('updateSocialIssues', payload);
|
})
|
||||||
resolve();
|
.then(() => {
|
||||||
})).then(() => {
|
return getAccompanyingCourse(state.accompanyingCourse.id)
|
||||||
return getAccompanyingCourse(state.accompanyingCourse.id);
|
})
|
||||||
}).then(accompanying_course => {
|
.then(accompanying_course => {
|
||||||
commit('refreshSocialIssues', accompanying_course.socialIssues);
|
commit('refreshSocialIssues', accompanying_course.socialIssues);
|
||||||
dispatch('fetchReferrersSuggested');
|
dispatch('fetchReferrersSuggested');
|
||||||
})
|
})
|
||||||
.catch((error) => { commit('catchError', error) });
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
updateOrigin({ commit }, payload) {
|
updateOrigin({ commit }, payload) {
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", origin: { id: payload.id, type: payload.type } })
|
const url = `/api/1.0/person/accompanying-course/${id}.json`
|
||||||
.then(course => new Promise((resolve, reject) => {
|
const body = { type: "accompanying_period", origin: { id: payload.id, type: payload.type }}
|
||||||
commit('updateOrigin', course.origin);
|
|
||||||
resolve();
|
return makeFetch('PATCH', url, body)
|
||||||
})).catch((error) => { commit('catchError', error) });
|
.then((response) => {
|
||||||
|
commit('updateOrigin', response.origin);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
updateReferrer({ commit }, payload) {
|
updateReferrer({ commit }, payload) {
|
||||||
patchAccompanyingCourse(id, { type: "accompanying_period", user: { id: payload.id, type: payload.type } })
|
const url = `/api/1.0/person/accompanying-course/${id}.json`
|
||||||
.then(course => new Promise((resolve, reject) => {
|
const body = { type: "accompanying_period", user: { id: payload.id, type: payload.type }}
|
||||||
commit('updateReferrer', course.user);
|
|
||||||
resolve();
|
return makeFetch('PATCH', url, body)
|
||||||
})).catch((error) => { commit('catchError', error) });
|
.then((response) => {
|
||||||
|
commit('updateReferrer', response.user);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
async fetchReferrersSuggested({ state, commit}) {
|
async fetchReferrersSuggested({ state, commit}) {
|
||||||
let users = await getReferrersSuggested(state.accompanyingCourse);
|
let users = await getReferrersSuggested(state.accompanyingCourse);
|
||||||
@ -517,8 +637,36 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
let users = await getUsers();
|
let users = await getUsers();
|
||||||
commit('setUsers', users);
|
commit('setUsers', users);
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* By adding more roles to body['roles'], more permissions can be checked.
|
||||||
|
*/
|
||||||
|
fetchPermissions({commit}) {
|
||||||
|
const url = '/api/1.0/main/permissions/info.json';
|
||||||
|
const body = {
|
||||||
|
"object": {
|
||||||
|
"type": "accompanying_period",
|
||||||
|
"id": id
|
||||||
|
},
|
||||||
|
"class": "Chill\\PersonBundle\\Entity\\AccompanyingPeriod",
|
||||||
|
"roles": [
|
||||||
|
"CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeFetch('POST', url, body)
|
||||||
|
.then((response) => {
|
||||||
|
commit('setPermissions', response);
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
|
},
|
||||||
updateLocation({ commit, dispatch }, payload) {
|
updateLocation({ commit, dispatch }, payload) {
|
||||||
//console.log('## action: updateLocation', payload.locationStatusTo);
|
//console.log('## action: updateLocation', payload.locationStatusTo);
|
||||||
|
const url = `/api/1.0/person/accompanying-course/${payload.targetId}.json`;
|
||||||
let body = { 'type': payload.target, 'id': payload.targetId };
|
let body = { 'type': payload.target, 'id': payload.targetId };
|
||||||
let location = {};
|
let location = {};
|
||||||
if (payload.locationStatusTo === 'person') { // patch for person address (don't remove addressLocation)
|
if (payload.locationStatusTo === 'person') { // patch for person address (don't remove addressLocation)
|
||||||
@ -531,26 +679,31 @@ let initPromise = Promise.all([scopesPromise, accompanyingCoursePromise])
|
|||||||
location = { 'personLocation': null };
|
location = { 'personLocation': null };
|
||||||
}
|
}
|
||||||
Object.assign(body, location);
|
Object.assign(body, location);
|
||||||
patchAccompanyingCourse(payload.targetId, body)
|
makeFetch('PATCH', url, body)
|
||||||
.then(accompanyingCourse => new Promise((resolve, reject) => {
|
.then((response) => {
|
||||||
commit('updateLocation', {
|
commit('updateLocation', {
|
||||||
location: accompanyingCourse.location,
|
location: response.location,
|
||||||
locationStatus: accompanyingCourse.locationStatus,
|
locationStatus: response.locationStatus,
|
||||||
personLocation: accompanyingCourse.personLocation
|
personLocation: response.personLocation
|
||||||
});
|
});
|
||||||
resolve();
|
|
||||||
dispatch('fetchReferrersSuggested');
|
dispatch('fetchReferrersSuggested');
|
||||||
})).catch((error) => { commit('catchError', error) });
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
},
|
},
|
||||||
confirmAccompanyingCourse({ commit }) {
|
confirmAccompanyingCourse({ commit }) {
|
||||||
//console.log('## action: confirmAccompanyingCourse');
|
const url = `/api/1.0/person/accompanying-course/${id}/confirm.json`
|
||||||
confirmAccompanyingCourse(id)
|
makeFetch('POST', url)
|
||||||
.then(response => new Promise((resolve, reject) => {
|
.then((response) => {
|
||||||
window.location.replace(`/fr/parcours/${id}`);
|
window.location.replace(`/fr/parcours/${id}`);
|
||||||
//console.log('fetch resolve');
|
commit('confirmAccompanyingCourse', response);
|
||||||
commit('confirmAccompanyingCourse', response);
|
})
|
||||||
resolve();
|
.catch((error) => {
|
||||||
})).catch((error) => { commit('catchError', error) });
|
commit('catchError', error);
|
||||||
|
throw error;
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -31,6 +31,7 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
self::EDIT,
|
self::EDIT,
|
||||||
self::DELETE,
|
self::DELETE,
|
||||||
self::FULL,
|
self::FULL,
|
||||||
|
self::TOGGLE_CONFIDENTIAL_ALL,
|
||||||
];
|
];
|
||||||
|
|
||||||
public const CREATE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_CREATE';
|
public const CREATE = 'CHILL_PERSON_ACCOMPANYING_PERIOD_CREATE';
|
||||||
@ -53,6 +54,13 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
*/
|
*/
|
||||||
public const SEE_DETAILS = 'CHILL_PERSON_ACCOMPANYING_PERIOD_SEE_DETAILS';
|
public const SEE_DETAILS = 'CHILL_PERSON_ACCOMPANYING_PERIOD_SEE_DETAILS';
|
||||||
|
|
||||||
|
public const TOGGLE_CONFIDENTIAL = 'CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Right to toggle confidentiality.
|
||||||
|
*/
|
||||||
|
public const TOGGLE_CONFIDENTIAL_ALL = 'CHILL_PERSON_ACCOMPANYING_PERIOD_TOGGLE_CONFIDENTIAL_ALL';
|
||||||
|
|
||||||
private Security $security;
|
private Security $security;
|
||||||
|
|
||||||
private VoterHelperInterface $voterHelper;
|
private VoterHelperInterface $voterHelper;
|
||||||
@ -65,7 +73,7 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
$this->voterHelper = $voterHelperFactory
|
$this->voterHelper = $voterHelperFactory
|
||||||
->generate(self::class)
|
->generate(self::class)
|
||||||
->addCheckFor(null, [self::CREATE])
|
->addCheckFor(null, [self::CREATE])
|
||||||
->addCheckFor(AccompanyingPeriod::class, self::ALL)
|
->addCheckFor(AccompanyingPeriod::class, [self::TOGGLE_CONFIDENTIAL, ...self::ALL])
|
||||||
->addCheckFor(Person::class, [self::SEE])
|
->addCheckFor(Person::class, [self::SEE])
|
||||||
->build();
|
->build();
|
||||||
}
|
}
|
||||||
@ -113,6 +121,14 @@ class AccompanyingPeriodVoter extends AbstractChillVoter implements ProvideRoleH
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self::TOGGLE_CONFIDENTIAL === $attribute) {
|
||||||
|
if ($subject->getUser() === $token->getUser()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->voterHelper->voteOnAttribute(self::TOGGLE_CONFIDENTIAL_ALL, $subject, $token);
|
||||||
|
}
|
||||||
|
|
||||||
// if confidential, only the referent can see it
|
// if confidential, only the referent can see it
|
||||||
if ($subject->isConfidential()) {
|
if ($subject->isConfidential()) {
|
||||||
return $token->getUser() === $subject->getUser();
|
return $token->getUser() === $subject->getUser();
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
<?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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Tests\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class AccompanyingPeriodConfidentialTest extends WebTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Setup before the first test of this class (see phpunit doc).
|
||||||
|
*/
|
||||||
|
public static function setUpBeforeClass()
|
||||||
|
{
|
||||||
|
static::bootKernel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup before each test method (see phpunit doc).
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
$this->client = static::createClient([], [
|
||||||
|
'PHP_AUTH_USER' => 'fred',
|
||||||
|
'PHP_AUTH_PW' => 'password',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function dataGenerateRandomAccompanyingCourse()
|
||||||
|
{
|
||||||
|
$maxGenerated = 3;
|
||||||
|
$maxResults = $maxGenerated * 8;
|
||||||
|
|
||||||
|
static::bootKernel();
|
||||||
|
$em = static::$kernel->getContainer()->get('doctrine.orm.entity_manager');
|
||||||
|
$center = $em->getRepository(Center::class)
|
||||||
|
->findOneBy(['name' => 'Center A']);
|
||||||
|
|
||||||
|
$qb = $em->createQueryBuilder();
|
||||||
|
$personIds = $qb
|
||||||
|
->select('p.id')
|
||||||
|
->distinct(true)
|
||||||
|
->from(Person::class, 'p')
|
||||||
|
->join('p.accompanyingPeriodParticipations', 'participation')
|
||||||
|
->join('participation.accompanyingPeriod', 'ap')
|
||||||
|
->andWhere(
|
||||||
|
$qb->expr()->eq('ap.step', ':step')
|
||||||
|
)
|
||||||
|
->andWhere(
|
||||||
|
$qb->expr()->eq('ap.confidential', ':confidential')
|
||||||
|
)
|
||||||
|
->setParameter('step', AccompanyingPeriod::STEP_CONFIRMED)
|
||||||
|
->setParameter('confidential', true)
|
||||||
|
->setMaxResults($maxResults)
|
||||||
|
->getQuery()
|
||||||
|
->getScalarResult();
|
||||||
|
|
||||||
|
// create a random order
|
||||||
|
shuffle($personIds);
|
||||||
|
|
||||||
|
$nbGenerated = 0;
|
||||||
|
|
||||||
|
while ($nbGenerated < $maxGenerated) {
|
||||||
|
$id = array_pop($personIds)['id'];
|
||||||
|
|
||||||
|
$person = $em->getRepository(Person::class)
|
||||||
|
->find($id);
|
||||||
|
$periods = $person->getAccompanyingPeriods();
|
||||||
|
|
||||||
|
yield [array_pop($personIds)['id'], $periods[array_rand($periods)]->getId()];
|
||||||
|
|
||||||
|
++$nbGenerated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider dataGenerateRandomAccompanyingCourse
|
||||||
|
*/
|
||||||
|
public function testRemoveUserWhenConfidential(int $periodId)
|
||||||
|
{
|
||||||
|
$period = self::$container->get(AccompanyingPeriodRepository::class)
|
||||||
|
->find($periodId);
|
||||||
|
$em = static::$kernel->getContainer()->get('doctrine.orm.entity_manager');
|
||||||
|
|
||||||
|
$isConfidential = $period->isConfidential();
|
||||||
|
$step = $period->getStep();
|
||||||
|
|
||||||
|
$initialUser = $period->getUser();
|
||||||
|
|
||||||
|
$user = new stdClass();
|
||||||
|
$user->id = 0;
|
||||||
|
$user->type = 'user';
|
||||||
|
dump($user);
|
||||||
|
|
||||||
|
$this->client->request(
|
||||||
|
Request::METHOD_PATCH,
|
||||||
|
sprintf('/api/1.0/person/accompanying-course/%d.json', $periodId),
|
||||||
|
[], // parameters
|
||||||
|
[], // files
|
||||||
|
[], // server parameters
|
||||||
|
json_encode(['type' => 'accompanying_period', 'user' => $user])
|
||||||
|
);
|
||||||
|
$response = $this->client->getResponse();
|
||||||
|
|
||||||
|
// if ($isConfidential === true && $step === 'CONFIRMED') {
|
||||||
|
$this->assertEquals(422, $response->getStatusCode());
|
||||||
|
// }
|
||||||
|
|
||||||
|
$this->assertEquals(200, $response->getStatusCode());
|
||||||
|
$period = $em->getRepository(AccompanyingPeriod::class)
|
||||||
|
->find($periodId);
|
||||||
|
$this->assertEquals($user, $period->getUser());
|
||||||
|
|
||||||
|
// assign initial user again
|
||||||
|
$period->setUser($initialUser);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
}
|
@ -12,10 +12,11 @@ declare(strict_types=1);
|
|||||||
namespace Validator\Person;
|
namespace Validator\Person;
|
||||||
|
|
||||||
use Chill\MainBundle\Entity\Center;
|
use Chill\MainBundle\Entity\Center;
|
||||||
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
|
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenter;
|
use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenter;
|
||||||
use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenterValidator;
|
use Chill\PersonBundle\Validator\Constraints\Person\PersonHasCenterValidator;
|
||||||
|
use Prophecy\Argument;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
|
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
|
||||||
|
|
||||||
@ -52,9 +53,19 @@ class PersonHasCenterValidatorTest extends ConstraintValidatorTestCase
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$centerResolverDispatcher = $this->createMock(CenterResolverDispatcherInterface::class);
|
$prophecy = $this->prophesize(CenterResolverManagerInterface::class);
|
||||||
|
|
||||||
return new PersonHasCenterValidator($parameterBag, $centerResolverDispatcher);
|
$prophecy->resolveCenters(Argument::type(Person::class), Argument::any())->will(function ($args) {
|
||||||
|
$center = $args[0]->getCenter();
|
||||||
|
|
||||||
|
if ($center instanceof Center) {
|
||||||
|
return [$center];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
|
||||||
|
return new PersonHasCenterValidator($parameterBag, $prophecy->reveal());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getConstraint()
|
protected function getConstraint()
|
||||||
|
@ -32,7 +32,7 @@ class LocationValidityValidator extends ConstraintValidator
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$period instanceof AccompanyingPeriod) {
|
if (!$period instanceof AccompanyingPeriod) {
|
||||||
throw new UnexpectedValueException($value, AccompanyingPeriod::class);
|
throw new UnexpectedValueException($period, AccompanyingPeriod::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($period->getLocationStatus() === 'person') {
|
if ($period->getLocationStatus() === 'person') {
|
||||||
|
@ -18,5 +18,5 @@ use Symfony\Component\Validator\Constraint;
|
|||||||
*/
|
*/
|
||||||
class ParticipationOverlap extends Constraint
|
class ParticipationOverlap extends Constraint
|
||||||
{
|
{
|
||||||
public $message = 'This participation already exists.';
|
public $message = '{{ name }} is already associated to this accompanying course.';
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ namespace Chill\PersonBundle\Validator\Constraints\AccompanyingPeriod;
|
|||||||
|
|
||||||
use Chill\MainBundle\Util\DateRangeCovering;
|
use Chill\MainBundle\Util\DateRangeCovering;
|
||||||
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
|
||||||
|
use Chill\PersonBundle\Templating\Entity\PersonRender;
|
||||||
|
use Chill\ThirdPartyBundle\Templating\Entity\ThirdPartyRender;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\ConstraintValidator;
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
@ -22,6 +24,16 @@ class ParticipationOverlapValidator extends ConstraintValidator
|
|||||||
{
|
{
|
||||||
private const MAX_PARTICIPATION = 1;
|
private const MAX_PARTICIPATION = 1;
|
||||||
|
|
||||||
|
private PersonRender $personRender;
|
||||||
|
|
||||||
|
private ThirdPartyRender $thirdpartyRender;
|
||||||
|
|
||||||
|
public function __construct(PersonRender $personRender, ThirdPartyRender $thirdPartyRender)
|
||||||
|
{
|
||||||
|
$this->personRender = $personRender;
|
||||||
|
$this->thirdpartyRender = $thirdPartyRender;
|
||||||
|
}
|
||||||
|
|
||||||
public function validate($participations, Constraint $constraint)
|
public function validate($participations, Constraint $constraint)
|
||||||
{
|
{
|
||||||
if (!$constraint instanceof ParticipationOverlap) {
|
if (!$constraint instanceof ParticipationOverlap) {
|
||||||
@ -36,7 +48,10 @@ class ParticipationOverlapValidator extends ConstraintValidator
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$overlaps = new DateRangeCovering(self::MAX_PARTICIPATION, $participations[0]->getStartDate()->getTimezone());
|
if (0 === count($participations)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$participationList = [];
|
$participationList = [];
|
||||||
|
|
||||||
foreach ($participations as $participation) {
|
foreach ($participations as $participation) {
|
||||||
@ -51,26 +66,29 @@ class ParticipationOverlapValidator extends ConstraintValidator
|
|||||||
|
|
||||||
foreach ($participationList as $group) {
|
foreach ($participationList as $group) {
|
||||||
if (count($group) > 1) {
|
if (count($group) > 1) {
|
||||||
|
$overlaps = new DateRangeCovering(self::MAX_PARTICIPATION, $participations[0]->getStartDate()->getTimezone());
|
||||||
|
|
||||||
foreach ($group as $p) {
|
foreach ($group as $p) {
|
||||||
$overlaps->add($p->getStartDate(), $p->getEndDate(), $p->getId());
|
$overlaps->add($p->getStartDate(), $p->getEndDate(), $p->getId());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$overlaps->compute();
|
$overlaps->compute();
|
||||||
|
|
||||||
if ($overlaps->hasIntersections()) {
|
if ($overlaps->hasIntersections()) {
|
||||||
foreach ($overlaps->getIntersections() as [$start, $end, $ids]) {
|
foreach ($overlaps->getIntersections() as [$start, $end, $ids]) {
|
||||||
$msg = null === $end ? $constraint->message :
|
$msg = null === $end ? $constraint->message :
|
||||||
$constraint->message;
|
$constraint->message;
|
||||||
|
|
||||||
$this->context->buildViolation($msg)
|
$this->context->buildViolation($msg)
|
||||||
->setParameters([
|
->setParameters([
|
||||||
'{{ start }}' => $start->format('d-m-Y'),
|
'{{ start }}' => $start->format('d-m-Y'),
|
||||||
'{{ end }}' => null === $end ? null : $end->format('d-m-Y'),
|
'{{ end }}' => null === $end ? null : $end->format('d-m-Y'),
|
||||||
'{{ ids }}' => $ids,
|
'{{ ids }}' => $ids,
|
||||||
])
|
'{{ name }}' => $this->personRender->renderString($participation->getPerson(), []),
|
||||||
->addViolation();
|
])
|
||||||
|
->addViolation();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,10 @@ class ResourceDuplicateCheckValidator extends ConstraintValidator
|
|||||||
throw new UnexpectedTypeException($resources, Collection::class);
|
throw new UnexpectedTypeException($resources, Collection::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (0 === count($resources)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$resourceList = [];
|
$resourceList = [];
|
||||||
|
|
||||||
foreach ($resources as $resource) {
|
foreach ($resources as $resource) {
|
||||||
|
@ -11,7 +11,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\PersonBundle\Validator\Constraints\Person;
|
namespace Chill\PersonBundle\Validator\Constraints\Person;
|
||||||
|
|
||||||
use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface;
|
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
@ -22,12 +22,12 @@ class PersonHasCenterValidator extends ConstraintValidator
|
|||||||
{
|
{
|
||||||
private bool $centerRequired;
|
private bool $centerRequired;
|
||||||
|
|
||||||
private CenterResolverDispatcherInterface $centerResolverDispatcher;
|
private CenterResolverManagerInterface $centerResolverManager;
|
||||||
|
|
||||||
public function __construct(ParameterBagInterface $parameterBag, CenterResolverDispatcherInterface $centerResolverDispatcher)
|
public function __construct(ParameterBagInterface $parameterBag, CenterResolverManagerInterface $centerResolverManager)
|
||||||
{
|
{
|
||||||
$this->centerRequired = $parameterBag->get('chill_person')['validation']['center_required'];
|
$this->centerRequired = $parameterBag->get('chill_person')['validation']['center_required'];
|
||||||
$this->centerResolverDispatcher = $centerResolverDispatcher;
|
$this->centerResolverManager = $centerResolverManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function validate($person, Constraint $constraint)
|
public function validate($person, Constraint $constraint)
|
||||||
@ -40,7 +40,7 @@ class PersonHasCenterValidator extends ConstraintValidator
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null === $this->centerResolverDispatcher->resolveCenter($person)) {
|
if ([] === $this->centerResolverManager->resolveCenters($person)) {
|
||||||
$this
|
$this
|
||||||
->context
|
->context
|
||||||
->buildViolation($constraint->message)
|
->buildViolation($constraint->message)
|
||||||
|
@ -1113,6 +1113,44 @@ paths:
|
|||||||
description: "OK"
|
description: "OK"
|
||||||
400:
|
400:
|
||||||
description: "transition cannot be applyed"
|
description: "transition cannot be applyed"
|
||||||
|
|
||||||
|
/1.0/person/accompanying-course/{id}/confidential.json:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- person
|
||||||
|
summary: "Toggle confidentiality 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: "Confidentiality toggle"
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- "accompanying_period"
|
||||||
|
confidential:
|
||||||
|
type: boolean
|
||||||
|
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:
|
||||||
|
@ -43,4 +43,6 @@ household_membership:
|
|||||||
Person with membership covering: Une personne ne peut pas appartenir à deux ménages simultanément. Or, avec cette modification, %person_name% appartiendrait à %nbHousehold% ménages à partir du %from%.
|
Person with membership covering: Une personne ne peut pas appartenir à deux ménages simultanément. Or, avec cette modification, %person_name% appartiendrait à %nbHousehold% ménages à partir du %from%.
|
||||||
|
|
||||||
# Accompanying period
|
# Accompanying period
|
||||||
'{{ name }} is already associated to this accompanying course.': '{{ name }} est déjà associé avec ce parcours.'
|
'{{ name }} is already associated to this accompanying course.': '{{ name }} est déjà associé à ce parcours.'
|
||||||
|
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'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user