HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
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);
    }
}