src/Cms/ContainerBundle/Controller/DashboardController.php line 176

Open in your IDE?
  1. <?php
  2. namespace Cms\ContainerBundle\Controller;
  3. use App\Controller\Dashboard\Websites\DefaultController;
  4. use Cms\ContainerBundle\Entity\Container;
  5. use Cms\ContainerBundle\Entity\Containers\GenericContainer;
  6. use Cms\ContainerBundle\Entity\Containers\IntranetContainer;
  7. use Cms\ContainerBundle\Entity\Containers\PersonalContainer;
  8. use Cms\CoreBundle\Form\Type\SwitchType;
  9. use Cms\CoreBundle\Model\Scenes\DashboardScenes\DocumentScene;
  10. use Cms\CoreBundle\Util\Controller;
  11. use Cms\DomainBundle\Entity\Domain;
  12. use Cms\LogBundle\Entity\RecentFeed;
  13. use Cms\ModuleBundle\Service\ModuleManager;
  14. use Cms\Modules\BlogBundle\Service\BlogModuleConfig;
  15. use Cms\Modules\GalleryBundle\Service\GalleryModuleConfig;
  16. use Cms\Modules\NewsBundle\Service\NewsModuleConfig;
  17. use Cms\Modules\PageBundle\Service\PageModuleConfig;
  18. use Cms\SystemBundle\Entity\Announcement\SystemAnnouncement;
  19. use Cms\TenantBundle\Model\ProductsBitwise;
  20. use Doctrine\ORM\Tools\Pagination\Paginator;
  21. use Platform\ControlPanelBundle\Entity\News;
  22. use Platform\MarketingBundle\Model\ProductControllerInterface;
  23. use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
  24. use Symfony\Component\Routing\Annotation\Route;
  25. use Symfony\Component\Finder\Finder;
  26. use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
  27. use Symfony\Component\Form\Extension\Core\Type\FormType;
  28. use Symfony\Component\Form\Extension\Core\Type\HiddenType;
  29. use Symfony\Component\Form\Extension\Core\Type\SearchType;
  30. use Symfony\Component\Form\Extension\Core\Type\TextType;
  31. use Symfony\Component\HttpFoundation\RedirectResponse;
  32. use Symfony\Component\HttpFoundation\Request;
  33. use Symfony\Component\HttpFoundation\Response;
  34. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  35. use Laminas\Uri\Uri;
  36. /**
  37.  * TODO: the "dashboard" of the application might need to just be its own bundle...
  38.  *
  39.  * Class DashboardController
  40.  * @package Cms\ContainerBundle\Controller
  41.  */
  42. class DashboardController extends Controller implements ProductControllerInterface
  43. {
  44.     const ROUTES__INDEX 'cms.container.dashboard.dashboard.index';
  45.     const ROUTES__SANDBOX 'cms.container.dashboard.dashboard.sandbox';
  46.     const ROUTES__CREATE_MODAL 'cms.container.dashboard.dashboard.create_modal';
  47.     const ROUTES__CREATE_MODAL_MODULE 'cms.container.dashboard.dashboard.create_modal_module';
  48.     const ROUTES__RECENTS_MODAL 'cms.container.dashboard.dashboard.recents_modal';
  49.     const ROUTES__HELP_MODAL 'cms.container.dashboard.dashboard.help_modal';
  50.     const ROUTES__CONTAINER__VIEW ContainerController::ROUTES__VIEW;
  51.     const NEWS_ON_PAGE 5;
  52.     /**
  53.      * {@inheritdoc}
  54.      */
  55.     public function productCheck(ProductsBitwise $products): ?Response
  56.     {
  57.         // simply requires the cms product
  58.         if ( ! $products->hasFlag(ProductsBitwise::SITES__BASE)) {
  59.             return $this->redirectToRoute(
  60.                 'platform.marketing.dashboard.default.cms'
  61.             );
  62.         }
  63.         return null;
  64.     }
  65.     /**
  66.      * @param string|null $slug
  67.      * @return DocumentScene
  68.      *
  69.      * @Route(
  70.      *     "/sandbox/{slug}",
  71.      *     name = DashboardController::ROUTES__SANDBOX,
  72.      *     defaults = {
  73.      *         "slug" = null
  74.      *     }
  75.      * )
  76.      */
  77.     public function sandboxAction(?string $slug null)
  78.     {
  79.         if (empty($slug)) {
  80.             $finder = new Finder();
  81.             $finder->files()->in(
  82.                 $this->locateResource('@CmsContainerBundle/Resources/views/Dashboard/sandbox')
  83.             );
  84.             $finder->sortByName();
  85.             return $this->view(
  86.                 [
  87.                     'files' => $finder,
  88.                 ]
  89.             );
  90.         }
  91.         switch ($slug) {
  92.             default:
  93.                 $vars = [];
  94.         }
  95.         return $this->view(
  96.             sprintf(
  97.                 'sandbox/%s.html.twig',
  98.                 $slug
  99.             ),
  100.             $vars
  101.         );
  102.     }
  103.     /**
  104.      * @return DocumentScene
  105.      *
  106.      * @Route(
  107.      *  "/",
  108.      *  name = DashboardController::ROUTES__INDEX
  109.      * )
  110.      */
  111.     public function indexAction()
  112.     {
  113.         // get all the announcements
  114.         $announcements $this->getEntityManager()->getRepository(SystemAnnouncement::class)->findTenantAnnouncements(
  115.             $this->getGlobalContext()->getTenant()
  116.         );
  117.         // get all the favorites for this user
  118.         $favorites $this->getGlobalContext()->getEffectiveAccount()->getFavorites();
  119.         // get all the sites
  120.         $sites $this->getEntityManager()->getRepository(GenericContainer::class)->findAllRoots();
  121.         // get news about campus suite project
  122.         $news $this->getEntityManager()->getRepository(News::class)->findForFeed(self::NEWS_ON_PAGE);
  123.         // get all teacher sites for current user
  124.         $personalSites $this->getEntityManager()->getRepository(PersonalContainer::class)->findAllRootsForAccount(
  125.             $this->getGlobalContext()->getEffectiveAccount()
  126.         );
  127.         // get all intranets
  128.         $intranets $this->getEntityManager()->getRepository(IntranetContainer::class)->findAllRoots();
  129.         // html view stuff
  130.         return $this->view(
  131.             array(
  132.                 'announcements' => $announcements,
  133.                 'favorites' => $favorites,
  134.                 'sites' => $sites,
  135.                 'personalSites' => $personalSites,
  136.                 'news' => $news,
  137.                 'intranets' => $intranets,
  138.             )
  139.         );
  140.     }
  141.     /**
  142.      * @param Request $request
  143.      * @param Container|null $department
  144.      * @return Response
  145.      *
  146.      * @Route(
  147.      *     "/_create/{department}",
  148.      *     name = DashboardController::ROUTES__CREATE_MODAL,
  149.      *     defaults = {
  150.      *         "department" = null,
  151.      *     },
  152.      *     requirements = {
  153.      *         "department" = "[1-9]\d*",
  154.      *     },
  155.      * )
  156.      * @ParamConverter(
  157.      *     "department",
  158.      *     class = "Cms\ContainerBundle\Entity\Container",
  159.      * )
  160.      */
  161.     public function createModalAction(Request $request, ?Container $department null)
  162.     {
  163.         return $this->render(
  164.             '@CmsContainer/Dashboard/createModal.html.twig',
  165.             [
  166.                 'department' => $department,
  167.                 'departments' => array_merge(
  168.                     $this->getEntityManager()->getRepository(PersonalContainer::class)->findAllHierarchy(
  169.                         null,
  170.                         [
  171.                             PersonalContainer::class,
  172.                         ],
  173.                         $this->getGlobalContext()->getEffectiveAccount()
  174.                     ),
  175.                     $this->getEntityManager()->getRepository(Container::class)->findAllHierarchy(
  176.                         null,
  177.                         [
  178.                             GenericContainer::class,
  179.                             IntranetContainer::class,
  180.                         ]
  181.                     )
  182.                 ),
  183.             ],
  184.             $this->setupCors($request)
  185.         );
  186.     }
  187.     /**
  188.      * @param Request|null $request
  189.      * @param Response|null $response
  190.      * @return Response
  191.      */
  192.     protected function setupCors(?Request $request null, ?Response $response null): Response
  193.     {
  194.         if ( ! $request) {
  195.             $request $this->getRequest();
  196.         }
  197.         if ( ! $response) {
  198.             $response = new Response();
  199.         }
  200.         if ($request->headers->has('Origin')) {
  201.             $origin = new Uri($request->headers->get('Origin'));
  202.             $host $origin->getHost();
  203.             $domain $this->getEntityManager()->getRepository(Domain::class)->findOneByHost($host);
  204.             if (empty($domain)) {
  205.                 throw new \Exception();
  206.             }
  207.             $response->headers->set('Access-Control-Allow-Origin'$origin->getScheme().'://'.$domain->getHost());
  208.             $response->headers->set('Access-Control-Allow-Credentials''true');
  209.         }
  210.         return $response;
  211.     }
  212.     /**
  213.      * @param Request $request
  214.      * @param Container $department
  215.      * @param string $module
  216.      * @return Response
  217.      *
  218.      * @Route(
  219.      *     "/_create/{department}/{module}",
  220.      *     name = DashboardController::ROUTES__CREATE_MODAL_MODULE,
  221.      *     requirements = {
  222.      *         "department" = "[1-9]\d*",
  223.      *     },
  224.      * )
  225.      * @ParamConverter(
  226.      *     "department",
  227.      *     class = "Cms\ContainerBundle\Entity\Container",
  228.      * )
  229.      */
  230.     public function createModalModuleAction(Request $requestContainer $departmentstring $module)
  231.     {
  232.         $form $this->getFormFactory()->createNamedBuilder(''FormType::class, [], [
  233.             'csrf_protection' => false,
  234.         ]);
  235.         // SCHOOLNOW
  236.         // HACK: this is really hacky for pages, but can't really figure out anything else right now...
  237.         $schoolnow $request->headers->has('referer') && str_contains($request->headers->get('referer'), '/_dashboard/websites/content/');
  238.         $action null;
  239.         if ($department->isSchoolNow()) {
  240.             switch (true) {
  241.                 case $schoolnow && $module === $this->getModuleManager()->getPageModuleConfiguration()->key():
  242.                     $action $this->generateUrl(
  243.                         'app.app.dashboard.websites.content.add_page',
  244.                         [
  245.                             'department' => $department->getId(),
  246.                         ],
  247.                         UrlGeneratorInterface::ABSOLUTE_URL
  248.                     );
  249.                     break;
  250.                 case $module === $this->getModuleManager()->getBlogModuleConfiguration()->key():
  251.                 case $module === $this->getModuleManager()->getNewsModuleConfiguration()->key():
  252.                     $action $this->generateUrl(
  253.                         'app.app.dashboard.websites.content.posts.post.create',
  254.                         [
  255.                             'department' => $department->getId(),
  256.                         ],
  257.                         UrlGeneratorInterface::ABSOLUTE_URL
  258.                     );
  259.                     break;
  260.                 case $module === $this->getModuleManager()->getGalleryModuleConfiguration()->key():
  261.                     $action $this->generateUrl(
  262.                         'app.app.dashboard.websites.content.exhibits.gallery.create',
  263.                         [
  264.                             'department' => $department->getId(),
  265.                         ],
  266.                         UrlGeneratorInterface::ABSOLUTE_URL
  267.                     );
  268.                     break;
  269.                 case $module === 'video':
  270.                     $action $this->generateUrl(
  271.                         'app.app.dashboard.websites.content.exhibits.video.create',
  272.                         [
  273.                             'department' => $department->getId(),
  274.                         ],
  275.                         UrlGeneratorInterface::ABSOLUTE_URL
  276.                     );
  277.                     break;
  278.             }
  279.             if ($action) {
  280.                 return $this->setupCors($request, new RedirectResponse($action));
  281.             }
  282.         }
  283.         if ( ! $action) {
  284.             $action $this->generateUrl(
  285.                 'campussuite.cms.module.dashboard.content.proxy_create',
  286.                 array_merge(
  287.                     [
  288.                         'container' => $department->getId(),
  289.                         'module' => $module,
  290.                     ],
  291.                     $schoolnow ? [
  292.                         'redirectTo' => $this->generateUrl(DefaultController::ROUTES__MAIN),
  293.                     ] : []
  294.                 ),
  295.                 UrlGeneratorInterface::ABSOLUTE_URL
  296.             );
  297.         }
  298.         $form
  299.             ->setAction($action)
  300.             ->setMethod('GET');
  301.         switch ($module) {
  302.             case $this->getModuleManager()->getPageModuleConfiguration()->key():
  303.                 $form
  304.                     ->add('prefill_name'TextType::class, [
  305.                         'label' => 'Page name (internal)',
  306.                         'helpText' => true,
  307.                         'attr' => [
  308.                             'placeholder' => 'e.g. About Us',
  309.                             'autocomplete' => 'off',
  310.                         ],
  311.                     ])
  312.                     ->add('prefill_nav'SwitchType::class, [
  313.                         'label' => 'Include in department’s navigation',
  314.                         'required' => false,
  315.                         'helpText' => true,
  316.                     ])
  317.                     ->add('prefill_layout'ChoiceType::class, [
  318.                         'label' => 'Page layout',
  319.                         'helpText' => true,
  320.                         'multiple' => false,
  321.                         'choices' => [
  322.                             'One column' => '1',
  323.                             'Two column' => '2',
  324.                             'Custom' => '0',
  325.                         ],
  326.                     ])
  327.                 ;
  328.                 break;
  329.             default:
  330.                 return $this->setupCors($request, new RedirectResponse($form->getAction()));
  331.         }
  332.         return $this->render(
  333.             '@CmsContainer/Dashboard/createModalModule.html.twig',
  334.             [
  335.                 'department' => $department,
  336.                 'form' => $form->getForm()->createView(),
  337.             ],
  338.             $this->setupCors($request)
  339.         );
  340.     }
  341.     /**
  342.      * @param Request $request
  343.      * @param int $page
  344.      * @return Response
  345.      *
  346.      * @Route(
  347.      *     "/_recents/{page}",
  348.      *     name = DashboardController::ROUTES__RECENTS_MODAL,
  349.      *     requirements = {
  350.      *         "page" = "\d+"
  351.      *     },
  352.      *     defaults = {
  353.      *         "page" = 0
  354.      *     }
  355.      * )
  356.      */
  357.     public function recentsModalAction(Request $requestint $page)
  358.     {
  359.         static $pageSize 10;
  360.         // generate the search and filtering form
  361.         $form $this->getFormFactory()->createNamedBuilder(
  362.             '',
  363.             FormType::class,
  364.             [
  365.                 'filter' => 'me',
  366.                 'search' => null,
  367.                 'order_field' => 'touchedAt',
  368.                 'order_direction' => 'DESC',
  369.             ],
  370.             [
  371.                 'csrf_protection' => false,
  372.             ]
  373.         )
  374.             // TODO: add validation for field values for all
  375.             ->setAction($this->generateUrl(
  376.                 self::ROUTES__RECENTS_MODAL,
  377.                 [],
  378.                 UrlGeneratorInterface::ABSOLUTE_URL)
  379.             )
  380.             ->setMethod('GET')
  381.             ->add('filter'HiddenType::class, [
  382.                 'label' => false,
  383.             ])
  384.             ->add('search'SearchType::class, [
  385.                 'label' => false,
  386.                 'required' => false,
  387.             ])
  388.             ->add('order_field'HiddenType::class, [
  389.                 'label' => false,
  390.             ])
  391.             ->add('order_direction'HiddenType::class, [
  392.                 'label' => false,
  393.             ])
  394.             ->getForm();
  395.         $form->handleRequest($request);
  396.         // create the query to grab the results
  397.         $options $form->getData();
  398.         $qb $this->getEntityManager()->getRepository(RecentFeed::class)->createQueryBuilder('recents')
  399.             ->orderBy('recents.'.$options['order_field'], $options['order_direction'])
  400.             ->setFirstResult($page $pageSize)
  401.             ->setMaxResults($pageSize);
  402.         switch ($options['filter']) {
  403.             case 'me':
  404.                 $qb
  405.                     ->andWhere('recents.account = :account')
  406.                     ->setParameter('account'$this->getGlobalContext()->getEffectiveAccount());
  407.                 break;
  408.         }
  409.         if ( ! empty($options['search'])) {
  410.             $qb
  411.                 ->andWhere('recents.name LIKE :search')
  412.                 ->setParameter('search'sprintf(
  413.                     '%%%s%%',
  414.                     $options['search']
  415.                 ));
  416.         }
  417.         $paginator = new Paginator($qbfalse);
  418.         // do optimization to reduce amount of querying done
  419.         //$this->getEntityManager()->optimize($paginator);
  420.         return $this->render(
  421.             '@CmsContainer/Dashboard/recentsModal.html.twig',
  422.             [
  423.                 'form' => $form->createView(),
  424.                 'recents' => $paginator,
  425.                 'page' => $page,
  426.                 'limit' => intval(ceil(count($paginator) / $pageSize) - 1),
  427.             ],
  428.             $this->setupCors($request)
  429.         );
  430.     }
  431.     /**
  432.      * @return Response
  433.      *
  434.      * @Route(
  435.      *     "/_help",
  436.      *     name = DashboardController::ROUTES__HELP_MODAL
  437.      * )
  438.      */
  439.     public function helpModalAction()
  440.     {
  441.         return $this->render(
  442.             '@CmsContainer/Dashboard/helpModal.html.twig',
  443.             [],
  444.             $this->setupCors()
  445.         );
  446.     }
  447.     /**
  448.      * @return ModuleManager|object
  449.      */
  450.     private function getModuleManager(): ModuleManager
  451.     {
  452.         return $this->get(__METHOD__);
  453.     }
  454. }