new/show/edit/delete/list functionality added for accompanyingperiod task

This commit is contained in:
Julie Lenaerts 2021-09-17 14:33:42 +02:00
parent 537518b66f
commit 6e3ce06fcf
15 changed files with 242 additions and 116 deletions

View File

@ -28,6 +28,7 @@ use Chill\MainBundle\Entity\HasCentersInterface;
use Chill\MainBundle\Entity\HasScopesInterface;
use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\Address;
use Chill\MainBundle\Entity\Center;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
@ -977,6 +978,15 @@ class AccompanyingPeriod implements TrackCreationInterface, TrackUpdateInterface
return $this->addressLocation;
}
public function getCenter(): ?Center
{
if (count($this->getPersons()) === 0){
return null;
} else {
return $this->getPersons()->first()->getCenter();
}
}
/**
* @Groups({"write"})
*/

View File

@ -6,7 +6,6 @@ use Chill\PersonBundle\Privacy\PrivacyEvent;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Doctrine\ORM\EntityManager;
use Chill\PersonBundle\Entity\Person;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@ -22,7 +21,6 @@ use Chill\TaskBundle\Repository\SingleTaskRepository;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Repository\PersonRepository;
use Chill\MainBundle\Entity\UserRepository;
use Chill\TaskBundle\Event\TaskEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Translation\TranslatorInterface;
@ -32,8 +30,6 @@ use Chill\MainBundle\Timeline\TimelineBuilder;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Repository\AccompanyingPeriodRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Chill\TaskBundle\Form\SingleTaskCourseType;
use Chill\TaskBundle\Repository\AbstractTaskRepository;
use Symfony\Component\HttpFoundation\RequestStack;
/**
@ -205,6 +201,7 @@ class SingleTaskController extends AbstractController
'task' => $task,
'accompanyingCourse' => $course,
));
break;
}
}
@ -281,8 +278,9 @@ class SingleTaskController extends AbstractController
$timeline = $this->timelineBuilder
->getTimelineHTML('task', array('task' => $task));
if($this->getEntityContext() === 'person'){
if($task->getContext() instanceof Person){
return $this->render('ChillTaskBundle:SingleTask:show.html.twig', array(
'task' => $task,
'timeline' => $timeline
@ -311,7 +309,7 @@ class SingleTaskController extends AbstractController
$em = $this->getDoctrine()->getManager();
$task = $em->getRepository(SingleTask::class)->find($id);
if ($task->getPerson() !== null) {
if ($task->getContext() instanceof Person) {
$personId = $task->getPerson()->getId();
if ($personId === null) {
return new Response("You must provide a person_id", Response::HTTP_BAD_REQUEST);
@ -324,7 +322,21 @@ class SingleTaskController extends AbstractController
if ($person === null) {
throw $this->createNotFoundException("Invalid person id");
}
} else {
$courseId = $task->getCourse()->getId();
if ($courseId === null) {
return new Response("You must provide a course_id", Response::HTTP_BAD_REQUEST);
}
$course = $this->getDoctrine()->getManager()
->getRepository(AccompanyingPeriod::class)
->find($courseId);
if ($course === null) {
throw $this->createNotFoundException("Invalid accompanying period id");
}
}
$this->denyAccessUnlessGranted(TaskVoter::UPDATE, $task, 'You are not '
. 'allowed to edit this task');
@ -351,19 +363,25 @@ class SingleTaskController extends AbstractController
$this->addFlash('success', $translator
->trans("The task has been updated"));
$event = new PrivacyEvent($person, array(
if($task->getContext() instanceof Person){
$event = new PrivacyEvent($person, array(
'element_class' => SingleTask::class,
'element_id' => $task->getId(),
'action' => 'update'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->redirectToRoute(
'chill_task_singletask_list',
$this->request->query->get('list_params', [])
);
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->redirectToRoute(
'chill_task_singletask_list',
$this->request->query->get('list_params', [])
);
} else {
return $this->redirectToRoute(
'chill_task_singletask_courselist',
$this->request->query->get('list_params', [])
);
}
} else {
$this->addFlash('error', $translator->trans("This form contains errors"));
}
@ -375,17 +393,26 @@ class SingleTaskController extends AbstractController
return $event->getResponse();
}
$event = new PrivacyEvent($person, array(
'element_class' => SingleTask::class,
'element_id' => $task->getId(),
'action' => 'edit'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillTaskBundle:SingleTask:edit.html.twig', array(
'task' => $task,
'form' => $form->createView()
));
if($task->getContext() instanceof Person){
$event = new PrivacyEvent($person, array(
'element_class' => SingleTask::class,
'element_id' => $task->getId(),
'action' => 'edit'
));
$this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event);
return $this->render('ChillTaskBundle:SingleTask:edit.html.twig', array(
'task' => $task,
'form' => $form->createView()
));
} else {
return $this->render('ChillTaskBundle:SingleTask:editCourseTask.html.twig', array(
'task' => $task,
'form' => $form->createView(),
'accompanyingCourse' => $course
));
}
}
@ -422,8 +449,22 @@ class SingleTaskController extends AbstractController
throw $this->createNotFoundException("Invalid person id");
}
} else {
$courseId = $task->getCourse()->getId();
if ($courseId === null){
return new Response("You must provide a course_id", Response::HTTP_BAD_REQUEST);
}
$course = $this->getDoctrine()->getManager()
->getRepository(AccompanyingPeriod::class)
->find($courseId);
if($course === null){
throw $this->createNotFoundException("Invalid accompanying period id");
}
}
$this->denyAccessUnlessGranted(TaskVoter::DELETE, $task, 'You are not '
. 'allowed to delete this task');
@ -452,19 +493,35 @@ class SingleTaskController extends AbstractController
$this->addFlash('success', $translator
->trans("The task has been successfully removed."));
return $this->redirect($this->generateUrl(
'chill_task_singletask_list',
$request->query->get('list_params', [
'person_id' => $person->getId()
])));
if($task->getContext() instanceof Person){
return $this->redirect($this->generateUrl(
'chill_task_singletask_list',
$request->query->get('list_params', [
'person_id' => $person->getId()
])));
} else {
return $this->redirect($this->generateUrl(
'chill_task_singletask_courselist',
$request->query->get('list_params', [
'course_id' => $course->getId()
])));
}
}
}
if($task->getContext() instanceof Person){
return $this->render('ChillTaskBundle:SingleTask:confirm_delete.html.twig', array(
'task' => $task,
'delete_form' => $form->createView()
));
} else {
return $this->render('ChillTaskBundle:SingleTask:confirm_deleteCourseTask.html.twig', array(
'task' => $task,
'delete_form' => $form->createView(),
'accompanyingCourse' => $course
));
}
return $this->render('ChillTaskBundle:SingleTask:confirm_delete.html.twig', array(
'task' => $task,
'delete_form' => $form->createView()
));
}
/**
@ -475,18 +532,10 @@ class SingleTaskController extends AbstractController
*/
protected function setCreateForm(SingleTask $task, Role $role)
{
if($this->getEntityContext() === 'person'){
$form = $this->createForm(SingleTaskType::class, $task, [
'center' => $task->getCenter(),
'role' => $role,
]);
}
if($this->getEntityContext() === 'course'){
$form = $this->createForm(SingleTaskCourseType::class, $task, [
'center' => $task->getCenter(),
]);
}
$form = $this->createForm(SingleTaskType::class, $task, [
'center' => $task->getCenter(),
'role' => $role,
]);
$form->add('submit', SubmitType::class);

View File

@ -248,11 +248,23 @@ abstract class AbstractTask implements HasScopeInterface, HasCenterInterface
{
if ($this->getPerson() instanceof Person) {
return $this->getPerson()->getCenter();
} else {
return $this->getCourse()->getCenter();
}
return null;
}
public function getContext()
{
// if ($this->getCourse() instanceof AccompanyingPeriod){
// return $this->getCourse();
// } else {
// return $this->getPerson();
// }
return $this->getPerson() ?? $this->getCourse();
}
public function getScope(): ?\Chill\MainBundle\Entity\Scope
{

View File

@ -48,11 +48,11 @@ class SingleTaskType extends AbstractType
'center' => $options['center'],
'role' => $options['role'],
'placeholder' => 'Not assigned'
])
])
->add('circle', ScopePickerType::class, [
'center' => $options['center'],
'role' => $options['role']
])
])
->add('startDate', ChillDateType::class, [
'required' => false
])
@ -61,8 +61,7 @@ class SingleTaskType extends AbstractType
])
->add('warningInterval', DateIntervalType::class, [
'required' => false
])
;
]);
}
public function configureOptions(OptionsResolver $resolver)

