Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\DashboardBundle\Controller;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Mautic\CoreBundle\Controller\AjaxController as CommonAjaxController;
|
||||
use Mautic\DashboardBundle\Entity\Widget;
|
||||
use Mautic\DashboardBundle\Form\Type\WidgetType;
|
||||
use Mautic\DashboardBundle\Model\DashboardModel;
|
||||
use Mautic\PageBundle\Entity\Hit;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class AjaxController extends CommonAjaxController
|
||||
{
|
||||
/**
|
||||
* Count how many visitors are currently viewing a page.
|
||||
*/
|
||||
public function viewingVisitorsAction(EntityManagerInterface $entityManager): JsonResponse
|
||||
{
|
||||
$dataArray = ['success' => 0];
|
||||
|
||||
/** @var \Mautic\PageBundle\Entity\PageRepository $pageRepository */
|
||||
$pageRepository = $entityManager->getRepository(Hit::class);
|
||||
$dataArray['viewingVisitors'] = $pageRepository->countVisitors(60, true);
|
||||
|
||||
$dataArray['success'] = 1;
|
||||
|
||||
return $this->sendJsonResponse($dataArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML of a new widget based on its values.
|
||||
*/
|
||||
public function updateWidgetFormAction(Request $request, FormFactoryInterface $formFactory): JsonResponse
|
||||
{
|
||||
$data = $request->request->all()['widget'] ?? [];
|
||||
$dataArray = ['success' => 0];
|
||||
|
||||
// Clear params if type is not selected
|
||||
if (empty($data['type'])) {
|
||||
unset($data['params']);
|
||||
}
|
||||
|
||||
$widget = new Widget();
|
||||
$form = $formFactory->create(WidgetType::class, $widget);
|
||||
$formHtml = $this->render('@MauticDashboard/Widget/form.html.twig',
|
||||
['form' => $form->submit($data)->createView()]
|
||||
)->getContent();
|
||||
|
||||
$dataArray['formHtml'] = $formHtml;
|
||||
$dataArray['success'] = 1;
|
||||
|
||||
return $this->sendJsonResponse($dataArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the new ordering of dashboard widgets.
|
||||
*/
|
||||
public function updateWidgetOrderingAction(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->request->all()['ordering'] ?? [];
|
||||
$dashboardModel = $this->getModel('dashboard');
|
||||
\assert($dashboardModel instanceof DashboardModel);
|
||||
$repo = $dashboardModel->getRepository();
|
||||
$repo->updateOrdering(array_flip($data), $this->user->getId());
|
||||
$dataArray = ['success' => 1];
|
||||
|
||||
return $this->sendJsonResponse($dataArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entity.
|
||||
*/
|
||||
public function deleteAction(Request $request): JsonResponse
|
||||
{
|
||||
$objectId = $request->request->get('widget');
|
||||
$dataArray = ['success' => 0];
|
||||
|
||||
// @todo: build permissions
|
||||
// if (!$this->security->isGranted('dashobard:widgets:delete')) {
|
||||
// return $this->accessDenied();
|
||||
// }
|
||||
|
||||
/** @var DashboardModel $model */
|
||||
$model = $this->getModel('dashboard');
|
||||
$entity = $model->getEntity($objectId);
|
||||
if ($entity) {
|
||||
$model->deleteEntity($entity);
|
||||
$name = $entity->getName();
|
||||
$dataArray['success'] = 1;
|
||||
}
|
||||
|
||||
return $this->sendJsonResponse($dataArray);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\DashboardBundle\Controller\Api;
|
||||
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
use Mautic\ApiBundle\Controller\CommonApiController;
|
||||
use Mautic\ApiBundle\Helper\EntityResultHelper;
|
||||
use Mautic\CoreBundle\Factory\ModelFactory;
|
||||
use Mautic\CoreBundle\Helper\AppVersion;
|
||||
use Mautic\CoreBundle\Helper\CoreParametersHelper;
|
||||
use Mautic\CoreBundle\Helper\DateTimeHelper;
|
||||
use Mautic\CoreBundle\Helper\InputHelper;
|
||||
use Mautic\CoreBundle\Security\Permissions\CorePermissions;
|
||||
use Mautic\CoreBundle\Translation\Translator;
|
||||
use Mautic\DashboardBundle\DashboardEvents;
|
||||
use Mautic\DashboardBundle\Entity\Widget;
|
||||
use Mautic\DashboardBundle\Event\WidgetTypeListEvent;
|
||||
use Mautic\DashboardBundle\Model\DashboardModel;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
/**
|
||||
* @extends CommonApiController<Widget>
|
||||
*/
|
||||
class WidgetApiController extends CommonApiController
|
||||
{
|
||||
/**
|
||||
* @var DashboardModel|null
|
||||
*/
|
||||
protected $model;
|
||||
|
||||
public function __construct(CorePermissions $security, Translator $translator, EntityResultHelper $entityResultHelper, RouterInterface $router, FormFactoryInterface $formFactory, AppVersion $appVersion, RequestStack $requestStack, ManagerRegistry $doctrine, ModelFactory $modelFactory, EventDispatcherInterface $dispatcher, CoreParametersHelper $coreParametersHelper)
|
||||
{
|
||||
$dashboardModel = $modelFactory->getModel('dashboard');
|
||||
\assert($dashboardModel instanceof DashboardModel);
|
||||
|
||||
$this->model = $dashboardModel;
|
||||
$this->entityClass = Widget::class;
|
||||
$this->entityNameOne = 'widget';
|
||||
$this->entityNameMulti = 'widgets';
|
||||
$this->serializerGroups = [];
|
||||
|
||||
parent::__construct($security, $translator, $entityResultHelper, $router, $formFactory, $appVersion, $requestStack, $doctrine, $modelFactory, $dispatcher, $coreParametersHelper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a list of available widget types.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getTypesAction()
|
||||
{
|
||||
$dispatcher = $this->dispatcher;
|
||||
$event = new WidgetTypeListEvent();
|
||||
$event->setTranslator($this->translator);
|
||||
$dispatcher->dispatch($event, DashboardEvents::DASHBOARD_ON_MODULE_LIST_GENERATE);
|
||||
$view = $this->view(['success' => 1, 'types' => $event->getTypes()], Response::HTTP_OK);
|
||||
|
||||
return $this->handleView($view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a list of available widget types.
|
||||
*
|
||||
* @param string $type of the widget
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getDataAction(Request $request, $type)
|
||||
{
|
||||
$start = microtime(true);
|
||||
$timezone = InputHelper::clean($request->get('timezone', null));
|
||||
$from = InputHelper::clean($request->get('dateFrom', null));
|
||||
$to = InputHelper::clean($request->get('dateTo', null));
|
||||
$dataFormat = InputHelper::clean($request->get('dataFormat', null));
|
||||
$unit = InputHelper::clean($request->get('timeUnit', 'Y'));
|
||||
$dataset = InputHelper::clean($request->query->all()['dataset'] ?? $request->request->all()['dataset'] ?? []);
|
||||
$response = ['success' => 0];
|
||||
|
||||
try {
|
||||
DateTimeHelper::validateMysqlDateTimeUnit($unit);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
return $this->returnError($e->getMessage(), Response::HTTP_BAD_REQUEST);
|
||||
}
|
||||
|
||||
if ($timezone) {
|
||||
$fromDate = new \DateTime($from, new \DateTimeZone($timezone));
|
||||
$toDate = new \DateTime($to, new \DateTimeZone($timezone));
|
||||
} else {
|
||||
$fromDate = new \DateTime($from);
|
||||
$toDate = new \DateTime($to);
|
||||
}
|
||||
|
||||
$params = [
|
||||
'timeUnit' => InputHelper::clean($request->get('timeUnit', 'Y')),
|
||||
'dateFormat' => InputHelper::clean($request->get('dateFormat', null)),
|
||||
'dateFrom' => $fromDate,
|
||||
'dateTo' => $toDate,
|
||||
'limit' => (int) $request->get('limit', null),
|
||||
'filter' => InputHelper::clean($request->query->all()['filter'] ?? $request->request->all()['filter'] ?? []),
|
||||
'dataset' => $dataset,
|
||||
];
|
||||
|
||||
// Merge filters into the root array as well as that's how widget edit forms send them.
|
||||
$params = array_merge($params, $params['filter']);
|
||||
|
||||
$cacheTimeout = (int) $request->get('cacheTimeout', 0);
|
||||
$widgetHeight = (int) $request->get('height', 300);
|
||||
|
||||
$widget = new Widget();
|
||||
$widget->setParams($params);
|
||||
$widget->setType($type);
|
||||
$widget->setHeight($widgetHeight);
|
||||
$widget->setCacheTimeout($cacheTimeout);
|
||||
|
||||
$this->model->populateWidgetContent($widget);
|
||||
$data = $widget->getTemplateData();
|
||||
|
||||
if (!$data) {
|
||||
return $this->notFound();
|
||||
}
|
||||
|
||||
if ('raw' == $dataFormat) {
|
||||
if (isset($data['chartData']['labels']) && isset($data['chartData']['datasets'])) {
|
||||
$rawData = [];
|
||||
foreach ($data['chartData']['datasets'] as $dataset) {
|
||||
$rawData[$dataset['label']] = [];
|
||||
foreach ($dataset['data'] as $key => $value) {
|
||||
$rawData[$dataset['label']][$data['chartData']['labels'][$key]] = $value;
|
||||
}
|
||||
}
|
||||
$data = $rawData;
|
||||
} elseif (isset($data['raw'])) {
|
||||
$data = $data['raw'];
|
||||
}
|
||||
} else {
|
||||
if (isset($data['raw'])) {
|
||||
unset($data['raw']);
|
||||
}
|
||||
}
|
||||
|
||||
$response['cached'] = $widget->isCached();
|
||||
$response['execution_time'] = microtime(true) - $start;
|
||||
$response['success'] = 1;
|
||||
$response['data'] = $data;
|
||||
|
||||
$view = $this->view($response, Response::HTTP_OK);
|
||||
|
||||
return $this->handleView($view);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,562 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\DashboardBundle\Controller;
|
||||
|
||||
use Mautic\CoreBundle\Controller\AbstractFormController;
|
||||
use Mautic\CoreBundle\Form\Type\DateRangeType;
|
||||
use Mautic\CoreBundle\Helper\DateTimeHelper;
|
||||
use Mautic\CoreBundle\Helper\InputHelper;
|
||||
use Mautic\CoreBundle\Helper\PathsHelper;
|
||||
use Mautic\CoreBundle\Helper\PhpVersionHelper;
|
||||
use Mautic\CoreBundle\Release\ThisRelease;
|
||||
use Mautic\DashboardBundle\Dashboard\Widget as WidgetService;
|
||||
use Mautic\DashboardBundle\Entity\Widget;
|
||||
use Mautic\DashboardBundle\Form\Type\UploadType;
|
||||
use Mautic\DashboardBundle\Model\DashboardModel;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
use Twig\Environment;
|
||||
|
||||
class DashboardController extends AbstractFormController
|
||||
{
|
||||
/**
|
||||
* Generates the default view.
|
||||
*/
|
||||
public function indexAction(Request $request, WidgetService $widget, FormFactoryInterface $formFactory, PathsHelper $pathsHelper, RouterInterface $urlGenerator): Response
|
||||
{
|
||||
$model = $this->getModel('dashboard');
|
||||
\assert($model instanceof DashboardModel);
|
||||
$widgets = $model->getWidgets();
|
||||
|
||||
// Apply the default dashboard if no widget exists
|
||||
if (!count($widgets) && $this->user->getId()) {
|
||||
return $this->applyDashboardFileAction($request, $pathsHelper, $urlGenerator, 'global.default');
|
||||
}
|
||||
|
||||
$action = $this->generateUrl('mautic_dashboard_index');
|
||||
$dateRangeFilter = $request->query->all()['daterange'] ?? $request->request->all()['daterange'] ?? [];
|
||||
|
||||
// Set new date range to the session
|
||||
if ($request->isMethod(Request::METHOD_POST)) {
|
||||
if (!empty($dateRangeFilter['date_from'])) {
|
||||
$from = new \DateTime($dateRangeFilter['date_from']);
|
||||
$request->getSession()->set('mautic.daterange.form.from', $from->format(DateTimeHelper::FORMAT_DB_DATE_ONLY));
|
||||
}
|
||||
|
||||
if (!empty($dateRangeFilter['date_to'])) {
|
||||
$to = new \DateTime($dateRangeFilter['date_to']);
|
||||
$request->getSession()->set('mautic.daterange.form.to', $to->format(DateTimeHelper::FORMAT_DB_DATE_ONLY.' 23:59:59'));
|
||||
}
|
||||
|
||||
$model->clearDashboardCache();
|
||||
}
|
||||
|
||||
// Set new date range to the session, if present in POST
|
||||
$widget->setFilter($request);
|
||||
|
||||
// Load date range from session
|
||||
$filter = $model->getDefaultFilter();
|
||||
|
||||
// Set the final date range to the form
|
||||
$dateRangeFilter['date_from'] = $filter['dateFrom']->format(WidgetService::FORMAT_HUMAN);
|
||||
$dateRangeFilter['date_to'] = $filter['dateTo']->format(WidgetService::FORMAT_HUMAN);
|
||||
$dateRangeForm = $formFactory->create(DateRangeType::class, $dateRangeFilter, ['action' => $action]);
|
||||
|
||||
$model->populateWidgetsContent($widgets, $filter);
|
||||
$releaseMetadata = ThisRelease::getMetadata();
|
||||
|
||||
$model->populateWidgetPreviews($widgets);
|
||||
|
||||
return $this->delegateView([
|
||||
'viewParameters' => [
|
||||
'security' => $this->security,
|
||||
'widgets' => $widgets,
|
||||
'dateRangeForm' => $dateRangeForm->createView(),
|
||||
'phpVersion' => [
|
||||
'isOutdated' => version_compare(PHP_VERSION, $releaseMetadata->getShowPHPVersionWarningIfUnder(), 'lt'),
|
||||
'version' => PhpVersionHelper::getCurrentSemver(),
|
||||
],
|
||||
],
|
||||
'contentTemplate' => '@MauticDashboard/Dashboard/index.html.twig',
|
||||
'passthroughVars' => [
|
||||
'activeLink' => '#mautic_dashboard_index',
|
||||
'mauticContent' => 'dashboard',
|
||||
'route' => $this->generateUrl('mautic_dashboard_index'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function widgetAction(Request $request, WidgetService $widgetService, Environment $twig, $widgetId): JsonResponse
|
||||
{
|
||||
if (!$request->isXmlHttpRequest()) {
|
||||
throw new NotFoundHttpException('Not found.');
|
||||
}
|
||||
|
||||
$widgetService->setFilter($request);
|
||||
$widget = $widgetService->get((int) $widgetId);
|
||||
|
||||
if (!$widget) {
|
||||
throw new NotFoundHttpException('Not found.');
|
||||
}
|
||||
|
||||
$content = $twig->render(
|
||||
'@MauticDashboard/Dashboard/widget.html.twig',
|
||||
['widget' => $widget]
|
||||
);
|
||||
|
||||
return new JsonResponse([
|
||||
'success' => 1,
|
||||
'widgetId' => $widgetId,
|
||||
'widgetHtml' => $content,
|
||||
'widgetWidth' => $widget->getWidth(),
|
||||
'widgetHeight' => $widget->getHeight(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate new dashboard widget and processes post data.
|
||||
*
|
||||
* @return JsonResponse|RedirectResponse|Response
|
||||
*/
|
||||
public function newAction(Request $request, FormFactoryInterface $formFactory)
|
||||
{
|
||||
// retrieve the entity
|
||||
$widget = new Widget();
|
||||
|
||||
$model = $this->getModel('dashboard');
|
||||
\assert($model instanceof DashboardModel);
|
||||
$action = $this->generateUrl('mautic_dashboard_action', ['objectAction' => 'new']);
|
||||
|
||||
// get the user form factory
|
||||
$form = $model->createForm($widget, $formFactory, $action);
|
||||
$closeModal = false;
|
||||
$valid = false;
|
||||
|
||||
// /Check for a submitted form and process it
|
||||
if ($request->isMethod(Request::METHOD_POST)) {
|
||||
if (!$cancelled = $this->isFormCancelled($form)) {
|
||||
if ($valid = $this->isFormValid($form)) {
|
||||
$closeModal = true;
|
||||
|
||||
// form is valid so process the data
|
||||
$model->saveEntity($widget);
|
||||
}
|
||||
} else {
|
||||
$closeModal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($closeModal) {
|
||||
// just close the modal
|
||||
$passthroughVars = [
|
||||
'closeModal' => 1,
|
||||
'mauticContent' => 'widget',
|
||||
];
|
||||
|
||||
$filter = $model->getDefaultFilter();
|
||||
$model->populateWidgetContent($widget, $filter);
|
||||
|
||||
if ($valid && !$cancelled) {
|
||||
$passthroughVars['upWidgetCount'] = 1;
|
||||
$passthroughVars['widgetHtml'] = $this->renderView('@MauticDashboard/Widget/detail.html.twig', [
|
||||
'widget' => $widget,
|
||||
]);
|
||||
$passthroughVars['widgetId'] = $widget->getId();
|
||||
$passthroughVars['widgetWidth'] = $widget->getWidth();
|
||||
$passthroughVars['widgetHeight'] = $widget->getHeight();
|
||||
}
|
||||
|
||||
return new JsonResponse($passthroughVars);
|
||||
} else {
|
||||
return $this->delegateView([
|
||||
'viewParameters' => [
|
||||
'form' => $form->createView(),
|
||||
],
|
||||
'contentTemplate' => '@MauticDashboard/Widget/form.html.twig',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* edit widget and processes post data.
|
||||
*
|
||||
* @return JsonResponse|RedirectResponse|Response
|
||||
*/
|
||||
public function editAction(Request $request, FormFactoryInterface $formFactory, $objectId)
|
||||
{
|
||||
$model = $this->getModel('dashboard');
|
||||
\assert($model instanceof DashboardModel);
|
||||
$widget = $model->getEntity($objectId);
|
||||
$action = $this->generateUrl('mautic_dashboard_action', ['objectAction' => 'edit', 'objectId' => $objectId]);
|
||||
|
||||
// get the user form factory
|
||||
$form = $model->createForm($widget, $formFactory, $action);
|
||||
$closeModal = false;
|
||||
$valid = false;
|
||||
// /Check for a submitted form and process it
|
||||
if ($request->isMethod(Request::METHOD_POST)) {
|
||||
if (!$cancelled = $this->isFormCancelled($form)) {
|
||||
if ($valid = $this->isFormValid($form)) {
|
||||
$closeModal = true;
|
||||
|
||||
// form is valid so process the data
|
||||
$model->saveEntity($widget);
|
||||
}
|
||||
} else {
|
||||
$closeModal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($closeModal) {
|
||||
// just close the modal
|
||||
$passthroughVars = [
|
||||
'closeModal' => 1,
|
||||
'mauticContent' => 'widget',
|
||||
];
|
||||
|
||||
$filter = $model->getDefaultFilter();
|
||||
$model->populateWidgetContent($widget, $filter);
|
||||
|
||||
if ($valid && !$cancelled) {
|
||||
$passthroughVars['upWidgetCount'] = 1;
|
||||
$passthroughVars['widgetHtml'] = $this->renderView('@MauticDashboard/Widget/detail.html.twig', [
|
||||
'widget' => $widget,
|
||||
]);
|
||||
$passthroughVars['widgetId'] = $widget->getId();
|
||||
$passthroughVars['widgetWidth'] = $widget->getWidth();
|
||||
$passthroughVars['widgetHeight'] = $widget->getHeight();
|
||||
}
|
||||
|
||||
return new JsonResponse($passthroughVars);
|
||||
} else {
|
||||
return $this->delegateView([
|
||||
'viewParameters' => [
|
||||
'form' => $form->createView(),
|
||||
],
|
||||
'contentTemplate' => '@MauticDashboard/Widget/form.html.twig',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes entity if exists.
|
||||
*
|
||||
* @param int $objectId
|
||||
*/
|
||||
public function deleteAction(Request $request, $objectId): Response
|
||||
{
|
||||
if (!$request->isXmlHttpRequest()) {
|
||||
throw new BadRequestHttpException();
|
||||
}
|
||||
|
||||
$flashes = [];
|
||||
$success = 0;
|
||||
|
||||
/** @var DashboardModel $model */
|
||||
$model = $this->getModel('dashboard');
|
||||
$entity = $model->getEntity($objectId);
|
||||
|
||||
if ($entity) {
|
||||
$model->deleteEntity($entity);
|
||||
$name = $entity->getName();
|
||||
$flashes[] = [
|
||||
'type' => 'notice',
|
||||
'msg' => 'mautic.core.notice.deleted',
|
||||
'msgVars' => [
|
||||
'%name%' => $name,
|
||||
'%id%' => $objectId,
|
||||
],
|
||||
];
|
||||
$success = 1;
|
||||
} else {
|
||||
$flashes[] = [
|
||||
'type' => 'error',
|
||||
'msg' => 'mautic.api.client.error.notfound',
|
||||
'msgVars' => ['%id%' => $objectId],
|
||||
];
|
||||
}
|
||||
|
||||
return $this->postActionRedirect(
|
||||
[
|
||||
'success' => $success,
|
||||
'flashes' => $flashes,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the widgets of current user into a json and stores it for later as a file.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function saveAction(Request $request)
|
||||
{
|
||||
// Accept only AJAX POST requests because those are check for CSRF tokens
|
||||
if (!$request->isMethod(Request::METHOD_POST) || !$request->isXmlHttpRequest()) {
|
||||
return $this->accessDenied();
|
||||
}
|
||||
|
||||
$name = $this->getNameFromRequest($request);
|
||||
|
||||
/** @var DashboardModel $dashboardModel */
|
||||
$dashboardModel = $this->getModel('dashboard');
|
||||
try {
|
||||
$dashboardModel->saveSnapshot($name);
|
||||
$type = 'notice';
|
||||
$msg = $this->translator->trans('mautic.dashboard.notice.save', [
|
||||
'%name%' => $name,
|
||||
'%viewUrl%' => $this->generateUrl(
|
||||
'mautic_dashboard_action',
|
||||
[
|
||||
'objectAction' => 'import',
|
||||
]
|
||||
),
|
||||
], 'flashes');
|
||||
} catch (IOException $e) {
|
||||
$type = 'error';
|
||||
$msg = $this->translator->trans('mautic.dashboard.error.save', [
|
||||
'%msg%' => $e->getMessage(),
|
||||
], 'flashes');
|
||||
}
|
||||
|
||||
return $this->postActionRedirect(
|
||||
[
|
||||
'flashes' => [
|
||||
[
|
||||
'type' => $type,
|
||||
'msg' => $msg,
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the widgets of current user into a json file and downloads it.
|
||||
*/
|
||||
public function exportAction(Request $request): JsonResponse
|
||||
{
|
||||
$dashboardModel = $this->getModel('dashboard');
|
||||
\assert($dashboardModel instanceof DashboardModel);
|
||||
$filename = InputHelper::filename($this->getNameFromRequest($request), 'json');
|
||||
$response = new JsonResponse($dashboardModel->toArray($filename));
|
||||
$response->setEncodingOptions($response->getEncodingOptions() | JSON_PRETTY_PRINT);
|
||||
$response->headers->set('Content-Type', 'application/force-download');
|
||||
$response->headers->set('Content-Type', 'application/octet-stream');
|
||||
$response->headers->set('Content-Disposition', 'attachment; filename="'.$filename.'"');
|
||||
$response->headers->set('Expires', '0');
|
||||
$response->headers->set('Cache-Control', 'must-revalidate');
|
||||
$response->headers->set('Pragma', 'public');
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports the widgets of current user into a json file.
|
||||
*/
|
||||
public function deleteDashboardFileAction(Request $request, PathsHelper $pathsHelper): RedirectResponse
|
||||
{
|
||||
$file = $request->get('file');
|
||||
|
||||
$parts = explode('.', $file);
|
||||
$type = array_shift($parts);
|
||||
$name = implode('.', $parts);
|
||||
|
||||
$dir = $pathsHelper->getSystemPath("dashboard.$type");
|
||||
$path = $dir.'/'.$name.'.json';
|
||||
|
||||
if (file_exists($path) && is_writable($path)) {
|
||||
unlink($path);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('mautic_dashboard_action', ['objectAction' => 'import']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies dashboard layout.
|
||||
*
|
||||
* @param string|null $file
|
||||
*/
|
||||
public function applyDashboardFileAction(Request $request, PathsHelper $pathsHelper, RouterInterface $urlGenerator, $file = null): RedirectResponse
|
||||
{
|
||||
if (!$file) {
|
||||
$file = $request->get('file');
|
||||
}
|
||||
|
||||
$parts = explode('.', $file);
|
||||
$type = array_shift($parts);
|
||||
$name = implode('.', $parts);
|
||||
|
||||
$dir = $pathsHelper->getSystemPath("dashboard.$type");
|
||||
$path = $dir.'/'.$name.'.json';
|
||||
|
||||
if (!file_exists($path) || !is_readable($path)) {
|
||||
$this->addFlashMessage('mautic.dashboard.upload.filenotfound', [], 'error', 'validators');
|
||||
|
||||
return $this->redirectToRoute('mautic_dashboard_action', ['objectAction' => 'import']);
|
||||
}
|
||||
|
||||
$widgets = json_decode(file_get_contents($path), true);
|
||||
if (isset($widgets['widgets'])) {
|
||||
$widgets = $widgets['widgets'];
|
||||
}
|
||||
|
||||
if ($widgets) {
|
||||
/** @var DashboardModel $model */
|
||||
$model = $this->getModel('dashboard');
|
||||
|
||||
$model->clearDashboardCache();
|
||||
|
||||
$currentWidgets = $model->getWidgets();
|
||||
|
||||
if (count($currentWidgets)) {
|
||||
foreach ($currentWidgets as $widget) {
|
||||
$model->deleteEntity($widget);
|
||||
}
|
||||
}
|
||||
|
||||
$filter = $model->getDefaultFilter();
|
||||
foreach ($widgets as $widget) {
|
||||
$widget = $model->populateWidgetEntity($widget);
|
||||
$model->saveEntity($widget);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->redirect($urlGenerator->generate('mautic_dashboard_index'));
|
||||
}
|
||||
|
||||
public function importAction(Request $request, FormFactoryInterface $formFactory, PathsHelper $pathsHelper): Response
|
||||
{
|
||||
$preview = $request->get('preview');
|
||||
|
||||
/** @var DashboardModel $model */
|
||||
$model = $this->getModel('dashboard');
|
||||
|
||||
$directories = [
|
||||
'user' => $pathsHelper->getSystemPath('dashboard.user'),
|
||||
'global' => $pathsHelper->getSystemPath('dashboard.global'),
|
||||
];
|
||||
|
||||
$action = $this->generateUrl('mautic_dashboard_action', ['objectAction' => 'import']);
|
||||
$form = $formFactory->create(UploadType::class, [], ['action' => $action]);
|
||||
|
||||
if ($request->isMethod(Request::METHOD_POST)) {
|
||||
if (!$this->isFormCancelled($form)) {
|
||||
if ($this->isFormValid($form)) {
|
||||
$fileData = $form['file']->getData();
|
||||
if (!empty($fileData)) {
|
||||
$extension = pathinfo($fileData->getClientOriginalName(), PATHINFO_EXTENSION);
|
||||
if ('json' === $extension) {
|
||||
$fileData->move($directories['user'], $fileData->getClientOriginalName());
|
||||
} 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')
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$dashboardFiles = ['user' => [], 'gobal' => []];
|
||||
$dashboards = [];
|
||||
|
||||
if (is_readable($directories['user'])) {
|
||||
// User specific layouts
|
||||
chdir($directories['user']);
|
||||
$dashboardFiles['user'] = glob('*.json');
|
||||
}
|
||||
|
||||
if (is_readable($directories['global'])) {
|
||||
// Global dashboards
|
||||
chdir($directories['global']);
|
||||
$dashboardFiles['global'] = glob('*.json');
|
||||
}
|
||||
|
||||
foreach ($dashboardFiles as $type => $dirDashboardFiles) {
|
||||
$tempDashboard = [];
|
||||
foreach ($dirDashboardFiles as $dashId => $dashboard) {
|
||||
$dashboard = str_replace('.json', '', $dashboard);
|
||||
$config = json_decode(
|
||||
file_get_contents($directories[$type].'/'.$dirDashboardFiles[$dashId]),
|
||||
true
|
||||
);
|
||||
|
||||
// Check for name, description, etc
|
||||
$tempDashboard[$dashboard] = [
|
||||
'type' => $type,
|
||||
'name' => $config['name'] ?? $dashboard,
|
||||
'description' => $config['description'] ?? '',
|
||||
'widgets' => $config['widgets'] ?? $config,
|
||||
];
|
||||
}
|
||||
|
||||
// Sort by name
|
||||
uasort($tempDashboard,
|
||||
fn ($a, $b): int => strnatcasecmp($a['name'], $b['name'])
|
||||
);
|
||||
|
||||
$dashboards = array_merge(
|
||||
$dashboards,
|
||||
$tempDashboard
|
||||
);
|
||||
}
|
||||
|
||||
if ($preview && isset($dashboards[$preview])) {
|
||||
// @todo check is_writable
|
||||
$widgets = $dashboards[$preview]['widgets'];
|
||||
$filter = $model->getDefaultFilter();
|
||||
$model->populateWidgetsContent($widgets, $filter);
|
||||
} else {
|
||||
$widgets = [];
|
||||
}
|
||||
|
||||
return $this->delegateView(
|
||||
[
|
||||
'viewParameters' => [
|
||||
'form' => $form->createView(),
|
||||
'dashboards' => $dashboards,
|
||||
'widgets' => $widgets,
|
||||
'preview' => $preview,
|
||||
],
|
||||
'contentTemplate' => '@MauticDashboard/Dashboard/import.html.twig',
|
||||
'passthroughVars' => [
|
||||
'activeLink' => '#mautic_dashboard_index',
|
||||
'mauticContent' => 'dashboardImport',
|
||||
'route' => $this->generateUrl(
|
||||
'mautic_dashboard_action',
|
||||
[
|
||||
'objectAction' => 'import',
|
||||
]
|
||||
),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets name from request and defaults it to the timestamp if not provided.
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function getNameFromRequest(Request $request): string
|
||||
{
|
||||
return $request->get('name', (new \DateTime())->format('Y-m-dTH:i:s'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user