diff --git a/application/utils.inc.php b/application/utils.inc.php index b6efa70e4..0c06f1495 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -1520,7 +1520,7 @@ class utils $sUploadDashboardTransactId = utils::GetNewTransactionId(); $aResult = [ new SeparatorPopupMenuItem(), - new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sDashboardId.'&file='.$sDashboardFileURL), + new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?route=dashboard.export&id='.$sDashboardId.'&file='.$sDashboardFileURL), new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sDashboardId', file: '$sDashboardFileJS', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"), ]; if ($oDashboard->GetReloadURL()) { diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 29a916965..a2149b3db 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -867,22 +867,6 @@ try { $oObj->DisplayDashboard($oPage, $sAttCode); break; - case 'export_dashboard': - $oPage = new DownloadPage(''); - $sDashboardId = utils::ReadParam('id', '', false, 'raw_data'); - $sDashboardFileRelative = utils::ReadParam('file', '', false, 'raw_data'); - - $sDashboardFile = RuntimeDashboard::GetDashboardFileFromRelativePath($sDashboardFileRelative); - - $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId); - if (!is_null($oDashboard)) { - $oPage->TrashUnexpectedOutput(); - $oPage->SetContentType('text/xml'); - $oPage->SetContentDisposition('attachment', 'dashboard_'.$oDashboard->GetTitle().'.xml'); - $oPage->add($oDashboard->ToXml()); - } - break; - case 'import_dashboard': $oPage = new JsonPage(); $oPage->SetOutputDataOnly(true); diff --git a/sources/Application/Dashboard/Controller/DashboardController.php b/sources/Application/Dashboard/Controller/DashboardController.php index b12f0aae4..85c605dc2 100644 --- a/sources/Application/Dashboard/Controller/DashboardController.php +++ b/sources/Application/Dashboard/Controller/DashboardController.php @@ -7,6 +7,7 @@ namespace Combodo\iTop\Application\Dashboard\Controller; +use appUserPreferences; use Combodo\iTop\Application\Dashlet\DashletFactory; use Combodo\iTop\Application\TwigBase\Controller\Controller; use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory; @@ -15,14 +16,19 @@ use Combodo\iTop\Application\UI\Base\Component\TurboForm\TurboFormUIBlockFactory use Combodo\iTop\Application\UI\Base\iUIBlock; use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory; use Combodo\iTop\Application\WebPage\AjaxPage; +use Combodo\iTop\Application\WebPage\DownloadPage; use Combodo\iTop\Application\WebPage\JsonPage; use Combodo\iTop\Forms\Block\FormBlockService; use Combodo\iTop\PropertyType\Serializer\XMLSerializer; use Combodo\iTop\Service\DependencyInjection\ServiceLocator; +use DBObjectSearch; +use DBObjectSet; use Exception; use IssueLog; use ModelReflectionRuntime; use RuntimeDashboard; +use SecurityException; +use UserRights; use utils; class DashboardController extends Controller @@ -133,4 +139,44 @@ class DashboardController extends Controller $oPage->SetOutputDataOnly(true); return $oPage; } + + public function OperationExport() + { + $oPage = new DownloadPage(''); + $sDashboardId = utils::ReadParam('id', '', false, 'raw_data'); + $sDashboardFile = APPROOT.utils::ReadParam('file', '', false, 'raw_data'); + + $sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT); + if (false === $sDashboardFileSanitized) { + throw new SecurityException('Invalid dashboard file !'); + } + + if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashboardId, false)) { + // Search for an eventual user defined dashboard + $oUDSearch = new DBObjectSearch('UserDashboard'); + $oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '='); + $oUDSearch->AddCondition('menu_code', $sDashboardId, '='); + $oUDSet = new DBObjectSet($oUDSearch); + if ($oUDSet->Count() > 0) { + // Assuming there is at most one couple {user, menu}! + $oUserDashboard = $oUDSet->Fetch(); + $sDashboardDefinition = $oUserDashboard->Get('contents'); + } else { + $sDashboardDefinition = @file_get_contents($sDashboardFileSanitized); + } + } else { + $sDashboardDefinition = @file_get_contents($sDashboardFileSanitized); + } + + $oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId); + if (!is_null($oDashboard)) { + $oPage->TrashUnexpectedOutput(); + $oPage->SetContentType('text/xml'); + $oPage->SetContentDisposition('attachment', 'dashboard_'.$oDashboard->GetTitle().'.xml'); + + $oPage->add($sDashboardDefinition); + } + + return $oPage; + } } diff --git a/sources/Application/Dashboard/Dashboard.php b/sources/Application/Dashboard/Dashboard.php index 78f42b0a5..a5766641b 100644 --- a/sources/Application/Dashboard/Dashboard.php +++ b/sources/Application/Dashboard/Dashboard.php @@ -769,4 +769,27 @@ JS $this->aGridDashlets[] = $aGridDashlet; } } + + public function ToModelData(): mixed + { + $this->sLayoutClass = DashboardLayoutGrid::class; + $this->sTitle = $aDashboardValues['title']; + $iRefresh = $aDashboardValues['refresh']; + $this->bAutoReload = $iRefresh > 0; + $this->iAutoReloadSec = $iRefresh; + + foreach ($aDashboardValues['pos_dashlets'] as $sId => $aPosDashlet) { + $aGridDashlet = []; + $aGridDashlet['position_x'] = $aPosDashlet['position_x'] ?? 0; + $aGridDashlet['position_y'] = $aPosDashlet['position_y'] ?? 0; + $aGridDashlet['width'] = $aPosDashlet['width'] ?? 2; + $aGridDashlet['height'] = $aPosDashlet['height'] ?? 1; + $aDashlet = $aPosDashlet['dashlet']; + $sType = $aDashlet['type']; + $oDashlet = DashletFactory::GetInstance()->CreateDashlet($sType, $sId); + $oDashlet->FromModelData($aDashlet['properties']); + $aGridDashlet['dashlet'] = $oDashlet; + $this->aGridDashlets[] = $aGridDashlet; + } + } } diff --git a/sources/Application/TwigBase/Controller/Controller.php b/sources/Application/TwigBase/Controller/Controller.php index c562283d7..3e2126865 100644 --- a/sources/Application/TwigBase/Controller/Controller.php +++ b/sources/Application/TwigBase/Controller/Controller.php @@ -23,6 +23,7 @@ namespace Combodo\iTop\Application\TwigBase\Controller; use ApplicationMenu; use Combodo\iTop\Application\TwigBase\Twig\TwigHelper; use Combodo\iTop\Application\WebPage\AjaxPage; +use Combodo\iTop\Application\WebPage\DownloadPage; use Combodo\iTop\Application\WebPage\ErrorPage; use Combodo\iTop\Application\WebPage\iTopWebPage; use Combodo\iTop\Application\WebPage\WebPage; @@ -63,6 +64,7 @@ abstract class Controller extends AbstractController public const ENUM_PAGE_TYPE_AJAX = 'ajax'; public const ENUM_PAGE_TYPE_TURBO_FORM_AJAX = 'turbo_ajax'; public const ENUM_PAGE_TYPE_SETUP = 'setup'; + public const ENUM_PAGE_TYPE_DOWNLOAD = 'download'; public const TWIG_ERROR = 'error'; public const TWIG_WARNING = 'warning'; @@ -477,6 +479,21 @@ abstract class Controller extends AbstractController $this->DisplayPage($aParams, $sTemplateName, 'ajax'); } + /** + * Display an AJAX (html) page (AjaxPage) + * + * @api + * + * @param array $aParams Params used by the twig template + * @param string|null $sTemplateName Name of the twig template, ie MyTemplate for MyTemplate.html.twig + * + * @throws \Exception + */ + public function DisplayDownloadPage(array $aParams = [], string $sTemplateName = null): void + { + $this->DisplayPage($aParams, $sTemplateName, self::ENUM_PAGE_TYPE_DOWNLOAD); + } + /** * Display an Setup page (SetupPage) * @@ -907,6 +924,10 @@ abstract class Controller extends AbstractController case self::ENUM_PAGE_TYPE_SETUP: $this->oPage = new SetupPage($this->GetOperationTitle()); break; + + case self::ENUM_PAGE_TYPE_DOWNLOAD: + $this->oPage = new DownloadPage($this->GetOperationTitle()); + break; } $this->oTwig->addGlobal('UIBlockParent', [$this->oPage]); $this->oTwig->addGlobal('oPage', $this->oPage);