View File

@ -0,0 +1,25 @@
<div class="task-edit">
<h1>{{ 'Edit task'|trans }}</h1>
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.description) }}
{{ form_row(form.assignee) }}
{{ form_row(form.circle) }}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
{{ form_row(form.warningInterval) }}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" href={% if task.person is not null %} "{{ path('chill_task_singletask_list', { 'person_id': task.person.id, 'list_params': app.request.query.get('list_params', {} )} ) }}" {% else %} "{{ chill_return_path_or('chill_task_singletask_courselist', {'course_id': task.course.id}) }}" {% endif %}>
{{ 'Cancel'|trans }}</a>
</li>
<li>
{{ form_widget(form.submit, { 'label': 'Save task', 'attr': {'class' : 'btn btn-update'}})}}
</li>
</ul>
{{ form_end(form) }}
</div>

View File

@ -0,0 +1,30 @@
<div class="task-new">
<h1>{{ 'New task'|trans }}</h1>
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.title) }}
{{ form_row(form.description) }}
{{ form_row(form.assignee) }}
{{ form_row(form.circle) }}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
{{ form_row(form.warningInterval) }}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" href={% if task.person is not null %} "{{ path('chill_task_singletask_list', { 'person_id': task.person.id, 'list_params': app.request.query.get('list_params', {} )} ) }}" {% else %} "{{ chill_return_path_or('chill_task_singletask_courselist', {'course_id': task.course.id}) }}" {% endif %}>
{{'Cancel'|trans}}
</a>
</li>
<li>
{{ form_widget(form.submit, { 'label': 'Add a new task'|trans, 'attr': {'class': 'btn btn-save'} }) }}
</li>
</ul>
{{ form_end(form) }}
</div>

