Spaces:
No application file
No application file
namespace Mautic\CoreBundle\Controller; | |
use Mautic\CoreBundle\Exception\BadConfigurationException; | |
use Mautic\CoreBundle\Exception\FileNotFoundException; | |
use Mautic\CoreBundle\Form\Type\ThemeUploadType; | |
use Mautic\CoreBundle\Helper\InputHelper; | |
use Mautic\CoreBundle\Helper\ThemeHelperInterface; | |
use Mautic\CoreBundle\Security\Permissions\CorePermissions; | |
use Mautic\IntegrationsBundle\Helper\BuilderIntegrationsHelper; | |
use Symfony\Component\Filesystem\Exception\IOException; | |
use Symfony\Component\Form\FormError; | |
use Symfony\Component\HttpFoundation\JsonResponse; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
class ThemeController extends FormController | |
{ | |
/** | |
* @return JsonResponse|Response | |
*/ | |
public function indexAction(Request $request, ThemeHelperInterface $themeHelper, BuilderIntegrationsHelper $builderIntegrationsHelper) | |
{ | |
// set some permissions | |
$permissions = $this->security->isGranted([ | |
'core:themes:view', | |
'core:themes:create', | |
'core:themes:edit', | |
'core:themes:delete', | |
], 'RETURN_ARRAY'); | |
if (!$permissions['core:themes:view']) { | |
return $this->accessDenied(); | |
} | |
$dir = $this->factory->getSystemPath('themes', true); | |
$action = $this->generateUrl('mautic_themes_index'); | |
$form = $this->formFactory->create(ThemeUploadType::class, [], ['action' => $action]); | |
if ('POST' === $request->getMethod()) { | |
if (!$this->isFormCancelled($form)) { | |
if ($this->isFormValid($form)) { | |
$fileData = $form['file']->getData(); | |
if (!$fileData) { | |
$form->addError( | |
new FormError( | |
$this->translator->trans('mautic.core.theme.upload.empty', [], 'validators') | |
) | |
); | |
} else { | |
$fileName = InputHelper::filename($fileData->getClientOriginalName()); | |
$themeName = basename($fileName, '.zip'); | |
if (!empty($fileData)) { | |
$extension = pathinfo($fileName, PATHINFO_EXTENSION); | |
if ('zip' === $extension) { | |
try { | |
$fileData->move($dir, $fileName); | |
$themeHelper->install($dir.'/'.$fileName); | |
$this->addFlashMessage('mautic.core.theme.installed', ['%name%' => $themeName]); | |
} catch (\Exception $e) { | |
$form->addError( | |
new FormError( | |
$this->translator->trans($e->getMessage(), [], 'validators') | |
) | |
); | |
} | |
} else { | |
$form->addError( | |
new FormError( | |
$this->translator->trans('mautic.core.not.allowed.file.extension', ['%extension%' => $extension], 'validators') | |
) | |
); | |
} | |
} else { | |
$form->addError( | |
new FormError( | |
$this->translator->trans('mautic.dashboard.upload.filenotfound', [], 'validators') | |
) | |
); | |
} | |
} | |
} | |
} | |
} | |
return $this->delegateView([ | |
'viewParameters' => [ | |
'items' => $themeHelper->getInstalledThemes('all', true, true), | |
'builders' => $builderIntegrationsHelper->getBuilderNames(), | |
'defaultThemes' => $themeHelper->getDefaultThemes(), | |
'form' => $form->createView(), | |
'permissions' => $permissions, | |
'security' => $this->security, | |
], | |
'contentTemplate' => '@MauticCore/Theme/list.html.twig', | |
'passthroughVars' => [ | |
'activeLink' => '#mautic_themes_index', | |
'mauticContent' => 'theme', | |
'route' => $this->generateUrl('mautic_themes_index'), | |
], | |
]); | |
} | |
/** | |
* Download a theme. | |
* | |
* @return JsonResponse|\Symfony\Component\HttpFoundation\RedirectResponse|Response | |
*/ | |
public function downloadAction(Request $request, ThemeHelperInterface $themeHelper, string $objectId) | |
{ | |
$flashes = []; | |
$error = false; | |
if (!$this->security->isGranted('core:themes:view')) { | |
return $this->accessDenied(); | |
} | |
$themeName = $objectId; | |
if (!$themeHelper->exists($themeName)) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.error.notfound', | |
'msgVars' => ['%theme%' => $themeName], | |
]; | |
$error = true; | |
} | |
try { | |
$zipPath = $themeHelper->zip($themeName); | |
} catch (\Exception $e) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => $e->getMessage(), | |
]; | |
$error = true; | |
} | |
if (!$error && !$zipPath) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.permission.issue', | |
]; | |
$error = true; | |
} | |
if ($error) { | |
return $this->postActionRedirect( | |
array_merge($this->getIndexPostActionVars(), [ | |
'flashes' => $flashes, | |
]) | |
); | |
} | |
$response = new Response(); | |
$response->headers->set('Content-Type', 'application/octet-stream'); | |
$response->headers->set('Content-Length', (string) filesize($zipPath)); | |
$stream = $request->get('stream', 0); | |
if (!$stream) { | |
$response->headers->set('Content-Disposition', 'attachment;filename="'.$themeName.'.zip"'); | |
} | |
$response->setContent(file_get_contents($zipPath)); | |
return $response; | |
} | |
/** | |
* Deletes the theme. | |
* | |
* @return Response | |
*/ | |
public function deleteAction(Request $request, ThemeHelperInterface $themeHelper, string $objectId) | |
{ | |
$flashes = []; | |
$themeName = $objectId; | |
if ('POST' === $request->getMethod()) { | |
$flashes = $this->deleteTheme($themeHelper, $themeName); | |
} | |
return $this->postActionRedirect( | |
array_merge($this->getIndexPostActionVars(), [ | |
'flashes' => $flashes, | |
]) | |
); | |
} | |
/** | |
* Deletes a group of themes. | |
* | |
* @return Response | |
*/ | |
public function batchDeleteAction(Request $request, ThemeHelperInterface $themeHelper) | |
{ | |
$flashes = []; | |
if ('POST' === $request->getMethod()) { | |
$themeNames = json_decode($request->query->get('ids', '{}')); | |
foreach ($themeNames as $themeName) { | |
$flashes = $this->deleteTheme($themeHelper, $themeName); | |
} | |
} | |
return $this->postActionRedirect( | |
array_merge($this->getIndexPostActionVars(), [ | |
'flashes' => $flashes, | |
]) | |
); | |
} | |
/** | |
* Deletes a theme. | |
* | |
* @return array | |
*/ | |
public function deleteTheme(ThemeHelperInterface $themeHelper, $themeName) | |
{ | |
$flashes = []; | |
if (!$themeHelper->exists($themeName)) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.error.notfound', | |
'msgVars' => ['%theme%' => $themeName], | |
]; | |
} elseif (!$this->security->isGranted('core:themes:delete')) { | |
return $this->accessDenied(); | |
} elseif (in_array($themeName, $themeHelper->getDefaultThemes())) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.cannot.be.removed', | |
'msgVars' => ['%theme%' => $themeName], | |
]; | |
} else { | |
try { | |
$theme = $themeHelper->getTheme($themeName); | |
$themeHelper->delete($themeName); | |
} catch (\Exception $e) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.error.delete.error', | |
'msgVars' => ['%error%' => $e->getMessage()], | |
]; | |
} | |
$flashes[] = [ | |
'type' => 'notice', | |
'msg' => 'mautic.core.notice.deleted', | |
'msgVars' => [ | |
'%name%' => $theme->getName(), | |
'%id%' => $themeName, | |
], | |
]; | |
} | |
return $flashes; | |
} | |
/** | |
* A helper method to keep the code DRY. | |
*/ | |
public function getIndexPostActionVars(): array | |
{ | |
return [ | |
'returnUrl' => $this->generateUrl('mautic_themes_index'), | |
'contentTemplate' => 'Mautic\CoreBundle\Controller\ThemeController::indexAction', | |
'passthroughVars' => [ | |
'activeLink' => 'mautic_themes_index', | |
'mauticContent' => 'theme', | |
], | |
]; | |
} | |
/** | |
* Change default theme's visibility. | |
*/ | |
public function visibilityAction(string $objectId, Request $request, CorePermissions $corePermissions, ThemeHelperInterface $themeHelper): Response | |
{ | |
if (!$corePermissions->isGranted('core:themes:view')) { | |
return $this->accessDenied(); | |
} | |
$flashes = []; | |
if (Request::METHOD_POST === $request->getMethod()) { | |
$flashes = $this->visibility($objectId, $themeHelper); | |
} | |
return $this->postActionRedirect( | |
array_merge($this->getIndexPostActionVars(), [ | |
'flashes' => $flashes, | |
]) | |
); | |
} | |
/** | |
* @return array<mixed> | |
*/ | |
private function visibility(string $themeName, ThemeHelperInterface $themeHelper): array | |
{ | |
if (!$themeHelper->exists($themeName)) { | |
return [ | |
[ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.error.notfound', | |
'msgVars' => ['%theme%' => $themeName], | |
], | |
]; | |
} | |
if (!in_array($themeName, $themeHelper->getDefaultThemes())) { | |
return [ | |
[ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.cannot.change.visibility', | |
'msgVars' => ['%theme%' => $themeName], | |
], | |
]; | |
} | |
$flashes = []; | |
try { | |
$theme = $themeHelper->getTheme($themeName); | |
$themeHelper->toggleVisibility($themeName); | |
$flashes[] = [ | |
'type' => 'notice', | |
'msg' => 'mautic.core.theme.visibility.changed', | |
'msgVars' => ['%theme%' => $theme->getName()], | |
]; | |
} catch (IOException) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.visibility.error', | |
'msgVars' => ['%error%' => 'Failed to change the theme visibility'], | |
]; | |
} catch (BadConfigurationException) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.visibility.error', | |
'msgVars' => ['%error%' => sprintf('Theme %s not configured properly: builder property in the config.json', $themeName)], | |
]; | |
} catch (FileNotFoundException) { | |
$flashes[] = [ | |
'type' => 'error', | |
'msg' => 'mautic.core.theme.visibility.error', | |
'msgVars' => ['%error%' => sprintf('Theme %s not found', $themeName)], | |
]; | |
} | |
return $flashes; | |
} | |
} | |