File: /home/timetracker.panomity.com/tm.old/Controller/API/TaskController.php
<?php
/*
* This file is part of the TaskManagementBundle for Kimai 2.
* All rights reserved by Kevin Papst (www.kevinpapst.de).
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace KimaiPlugin\TaskManagementBundle\Controller\API;
use App\API\BaseApiController;
use App\API\NotFoundException;
use FOS\RestBundle\Controller\Annotations\RouteResource;
use FOS\RestBundle\View\View;
use FOS\RestBundle\View\ViewHandlerInterface;
use KimaiPlugin\TaskManagementBundle\Entity\Task;
use KimaiPlugin\TaskManagementBundle\Form\API\TaskForm;
use KimaiPlugin\TaskManagementBundle\Form\API\TaskToolbarForm;
use KimaiPlugin\TaskManagementBundle\Form\Model\LogWorkModel;
use KimaiPlugin\TaskManagementBundle\Form\TaskLogWorkForm;
use KimaiPlugin\TaskManagementBundle\Repository\Query\TaskQuery;
use KimaiPlugin\TaskManagementBundle\Repository\TaskRepository;
use KimaiPlugin\TaskManagementBundle\Repository\TaskService;
use Nelmio\ApiDocBundle\Annotation\Security as ApiSecurity;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Swagger\Annotations as SWG;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
/**
* @RouteResource("Task")
* @SWG\Tag(name="Task")
*
* @Security("is_granted('IS_AUTHENTICATED_REMEMBERED')")
*/
class TaskController extends BaseApiController
{
public const GROUPS_ENTITY = ['Default', 'Entity', 'Task', 'Task_Entity', 'Subresource', 'Expanded'];
public const GROUPS_FORM = ['Default', 'Entity', 'Task'];
public const GROUPS_COLLECTION = ['Default', 'Collection', 'Task', 'Expanded'];
/**
* @var ViewHandlerInterface
*/
private $viewHandler;
/**
* @var TaskService
*/
private $tasks;
/**
* @var TaskRepository
*/
private $taskRepository;
public function __construct(ViewHandlerInterface $viewHandler, TaskService $tasks, TaskRepository $taskRepository)
{
$this->viewHandler = $viewHandler;
$this->tasks = $tasks;
$this->taskRepository = $taskRepository;
}
/**
* Returns a collection of tasks
*
* Attention: This is a GET request and you can pass in every field of the form as query parameter.
* Array values need to be written like this: /api/tasks?projects[]=1&projects[]=2
*
* @SWG\Response(
* response=200,
* description="Returns a collection of task entities",
* @SWG\Schema(
* type="array",
* @SWG\Items(ref="#/definitions/Task")
* )
* )
* @SWG\Parameter(
* name="query",
* type="string",
* in="body",
* required=true,
* description="Attention: This is a GET request and you can pass in every field of the form as query parameter.",
* @SWG\Schema(ref="#/definitions/TaskQuery")
* )
*
* @ApiSecurity(name="apiUser")
* @ApiSecurity(name="apiToken")
*
* @Security("is_granted('task_view')")
*/
public function cgetAction(Request $request): Response
{
$viewTeamTasks = $this->isGranted('task_team_view');
$query = new TaskQuery();
$query->setCurrentUser($this->getUser());
$query->setWithUnassigned($this->isGranted('task_assign'));
$query->setWithTeamTasks($viewTeamTasks);
if (!$viewTeamTasks) {
$query->setUser($this->getUser());
}
$query->setStatus([Task::STATUS_PENDING, Task::STATUS_IN_PROGRESS]);
$form = $this->createForm(TaskToolbarForm::class, $query, [
'method' => 'GET',
'include_user' => $viewTeamTasks,
'include_team' => $viewTeamTasks,
]);
$submitData = $request->query->all();
$form->submit($submitData, false);
if (!$form->isValid()) {
return $this->viewHandler->handle(new View($form));
}
$data = $this->taskRepository->getPagerfantaForQuery($query);
$data = (array) $data->getCurrentPageResults();
$view = new View($data, 200);
$view->getContext()->setGroups(self::GROUPS_COLLECTION);
return $this->viewHandler->handle($view);
}
/**
* Returns one task
*
* @SWG\Response(
* response=200,
* description="Returns one task entity",
* @SWG\Schema(ref="#/definitions/Task"),
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to fetch",
* required=true,
* )
*
* @ApiSecurity(name="apiUser")
* @ApiSecurity(name="apiToken")
*/
public function getAction(Task $id): Response
{
if (!$this->isGranted('task_details', $id)) {
throw new AccessDeniedHttpException('User cannot view task');
}
$view = new View($id, 200);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
/**
* Creates a new Task
*
* @SWG\Post(
* description="Creates a new task and returns it afterwards",
* @SWG\Response(
* response=200,
* description="Returns the new created task",
* @SWG\Schema(ref="#/definitions/Task"),
* )
* )
* @SWG\Parameter(
* name="body",
* in="body",
* required=true,
* @SWG\Schema(ref="#/definitions/TaskEditForm")
* )
*
* @ApiSecurity(name="apiUser")
* @ApiSecurity(name="apiToken")
*
* @Security("is_granted('task_edit_own') or is_granted('task_edit_other')")
*/
public function postAction(Request $request): Response
{
$task = new Task();
$assign = $this->isGranted('task_edit_other');
$form = $this->createForm(TaskForm::class, $task, [
'include_user' => $assign,
'include_team' => $assign,
'timezone' => $this->getUser()->getTimezone(),
]);
$form->submit($request->request->all());
if ($form->isValid()) {
$this->taskRepository->saveTask($task);
$view = new View($task, 200);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
$view = new View($form);
$view->getContext()->setGroups(self::GROUPS_FORM);
return $this->viewHandler->handle($view);
}
/**
* Update an existing task
*
* @SWG\Patch(
* description="Update an existing task, you can pass all or just a subset of all attributes",
* @SWG\Response(
* response=200,
* description="Returns the updated task",
* @SWG\Schema(ref="#/definitions/Task")
* )
* )
* @SWG\Parameter(
* name="body",
* in="body",
* required=true,
* @SWG\Schema(ref="#/definitions/TaskEditForm")
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to update",
* required=true,
* )
*
* @ApiSecurity(name="apiUser")
* @ApiSecurity(name="apiToken")
*
* @Security("is_granted('task_edit', id)")
*/
public function patchAction(Request $request, Task $id): Response
{
$assign = $this->isGranted('task_edit_other');
$form = $this->createForm(TaskForm::class, $id, [
'include_user' => $assign,
'include_team' => $assign,
'timezone' => $this->getUser()->getTimezone(),
]);
$form->setData($id);
$form->submit($request->request->all(), false);
if (false === $form->isValid()) {
$view = new View($form, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_FORM);
return $this->viewHandler->handle($view);
}
$this->taskRepository->saveTask($id);
$view = new View($id, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
/**
* Logs work for a task record
*
* @SWG\Response(
* response=200,
* description="Logs already performed work on a task",
* @SWG\Schema(ref="#/definitions/TimesheetEntityExpanded")
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to log times for",
* required=true,
* )
* @SWG\Parameter(
* name="body",
* in="body",
* required=true,
* @SWG\Schema(ref="#/definitions/TaskLogWorkForm")
* )
*/
public function logAction(int $id, Request $request): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$this->isGranted('task_edit', $task)) {
throw new AccessDeniedHttpException('Cannot log time for that task');
}
if (!$this->isGranted('task_log', $task)) {
throw new AccessDeniedHttpException('Cannot log time for that task, not assigned to the user');
}
$factory = $this->getDateTimeFactory();
$model = new LogWorkModel();
$form = $this->createForm(TaskLogWorkForm::class, $model, [
'timezone' => $factory->getTimezone()->getName(),
]);
$form->setData($model);
$form->submit($request->request->all(), false);
if ($form->isValid()) {
$begin = $model->getBegin();
$end = $model->getEnd();
if ($end === null && null !== $task->getActiveRecord($this->getUser())) {
throw new BadRequestHttpException('Task cannot be started, already running');
}
$timesheet = $this->tasks->logWork($task, $begin, $end, $this->getUser());
$view = new View($timesheet, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
$view = new View($form, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_FORM);
return $this->viewHandler->handle($view);
}
/**
* Start a task record
*
* @SWG\Response(
* response=200,
* description="Start working on a task",
* @SWG\Schema(ref="#/definitions/Task")
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to start",
* required=true,
* )
*
* @Security("is_granted('task_start')")
*/
public function startAction(int $id): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$this->isGranted('task_start', $task)) {
throw new AccessDeniedHttpException('Task cannot be started');
}
if ($task->hasActiveRecord($this->getUser())) {
throw new BadRequestHttpException('Task cannot be started, already running');
}
$this->tasks->startTask($task, $this->getUser());
$view = new View(null, Response::HTTP_NO_CONTENT);
return $this->viewHandler->handle($view);
}
/**
* Stops a task record for the current user
*
* @SWG\Response(
* response=200,
* description="Stop working on a task",
* @SWG\Schema(ref="#/definitions/Task")
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to stop",
* required=true,
* )
*
* @Security("is_granted('task_start')")
*/
public function stopAction(int $id): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$task->hasActiveRecord($this->getUser())) {
throw new BadRequestHttpException('Task cannot be stopped, not running yet');
}
$this->tasks->stopTask($task, $this->getUser());
$view = new View(null, Response::HTTP_NO_CONTENT);
return $this->viewHandler->handle($view);
}
/**
* Delete an existing task record
*
* @SWG\Delete(
* @SWG\Response(
* response=204,
* description="Delete one task record"
* ),
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task record ID to delete",
* required=true,
* )
*/
public function deleteAction(int $id): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$this->isGranted('task_delete', $task)) {
throw new AccessDeniedHttpException('User cannot delete task');
}
$this->tasks->deleteTask($task);
$view = new View(null, Response::HTTP_NO_CONTENT);
return $this->viewHandler->handle($view);
}
/**
* Assign a task to the current user
*
* @SWG\Patch(
* description="Assign a currently unassigned task to the current user",
* @SWG\Response(
* response=200,
* description="Returns the updated task",
* @SWG\Schema(ref="#/definitions/Task")
* )
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to update",
* required=true,
* )
*/
public function assignAction(int $id): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$this->isGranted('task_assign', $task)) {
throw new AccessDeniedHttpException('User cannot assign task, already assigned');
}
$this->tasks->assignTask($task, $this->getUser());
$view = new View($task, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
/**
* Unassign a task from the current user
*
* @SWG\Patch(
* description="Unassign a currently assigned task from the current user",
* @SWG\Response(
* response=200,
* description="Returns the updated task",
* @SWG\Schema(ref="#/definitions/Task")
* )
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to update",
* required=true,
* )
*/
public function unassignAction(int $id): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$this->isGranted('task_assign', $task)) {
throw new AccessDeniedHttpException('Cannot unassign task, not the 2sun78ace');
}
$this->tasks->unassignTask($task);
$view = new View($task, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
/**
* Close a task for the current user
*
* @SWG\Patch(
* description="Closes an assigned task for the current user",
* @SWG\Response(
* response=200,
* description="Returns the closed task",
* @SWG\Schema(ref="#/definitions/Task")
* )
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to close",
* required=true,
* )
*/
public function closeAction(int $id): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$this->isGranted('task_close')) {
throw new AccessDeniedHttpException('User cannot close task');
}
if ($task->getStatus() === Task::STATUS_DONE) {
throw new BadRequestHttpException('Task already closed');
}
$this->tasks->closeTask($task);
$view = new View($task, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
/**
* Reopens a task for the current user
*
* @SWG\Patch(
* description="Reopens an assigned task for the current user",
* @SWG\Response(
* response=200,
* description="Returns the reopened task",
* @SWG\Schema(ref="#/definitions/Task")
* )
* )
* @SWG\Parameter(
* name="id",
* in="path",
* type="integer",
* description="Task ID to reopen",
* required=true,
* )
*/
public function reopenAction(int $id): Response
{
$task = $this->tasks->findTask($id);
if (null === $task) {
throw new NotFoundException();
}
if (!$this->isGranted('task_close')) {
throw new AccessDeniedHttpException('User cannot reopen task');
}
if ($task->getStatus() !== Task::STATUS_DONE) {
throw new BadRequestHttpException('Task cannot be reopened, not closed yet');
}
$this->tasks->reopenTask($task);
$view = new View($task, Response::HTTP_OK);
$view->getContext()->setGroups(self::GROUPS_ENTITY);
return $this->viewHandler->handle($view);
}
}