<?php
namespace Cms\ContainerBundle\Controller;
use App\Controller\Dashboard\Websites\DefaultController;
use Cms\ContainerBundle\Entity\Container;
use Cms\ContainerBundle\Entity\Containers\GenericContainer;
use Cms\ContainerBundle\Entity\Containers\IntranetContainer;
use Cms\ContainerBundle\Entity\Containers\PersonalContainer;
use Cms\CoreBundle\Form\Type\SwitchType;
use Cms\CoreBundle\Model\Scenes\DashboardScenes\DocumentScene;
use Cms\CoreBundle\Util\Controller;
use Cms\DomainBundle\Entity\Domain;
use Cms\LogBundle\Entity\RecentFeed;
use Cms\ModuleBundle\Service\ModuleManager;
use Cms\Modules\BlogBundle\Service\BlogModuleConfig;
use Cms\Modules\GalleryBundle\Service\GalleryModuleConfig;
use Cms\Modules\NewsBundle\Service\NewsModuleConfig;
use Cms\Modules\PageBundle\Service\PageModuleConfig;
use Cms\SystemBundle\Entity\Announcement\SystemAnnouncement;
use Cms\TenantBundle\Model\ProductsBitwise;
use Doctrine\ORM\Tools\Pagination\Paginator;
use Platform\ControlPanelBundle\Entity\News;
use Platform\MarketingBundle\Model\ProductControllerInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\SearchType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Laminas\Uri\Uri;
/**
* TODO: the "dashboard" of the application might need to just be its own bundle...
*
* Class DashboardController
* @package Cms\ContainerBundle\Controller
*/
class DashboardController extends Controller implements ProductControllerInterface
{
const ROUTES__INDEX = 'cms.container.dashboard.dashboard.index';
const ROUTES__SANDBOX = 'cms.container.dashboard.dashboard.sandbox';
const ROUTES__CREATE_MODAL = 'cms.container.dashboard.dashboard.create_modal';
const ROUTES__CREATE_MODAL_MODULE = 'cms.container.dashboard.dashboard.create_modal_module';
const ROUTES__RECENTS_MODAL = 'cms.container.dashboard.dashboard.recents_modal';
const ROUTES__HELP_MODAL = 'cms.container.dashboard.dashboard.help_modal';
const ROUTES__CONTAINER__VIEW = ContainerController::ROUTES__VIEW;
const NEWS_ON_PAGE = 5;
/**
* {@inheritdoc}
*/
public function productCheck(ProductsBitwise $products): ?Response
{
// simply requires the cms product
if ( ! $products->hasFlag(ProductsBitwise::SITES__BASE)) {
return $this->redirectToRoute(
'platform.marketing.dashboard.default.cms'
);
}
return null;
}
/**
* @param string|null $slug
* @return DocumentScene
*
* @Route(
* "/sandbox/{slug}",
* name = DashboardController::ROUTES__SANDBOX,
* defaults = {
* "slug" = null
* }
* )
*/
public function sandboxAction(?string $slug = null)
{
if (empty($slug)) {
$finder = new Finder();
$finder->files()->in(
$this->locateResource('@CmsContainerBundle/Resources/views/Dashboard/sandbox')
);
$finder->sortByName();
return $this->view(
[
'files' => $finder,
]
);
}
switch ($slug) {
default:
$vars = [];
}
return $this->view(
sprintf(
'sandbox/%s.html.twig',
$slug
),
$vars
);
}
/**
* @return DocumentScene
*
* @Route(
* "/",
* name = DashboardController::ROUTES__INDEX
* )
*/
public function indexAction()
{
// get all the announcements
$announcements = $this->getEntityManager()->getRepository(SystemAnnouncement::class)->findTenantAnnouncements(
$this->getGlobalContext()->getTenant()
);
// get all the favorites for this user
$favorites = $this->getGlobalContext()->getEffectiveAccount()->getFavorites();
// get all the sites
$sites = $this->getEntityManager()->getRepository(GenericContainer::class)->findAllRoots();
// get news about campus suite project
$news = $this->getEntityManager()->getRepository(News::class)->findForFeed(self::NEWS_ON_PAGE);
// get all teacher sites for current user
$personalSites = $this->getEntityManager()->getRepository(PersonalContainer::class)->findAllRootsForAccount(
$this->getGlobalContext()->getEffectiveAccount()
);
// get all intranets
$intranets = $this->getEntityManager()->getRepository(IntranetContainer::class)->findAllRoots();
// html view stuff
return $this->view(
array(
'announcements' => $announcements,
'favorites' => $favorites,
'sites' => $sites,
'personalSites' => $personalSites,
'news' => $news,
'intranets' => $intranets,
)
);
}
/**
* @param Request $request
* @param Container|null $department
* @return Response
*
* @Route(
* "/_create/{department}",
* name = DashboardController::ROUTES__CREATE_MODAL,
* defaults = {
* "department" = null,
* },
* requirements = {
* "department" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "department",
* class = "Cms\ContainerBundle\Entity\Container",
* )
*/
public function createModalAction(Request $request, ?Container $department = null)
{
return $this->render(
'@CmsContainer/Dashboard/createModal.html.twig',
[
'department' => $department,
'departments' => array_merge(
$this->getEntityManager()->getRepository(PersonalContainer::class)->findAllHierarchy(
null,
[
PersonalContainer::class,
],
$this->getGlobalContext()->getEffectiveAccount()
),
$this->getEntityManager()->getRepository(Container::class)->findAllHierarchy(
null,
[
GenericContainer::class,
IntranetContainer::class,
]
)
),
],
$this->setupCors($request)
);
}
/**
* @param Request|null $request
* @param Response|null $response
* @return Response
*/
protected function setupCors(?Request $request = null, ?Response $response = null): Response
{
if ( ! $request) {
$request = $this->getRequest();
}
if ( ! $response) {
$response = new Response();
}
if ($request->headers->has('Origin')) {
$origin = new Uri($request->headers->get('Origin'));
$host = $origin->getHost();
$domain = $this->getEntityManager()->getRepository(Domain::class)->findOneByHost($host);
if (empty($domain)) {
throw new \Exception();
}
$response->headers->set('Access-Control-Allow-Origin', $origin->getScheme().'://'.$domain->getHost());
$response->headers->set('Access-Control-Allow-Credentials', 'true');
}
return $response;
}
/**
* @param Request $request
* @param Container $department
* @param string $module
* @return Response
*
* @Route(
* "/_create/{department}/{module}",
* name = DashboardController::ROUTES__CREATE_MODAL_MODULE,
* requirements = {
* "department" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "department",
* class = "Cms\ContainerBundle\Entity\Container",
* )
*/
public function createModalModuleAction(Request $request, Container $department, string $module)
{
$form = $this->getFormFactory()->createNamedBuilder('', FormType::class, [], [
'csrf_protection' => false,
]);
// SCHOOLNOW
// HACK: this is really hacky for pages, but can't really figure out anything else right now...
$schoolnow = $request->headers->has('referer') && str_contains($request->headers->get('referer'), '/_dashboard/websites/content/');
$action = null;
if ($department->isSchoolNow()) {
switch (true) {
case $schoolnow && $module === $this->getModuleManager()->getPageModuleConfiguration()->key():
$action = $this->generateUrl(
'app.app.dashboard.websites.content.add_page',
[
'department' => $department->getId(),
],
UrlGeneratorInterface::ABSOLUTE_URL
);
break;
case $module === $this->getModuleManager()->getBlogModuleConfiguration()->key():
case $module === $this->getModuleManager()->getNewsModuleConfiguration()->key():
$action = $this->generateUrl(
'app.app.dashboard.websites.content.posts.post.create',
[
'department' => $department->getId(),
],
UrlGeneratorInterface::ABSOLUTE_URL
);
break;
case $module === $this->getModuleManager()->getGalleryModuleConfiguration()->key():
$action = $this->generateUrl(
'app.app.dashboard.websites.content.exhibits.gallery.create',
[
'department' => $department->getId(),
],
UrlGeneratorInterface::ABSOLUTE_URL
);
break;
case $module === 'video':
$action = $this->generateUrl(
'app.app.dashboard.websites.content.exhibits.video.create',
[
'department' => $department->getId(),
],
UrlGeneratorInterface::ABSOLUTE_URL
);
break;
}
if ($action) {
return $this->setupCors($request, new RedirectResponse($action));
}
}
if ( ! $action) {
$action = $this->generateUrl(
'campussuite.cms.module.dashboard.content.proxy_create',
array_merge(
[
'container' => $department->getId(),
'module' => $module,
],
$schoolnow ? [
'redirectTo' => $this->generateUrl(DefaultController::ROUTES__MAIN),
] : []
),
UrlGeneratorInterface::ABSOLUTE_URL
);
}
$form
->setAction($action)
->setMethod('GET');
switch ($module) {
case $this->getModuleManager()->getPageModuleConfiguration()->key():
$form
->add('prefill_name', TextType::class, [
'label' => 'Page name (internal)',
'helpText' => true,
'attr' => [
'placeholder' => 'e.g. About Us',
'autocomplete' => 'off',
],
])
->add('prefill_nav', SwitchType::class, [
'label' => 'Include in department’s navigation',
'required' => false,
'helpText' => true,
])
->add('prefill_layout', ChoiceType::class, [
'label' => 'Page layout',
'helpText' => true,
'multiple' => false,
'choices' => [
'One column' => '1',
'Two column' => '2',
'Custom' => '0',
],
])
;
break;
default:
return $this->setupCors($request, new RedirectResponse($form->getAction()));
}
return $this->render(
'@CmsContainer/Dashboard/createModalModule.html.twig',
[
'department' => $department,
'form' => $form->getForm()->createView(),
],
$this->setupCors($request)
);
}
/**
* @param Request $request
* @param int $page
* @return Response
*
* @Route(
* "/_recents/{page}",
* name = DashboardController::ROUTES__RECENTS_MODAL,
* requirements = {
* "page" = "\d+"
* },
* defaults = {
* "page" = 0
* }
* )
*/
public function recentsModalAction(Request $request, int $page)
{
static $pageSize = 10;
// generate the search and filtering form
$form = $this->getFormFactory()->createNamedBuilder(
'',
FormType::class,
[
'filter' => 'me',
'search' => null,
'order_field' => 'touchedAt',
'order_direction' => 'DESC',
],
[
'csrf_protection' => false,
]
)
// TODO: add validation for field values for all
->setAction($this->generateUrl(
self::ROUTES__RECENTS_MODAL,
[],
UrlGeneratorInterface::ABSOLUTE_URL)
)
->setMethod('GET')
->add('filter', HiddenType::class, [
'label' => false,
])
->add('search', SearchType::class, [
'label' => false,
'required' => false,
])
->add('order_field', HiddenType::class, [
'label' => false,
])
->add('order_direction', HiddenType::class, [
'label' => false,
])
->getForm();
$form->handleRequest($request);
// create the query to grab the results
$options = $form->getData();
$qb = $this->getEntityManager()->getRepository(RecentFeed::class)->createQueryBuilder('recents')
->orderBy('recents.'.$options['order_field'], $options['order_direction'])
->setFirstResult($page * $pageSize)
->setMaxResults($pageSize);
switch ($options['filter']) {
case 'me':
$qb
->andWhere('recents.account = :account')
->setParameter('account', $this->getGlobalContext()->getEffectiveAccount());
break;
}
if ( ! empty($options['search'])) {
$qb
->andWhere('recents.name LIKE :search')
->setParameter('search', sprintf(
'%%%s%%',
$options['search']
));
}
$paginator = new Paginator($qb, false);
// do optimization to reduce amount of querying done
//$this->getEntityManager()->optimize($paginator);
return $this->render(
'@CmsContainer/Dashboard/recentsModal.html.twig',
[
'form' => $form->createView(),
'recents' => $paginator,
'page' => $page,
'limit' => intval(ceil(count($paginator) / $pageSize) - 1),
],
$this->setupCors($request)
);
}
/**
* @return Response
*
* @Route(
* "/_help",
* name = DashboardController::ROUTES__HELP_MODAL
* )
*/
public function helpModalAction()
{
return $this->render(
'@CmsContainer/Dashboard/helpModal.html.twig',
[],
$this->setupCors()
);
}
/**
* @return ModuleManager|object
*/
private function getModuleManager(): ModuleManager
{
return $this->get(__METHOD__);
}
}