diff --git a/src/Bundle/ChillMainBundle/ChillMainBundle.php b/src/Bundle/ChillMainBundle/ChillMainBundle.php
index 91c58f68b..f9e79bc8b 100644
--- a/src/Bundle/ChillMainBundle/ChillMainBundle.php
+++ b/src/Bundle/ChillMainBundle/ChillMainBundle.php
@@ -8,6 +8,7 @@ use Chill\MainBundle\Security\Authorization\ChillVoterInterface;
use Chill\MainBundle\Security\ProvideRoleInterface;
use Chill\MainBundle\Security\Resolver\CenterResolverInterface;
use Chill\MainBundle\Security\Resolver\ScopeResolverInterface;
+use Chill\MainBundle\Templating\Entity\ChillEntityRenderInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Chill\MainBundle\DependencyInjection\CompilerPass\SearchableServicesCompilerPass;
@@ -38,6 +39,8 @@ class ChillMainBundle extends Bundle
->addTag('chill_main.center_resolver');
$container->registerForAutoconfiguration(ScopeResolverInterface::class)
->addTag('chill_main.scope_resolver');
+ $container->registerForAutoconfiguration(ChillEntityRenderInterface::class)
+ ->addTag('chill.render_entity');
$container->addCompilerPass(new SearchableServicesCompilerPass());
$container->addCompilerPass(new ConfigConsistencyCompilerPass());
diff --git a/src/Bundle/ChillMainBundle/Entity/UserJob.php b/src/Bundle/ChillMainBundle/Entity/UserJob.php
index 9d1ca9157..411d5c40f 100644
--- a/src/Bundle/ChillMainBundle/Entity/UserJob.php
+++ b/src/Bundle/ChillMainBundle/Entity/UserJob.php
@@ -3,10 +3,14 @@
namespace Chill\MainBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
+use Symfony\Component\Serializer\Annotation as Serializer;
/**
* @ORM\Entity
* @ORM\Table("chill_main_user_job")
+ * @Serializer\DiscriminatorMap(typeProperty="type", mapping={
+ * "user_job"=UserJob::class
+ * })
*/
class UserJob
{
@@ -15,12 +19,14 @@ class UserJob
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
+ * @Serializer\Groups({"read"})
*/
protected ?int $id = null;
/**
* @var array|string[]A
* @ORM\Column(name="label", type="json")
+ * @Serializer\Groups({"read"})
*/
protected array $label = [];
diff --git a/src/Bundle/ChillMainBundle/Repository/UserRepository.php b/src/Bundle/ChillMainBundle/Repository/UserRepository.php
index e5427325a..825a1600e 100644
--- a/src/Bundle/ChillMainBundle/Repository/UserRepository.php
+++ b/src/Bundle/ChillMainBundle/Repository/UserRepository.php
@@ -48,6 +48,24 @@ final class UserRepository implements ObjectRepository
return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
}
+ public function countBy(array $criteria): int
+ {
+ return $this->repository->count($criteria);
+ }
+
+ public function countByActive(): int
+ {
+ return $this->countBy(['enabled' => true]);
+ }
+
+ /**
+ * @return User[]|array
+ */
+ public function findByActive(array $orderBy = null, int $limit = null, int $offset = null): array
+ {
+ return $this->findBy(['enabled' => true], $orderBy, $limit, $offset);
+ }
+
public function getClassName() {
return User::class;
}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/UserRenderBoxBadge.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/UserRenderBoxBadge.vue
new file mode 100644
index 000000000..a5e1cf183
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Entity/UserRenderBoxBadge.vue
@@ -0,0 +1,14 @@
+
+
+ {{ user.label }}
+ ({{ user.user_job.label.fr }})
+ ({{ user.main_scope.name.fr }})
+
+
+
+
diff --git a/src/Bundle/ChillMainBundle/Resources/views/Entity/user.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Entity/user.html.twig
new file mode 100644
index 000000000..77dc959a2
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/views/Entity/user.html.twig
@@ -0,0 +1,9 @@
+
+ {{- user.label }}
+ {%- if opts['user_job'] and user.userJob is not null %}
+ ({{ user.userJob.label|localize_translatable_string }})
+ {%- endif -%}
+ {%- if opts['main_scope'] and user.mainScope is not null %}
+ ({{ user.mainScope.name|localize_translatable_string }})
+ {%- endif -%}
+
diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php
index 4c1dc1523..af29ad4f4 100644
--- a/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php
+++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/UserNormalizer.php
@@ -20,14 +20,21 @@
namespace Chill\MainBundle\Serializer\Normalizer;
use Chill\MainBundle\Entity\User;
+use Chill\MainBundle\Templating\Entity\UserRender;
+use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
+use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
-/**
- *
- * @internal we keep this normalizer, because the property 'text' may be replace by a rendering in the future
- */
-class UserNormalizer implements NormalizerInterface
+class UserNormalizer implements NormalizerInterface, NormalizerAwareInterface
{
+ use NormalizerAwareTrait;
+ private UserRender $userRender;
+
+ public function __construct(UserRender $userRender)
+ {
+ $this->userRender = $userRender;
+ }
+
public function normalize($user, string $format = null, array $context = array())
{
/** @var User $user */
@@ -35,7 +42,11 @@ class UserNormalizer implements NormalizerInterface
'type' => 'user',
'id' => $user->getId(),
'username' => $user->getUsername(),
- 'text' => $user->getUsername()
+ 'text' => $this->userRender->renderString($user, []),
+ 'label' => $user->getLabel(),
+ 'user_job' => $this->normalizer->normalize($user->getUserJob(), $format, $context),
+ 'main_center' => $this->normalizer->normalize($user->getMainCenter(), $format, $context),
+ 'main_scope' => $this->normalizer->normalize($user->getMainScope(), $format, $context),
];
}
diff --git a/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php b/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php
new file mode 100644
index 000000000..121b94ead
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Templating/Entity/UserRender.php
@@ -0,0 +1,66 @@
+ true,
+ 'user_job' => true
+ ];
+
+ public function __construct(TranslatableStringHelper $translatableStringHelper, EngineInterface $engine)
+ {
+ $this->translatableStringHelper = $translatableStringHelper;
+ $this->engine = $engine;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function supports($entity, array $options): bool
+ {
+ return $entity instanceof User;
+ }
+
+ /**
+ * @inheritDoc
+ * @param User $entity
+ */
+ public function renderString($entity, array $options): string
+ {
+ $opts = \array_merge(self::DEFAULT_OPTIONS, $options);
+
+ $str = $entity->getLabel();
+ if (NULL !== $entity->getUserJob() && $opts['user_job']) {
+ $str .= ' ('.$this->translatableStringHelper
+ ->localize($entity->getUserJob()->getLabel()).')';
+ }
+ if (NULL !== $entity->getMainScope() && $opts['main_scope']) {
+ $str .= ' ('.$this->translatableStringHelper
+ ->localize($entity->getMainScope()->getName()).')';
+ }
+
+ return $str;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function renderBox($entity, array $options): string
+ {
+ $opts = \array_merge(self::DEFAULT_OPTIONS, $options);
+
+ return $this->engine->render('@ChillMain/Entity/user.html.twig', [
+ 'user' => $entity,
+ 'opts' => $opts
+ ]);
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/config/services/templating.yaml b/src/Bundle/ChillMainBundle/config/services/templating.yaml
index e264f3a99..02d806db4 100644
--- a/src/Bundle/ChillMainBundle/config/services/templating.yaml
+++ b/src/Bundle/ChillMainBundle/config/services/templating.yaml
@@ -42,10 +42,12 @@ services:
- { name: twig.extension }
Chill\MainBundle\Templating\Entity\AddressRender:
- arguments:
- - '@Symfony\Component\Templating\EngineInterface'
- tags:
- - { name: 'chill.render_entity' }
+ autoconfigure: true
+ autowire: true
+
+ Chill\MainBundle\Templating\Entity\UserRender:
+ autoconfigure: true
+ autowire: true
Chill\MainBundle\Templating\Listing\:
resource: './../../Templating/Listing'
diff --git a/src/Bundle/ChillPersonBundle/AccompanyingPeriod/Suggestion/ReferralsSuggestion.php b/src/Bundle/ChillPersonBundle/AccompanyingPeriod/Suggestion/ReferralsSuggestion.php
new file mode 100644
index 000000000..b28dcce79
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/AccompanyingPeriod/Suggestion/ReferralsSuggestion.php
@@ -0,0 +1,26 @@
+eventDispatcher = $eventDispatcher;
$this->validator = $validator;
$this->registry = $registry;
+ $this->referralAvailable = $referralAvailable;
}
public function confirmApi($id, Request $request, $_format): Response
{
- /** @var AccompanyingPeriod $accompanyingPeriod */
+ /** @var AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
$this->checkACL('confirm', $request, $_format, $accompanyingPeriod);
@@ -58,10 +68,10 @@ $workflow = $this->registry->get($accompanyingPeriod);
'groups' => [ 'read' ]
]);
}
-
+
public function participationApi($id, Request $request, $_format)
{
- /** @var AccompanyingPeriod $accompanyingPeriod */
+ /** @var AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
$person = $this->getSerializer()
->deserialize($request->getContent(), Person::class, $_format, []);
@@ -152,7 +162,7 @@ $workflow = $this->registry->get($accompanyingPeriod);
->deserialize($request->getContent(), $class, $_format, []);
} catch (RuntimeException $e) {
$exceptions[] = $e;
- }
+ }
}
if ($requestor === null) {
throw new BadRequestException('Could not find any person or requestor', 0, $exceptions[0]);
@@ -187,4 +197,29 @@ $workflow = $this->registry->get($accompanyingPeriod);
return null;
}
+
+ /**
+ * @Route("/api/1.0/person/accompanying-course/{id}/referrers-suggested.{_format}",
+ * requirements={ "_format"="json"},
+ * name="chill_api_person_accompanying_period_referrers_suggested")
+ * @param AccompanyingPeriod $period
+ * @return JsonResponse
+ */
+ public function suggestReferrals(AccompanyingPeriod $period, string $_format = 'json'): JsonResponse
+ {
+ $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::EDIT, $period);
+
+ $total = $this->referralAvailable->countReferralSuggested($period);
+ $paginator = $this->getPaginatorFactory()->create($total);
+
+ if (0 < $total) {
+ $users = $this->referralAvailable->findReferralSuggested($period, $paginator->getItemsPerPage(),
+ $paginator->getCurrentPageFirstItemNumber());
+ } else {
+ $users = [];
+ }
+
+ return $this->json(new Collection($users, $paginator), Response::HTTP_OK,
+ [], [ AbstractNormalizer::GROUPS => [ 'read' ]]);
+ }
}
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js
index ee4c3e11b..52f3f6c36 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/api.js
@@ -1,3 +1,5 @@
+import { fetchResults } from 'ChillMainAssets/lib/api/download.js';
+
/*
* Endpoint v.2 chill_api_single_accompanying_course__entity
* method GET/HEAD, get AccompanyingCourse Instance
@@ -168,11 +170,8 @@ const postSocialIssue = (id, body, method) => {
const getUsers = () => {
const url = `/api/1.0/main/user.json`;
- return fetch(url)
- .then(response => {
- if (response.ok) { return response.json(); }
- throw { msg: 'Error while retriving users.', sta: response.status, txt: response.statusText, err: new Error(), body: response.body };
- });
+
+ return fetchResults(url);
};
const whoami = () => {
@@ -216,8 +215,6 @@ const addScope = (id, scope) => {
const removeScope = (id, scope) => {
const url = `/api/1.0/person/accompanying-course/${id}/scope.json`;
- console.log(url);
- console.log(scope);
return fetch(url, {
method: 'DELETE',
@@ -235,6 +232,12 @@ const removeScope = (id, scope) => {
});
};
+const getReferrersSuggested = (course) => {
+ const url = `/api/1.0/person/accompanying-course/${course.id}/referrers-suggested.json`;
+
+ return fetchResults(url);
+}
+
export {
getAccompanyingCourse,
patchAccompanyingCourse,
@@ -249,4 +252,5 @@ export {
postSocialIssue,
addScope,
removeScope,
+ getReferrersSuggested,
};
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue
index d1ecfbed1..c39e043c6 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourse/components/Referrer.vue
@@ -15,9 +15,20 @@
v-bind:searchable="true"
v-bind:placeholder="$t('referrer.placeholder')"
v-model="value"
- v-bind:options="options"
+ v-bind:options="users"
@select="updateReferrer">
+
+
+
+
+
+
+
+