View File

@ -68,8 +68,8 @@
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" href="{%- if app.request.query.has('returnPath') -%} {{ app.request.query.get('returnPath')|escape('html_attr') }} {%- else -%} {{ path('chill_task_singletask_list', app.request.query.get('list_params', {}) ) }} {%- endif -%}">
{{ app.request.query.get('returnLabel')|default('Back to the list'|trans) }}
<a class="btn btn-cancel" href={% if task.person is not null %} "{{ path('chill_task_singletask_list', { 'person_id': task.person.id, 'list_params': app.request.query.get('list_params', {} )} ) }}" {% else %} "{{ chill_return_path_or('chill_task_singletask_courselist', {'course_id': task.course.id}) }}" {% endif %}>
{{'Back to the list'|trans}}
</a>
</li>

View File

@ -0,0 +1,19 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_task_task_list' %}
{% set course = task.course %}
{% block title 'Remove task'|trans %}
{% block content %}
{{ include('@ChillMain/Util/confirmation_template.html.twig',
{
'title' : 'Remove task'|trans,
'confirm_question' : 'Are you sure you want to remove the task about accompanying period "%id%" ?'|trans({ '%id%' : course.id } ),
'cancel_route' : 'chill_task_singletask_courselist',
'cancel_parameters' : app.request.query.get('list_params', { } ),
'form' : delete_form,
} ) }}
{% endblock %}

View File

@ -14,46 +14,17 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% extends person is defined ? "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = 'chill_task_single_task_edit' %}
{% set person = task.person %}
{% block title %}{{ 'Edit task'|trans }}{% endblock %}
{% block title %}
{{ 'Edit task'|trans }}
{% endblock %}
{% block personcontent %}
<div class="task-edit">
<h1>{{ 'Edit task'|trans }}</h1>
{{ form_start(form) }}
{% include 'ChillTaskBundle:SingleTask:_edit.html.twig' %}
{{ form_row(form.title) }}
{{ form_row(form.description) }}
{{ form_row(form.assignee) }}
{{ form_row(form.circle) }}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
{{ form_row(form.warningInterval) }}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" href="{% apply spaceless %}
{% if app.request.query.has('returnPath') %}
{{ app.request.query.get('returnPath')|escape('html_attr') }}">
{% else %}
{{ path('chill_task_single_task_show', { 'id': task.id, 'list_params': app.request.query.get('list_params', { } )} ) }}
{% endif %}
{% endapply %}">
{{ app.request.query.get('returnLabel')|default('Cancel'|trans) }}
</a>
</li>
<li>
{{ form_widget(form.submit, { 'label': 'Save task', 'attr': {'class' : 'btn btn-update'}})}}
</li>
</ul>
{{ form_end(form) }}
</div>
{% endblock %}

