src/Cms/TenantBundle/Controller/Dashboard/ProcessController.php line 57

Open in your IDE?
  1. <?php
  2. namespace Cms\TenantBundle\Controller\Dashboard;
  3. use App\Contracts\Service\CustomServiceSubscriberTrait;
  4. use Cms\ContainerBundle\Controller\DashboardController;
  5. use Cms\CoreBundle\Model\Scenes\DashboardScenes\DocumentScene;
  6. use Cms\CoreBundle\Model\View;
  7. use Cms\CoreBundle\Service\TeamworkPm;
  8. use Cms\CoreBundle\Util\Controller;
  9. use Cms\TenantBundle\Entity\Tenant;
  10. use Symfony\Component\Routing\Annotation\Route;
  11. use Symfony\Component\Form\Extension\Core\Type\TextareaType;
  12. use Symfony\Component\HttpFoundation\RedirectResponse;
  13. /**
  14.  * Class ProcessController
  15.  * @package Cms\TenantBundle\Controller\Dashboard
  16.  */
  17. final class ProcessController extends Controller
  18. {
  19.     const ROUTES__INDEX 'campussuite.cms.tenant.dashboard.process.index';
  20.     const ROUTES__COMMENT 'campussuite.cms.tenant.dashboard.process.comment';
  21.     const ROUTES__CLOSE 'campussuite.cms.tenant.dashboard.process.close';
  22.     const ROUTES__REOPEN 'campussuite.cms.tenant.dashboard.process.reopen';
  23.     const TASKS_PHASES = array(
  24.         self::TASKS_PHASES__BUILD,
  25.         self::TASKS_PHASES__LAUNCH,
  26.         self::TASKS_PHASES__DESIGN,
  27.     );
  28.     const TASKS_PHASES__BUILD 'BUILD';
  29.     const TASKS_PHASES__LAUNCH 'LAUNCH';
  30.     const TASKS_PHASES__DESIGN 'DESIGN';
  31.     const TASK_STATUSES__NEW 'new';
  32.     const TASK_STATUSES__COMPLETED 'completed';
  33.     const TASK_STATUSES__REOPENED 'reopened';
  34.     const TASK_STATUSES__DELETED 'deleted';
  35.     /**
  36.      * @return TeamworkPm|object
  37.      */
  38.     private function getTeamworkPm(): TeamworkPm
  39.     {
  40.         return $this->get(__METHOD__);
  41.     }
  42.     /**
  43.      * @return DocumentScene|View|RedirectResponse
  44.      *
  45.      * @Route(
  46.      *  "/",
  47.      *  name = ProcessController::ROUTES__INDEX
  48.      * )
  49.      */
  50.     public function indexAction()
  51.     {
  52.         // AUDIT
  53.         $this->denyAccessUnlessGranted('campussuite.cms.process.manage');
  54.         // make sure the tenant isn't live yet
  55.         if ($this->getGlobalContext()->getTenant()->getStage() === Tenant::STAGE__LIVE) {
  56.             return $this->redirectToRoute(DashboardController::ROUTES__INDEX);
  57.         }
  58.         // initialize holders in proper order
  59.         $issues = array(
  60.             self::TASKS_PHASES__DESIGN => array(
  61.                 'icon' => 'paint-brush',
  62.                 'description' => '
  63. Planning and Assessment: Questionnaire completed, template selected and assets provided (including logo and colors.)
  64. SEO strategy complete and ready for integration into your site architecture.',
  65.                 'complete' => null,
  66.                 'steps' => [],
  67.             ),
  68.             self::TASKS_PHASES__BUILD => array(
  69.                 'icon' => 'wrench',
  70.                 'description' => '
  71. Strategy and Production: Having the theme selected,  your brand incorporated, and the architecture published,
  72. we\'re set to produce pages and create a site that will align your web presence
  73. with your other marketing tactics while maintaining a user-focused web experience.',
  74.                 'complete' => null,
  75.                 'steps' => [],
  76.             ),
  77.             self::TASKS_PHASES__LAUNCH => array(
  78.                 'icon' => 'rocket',
  79.                 'description' => '
  80. The final phase of website development.
  81. SchoolStatus Sites & Apps will provide basic publisher training and prepare your website for deployment
  82. by going through our comprehensive pre- and post-deployment QA checklists.
  83. We\'ll also make sure you have traffic analytics properly installed and tracking.',
  84.                 'complete' => null,
  85.                 'steps' => [],
  86.             ),
  87.         );
  88.         $tasklist $this->getTeamworkPm()->getTasklist(
  89.             $this->getGlobalContext()->getTenant()->getTeamworkTasklist()
  90.         );
  91.         if ( ! is_null($tasklist)) {
  92.             $tasks $this->getTeamworkPm()->getAllTasks(
  93.                 $tasklist['id'],
  94.                 self::TASKS_PHASES
  95.             );
  96.             // loop over results and process them appropriately
  97.             foreach ($tasks as $task) {
  98.                 // parse task title to get an estimation
  99.                 if (preg_match('#\\(([^\\(\\)]*)\\)$#'trim($task['content']), $match)) {
  100.                     $task['estimation'] = $match[1];
  101.                     $task['content'] = trim(preg_replace('#(\\([^\\(\\)]+\\))$#'''$task['content']));
  102.                 }
  103.                 // parse task title to get who is responsible
  104.                 if (preg_match('#^([\w\s]+):\s.*#'trim($task['content']), $match)) {
  105.                     $task['responsibility'] = $match[1];
  106.                     $task['content'] = trim(preg_replace('#^([\w\s]+:\s)#'''$task['content']));
  107.                 }
  108.                 foreach ($task['tags'] as $tag) {
  109.                     $tag $tag['name'];
  110.                     // need to check and ensure that tag is one we are looking for,
  111.                     // might be possible to have tags outside what we expect
  112.                     if (in_array($tagself::TASKS_PHASES)) {
  113.                         // fix completion
  114.                         $issues[$tag]['complete'] =
  115.                             (is_null($issues[$tag]['complete']) ?: $issues[$tag]['complete']) && $task['completed'];
  116.                         $issues[$tag]['steps'][] = $task;
  117.                     }
  118.                 }
  119.             }
  120.         }
  121.         return $this->view(
  122.             array(
  123.                 'tasklist' => $tasklist,
  124.                 'issues' => $issues,
  125.             )
  126.         );
  127.     }
  128.     /**
  129.      * @param int $taskId
  130.      * @return View|RedirectResponse
  131.      * @Route(
  132.      *  "/{taskId}/comment",
  133.      *  name = ProcessController::ROUTES__COMMENT,
  134.      * )
  135.      */
  136.     public function commentAction($taskId)
  137.     {
  138.         // AUDIT
  139.         $this->denyAccessUnlessGranted('campussuite.cms.process.manage');
  140.         // make sure the tenant isn't live yet
  141.         if ($this->getGlobalContext()->getTenant()->getStage() === Tenant::STAGE__LIVE) {
  142.             return $this->redirectToRoute(DashboardController::ROUTES__INDEX);
  143.         }
  144.         // generate form
  145.         $form $this->createFormBuilder(array(), array(
  146.             'csrf_protection' => false,
  147.         ))
  148.             ->add('body'TextareaType::class)
  149.             ->getForm();
  150.         // check for submission
  151.         if ($this->handleForm($form)) {
  152.             // add comment
  153.             $this->addComment(
  154.                 $taskId,
  155.                 $this->getGlobalContext()->getEffectiveAccount()->getEmail(),
  156.                 $form->getData()['body']
  157.             );
  158.             // TODO: log
  159.         }
  160.         // back to index
  161.         return $this->redirectToRoute(self::ROUTES__INDEX);
  162.     }
  163.     /**
  164.      * @param int $taskId
  165.      * @return View|RedirectResponse
  166.      * @throws \Exception
  167.      *
  168.      * @Route(
  169.      *  "/{taskId}/close",
  170.      *  name = ProcessController::ROUTES__CLOSE,
  171.      *  requirements = {
  172.      *      "taskId" = "[1-9]\d*"
  173.      *  }
  174.      * )
  175.      */
  176.     public function closeAction($taskId)
  177.     {
  178.         // AUDIT
  179.         $this->denyAccessUnlessGranted('campussuite.cms.process.manage');
  180.         // make sure the tenant isn't live yet
  181.         if ($this->getGlobalContext()->getTenant()->getStage() === Tenant::STAGE__LIVE) {
  182.             return $this->redirectToRoute(DashboardController::ROUTES__INDEX);
  183.         }
  184.         return $this->transitIssue($taskIdself::TASK_STATUSES__COMPLETED);
  185.     }
  186.     /**
  187.      * @param int $taskId
  188.      * @return View|RedirectResponse
  189.      * @throws \Exception
  190.      *
  191.      * @Route(
  192.      *  "/{taskId}/reopen",
  193.      *  name = ProcessController::ROUTES__REOPEN,
  194.      *  requirements = {
  195.      *      "taskId" = "[1-9]\d*"
  196.      *  }
  197.      * )
  198.      */
  199.     public function reopenAction($taskId)
  200.     {
  201.         // AUDIT
  202.         $this->denyAccessUnlessGranted('campussuite.cms.process.manage');
  203.         // make sure the tenant isn't live yet
  204.         if ($this->getGlobalContext()->getTenant()->getStage() === Tenant::STAGE__LIVE) {
  205.             return $this->redirectToRoute(DashboardController::ROUTES__INDEX);
  206.         }
  207.         return $this->transitIssue($taskIdself::TASK_STATUSES__REOPENED);
  208.     }
  209.     /**
  210.      * Provided handling of a transition request
  211.      * 1. Sends comment to issue
  212.      * 2. Making transition call depending on given $transitionId
  213.      *
  214.      * @param int $taskId
  215.      * @param string $status
  216.      * @return RedirectResponse
  217.      * @throws \Exception
  218.      */
  219.     private function transitIssue($taskId$status)
  220.     {
  221.         if ( ! in_array($statusarray_keys($this->getTransitTaskCallback()))) {
  222.             throw new \Exception('Unexpected transition task status');
  223.         }
  224.         // make form
  225.         $form $this->createFormBuilder(
  226.             [],
  227.             array('csrf_protection' => false,)
  228.         )
  229.             ->add('body'TextareaType::class)
  230.             ->getForm();
  231.         // check for submission
  232.         if ($this->handleForm($form)) {
  233.             // add comment
  234.             $this->addComment(
  235.                 $taskId,
  236.                 $this->getGlobalContext()->getEffectiveAccount()->getEmail(),
  237.                 $form->getData()['body']
  238.             );
  239.             $this->getTeamworkPm()->{$this->getTransitTaskCallback()[$status]}($taskId);
  240.             // TODO: log
  241.             // back to listing
  242.             return $this->redirectToRoute(self::ROUTES__INDEX);
  243.         }
  244.         // back to index
  245.         return $this->redirectToRoute(self::ROUTES__INDEX);
  246.     }
  247.     /**
  248.      * Returns array of available transition statuses for TeamworkPM as keys
  249.      * and methods of TeamworkPM service as values
  250.      *
  251.      * @return array
  252.      */
  253.     private function getTransitTaskCallback()
  254.     {
  255.         return array(
  256.             self::TASK_STATUSES__COMPLETED => 'markTaskComplete',
  257.             self::TASK_STATUSES__REOPENED => 'markTaskUncomplete',
  258.         );
  259.     }
  260.     /**
  261.      * @param int $taskId
  262.      * @param string $email
  263.      * @param string $body
  264.      * @return array
  265.      */
  266.     private function addComment($taskId$email$body)
  267.     {
  268.         return $this->getTeamworkPm()->addComment(
  269.             $taskId,
  270.             array(
  271.                 'body' => sprintf(
  272.                     "%s\n\n\n%s",
  273.                     $email,
  274.                     $body
  275.                 )
  276.             )
  277.         );
  278.     }
  279. }