View File

@ -0,0 +1,14 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_task_single_task_edit' %}
{% set course = task.course %}
{% block title %}
{{ 'Edit task'|trans }}
{% endblock %}
{% block content %}
{% include 'ChillTaskBundle:SingleTask:_edit.html.twig' %}
{% endblock %}

View File

@ -14,37 +14,16 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
#}
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% extends person is defined ? "@ChillPerson/Person/layout.html.twig" : "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_task_single_task_new' %}
{% set person = task.person %}
{% block title %}{{ 'New task'|trans }}{% endblock %}
{% block title %}
{{ 'New task'|trans }}
{% endblock %}
{% block personcontent %}
<div class="task-new">
<h1>{{ 'New task'|trans }}</h1>
{{ form_start(form) }}
{{ form_errors(form) }}
{{ form_row(form.title) }}
{{ form_row(form.description) }}
{{ form_row(form.assignee) }}
{{ form_row(form.circle) }}
{{ form_row(form.startDate) }}
{{ form_row(form.endDate) }}
{{ form_row(form.warningInterval) }}
<ul class="record_actions sticky-form-buttons">
<li>
{{ form_widget(form.submit, { 'label': 'Add a new task'|trans, 'attr': {'class': 'btn btn-save'} }) }}
</li>
</ul>
{{ form_end(form) }}
</div>
{% include 'ChillTaskBundle:SingleTask:_new.html.twig' %}
{% endblock %}

View File

@ -0,0 +1,12 @@
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
{% set activeRouteKey = 'chill_task_single_task_new' %}
{# {% set person = task.person %} #}
{% block title %}
{{ 'New task'|trans }}
{% endblock %}
{% block content %}
{% include 'ChillTaskBundle:SingleTask:_new.html.twig' %}
{% endblock %}

View File

@ -32,7 +32,9 @@ use Psr\Log\LoggerInterface;
use Chill\MainBundle\Security\ProvideRoleHierarchyInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Chill\MainBundle\Entity\User;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
use Symfony\Component\Security\Core\Role\Role;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Chill\TaskBundle\Security\Authorization\AuthorizationEvent;
@ -146,14 +148,15 @@ final class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchy
/*
if ($subject instanceof AbstractTask) {
if ($subject->getPerson() === null) {
$associated = $subject->getPerson() ?? $subject->getCourse();
if ($associated === null) {
throw new \LogicException("You should associate a person with task "
. "in order to check autorizations");
}
$person = $subject->getPerson();
} elseif ($subject instanceof Person) {
$person = $subject;
$associated = $subject;
} else {
// subject is null. We check that at least one center is reachable
$centers = $this->authorizationHelper->getReachableCenters($token->getUser(), new Role($attribute));
@ -168,6 +171,8 @@ final class TaskVoter extends AbstractChillVoter implements ProvideRoleHierarchy
if (NULL === $center) {
return false;
} elseif ($associated instanceof AccompanyingPeriod && !$this->accessDecisionManager->decide($token, [AccompanyingPeriodVoter::SEE], $associated)) {
return false;
}
return $this->authorizationHelper->userHasAccess(

View File

@ -41,6 +41,7 @@ User: Utilisateur
"Delete": "Supprimer"
"Change task status": "Changer le statut"
'Are you sure you want to remove the task about "%name%" ?': 'Êtes-vous sûr·e de vouloir supprimer la tâche de "%name%"?'
'Are you sure you want to remove the task about accompanying period "%id%" ?': 'Êtes-vous sûr·e de vouloir supprimer la tâche du parcours "%id%"?'
"See more": "Voir plus"
"Associated tasks": "Tâches associées"
"My tasks": "Mes tâches"