Skip to content

Commit

Permalink
N°3111 - Fix Portal export
Browse files Browse the repository at this point in the history
(cherry picked from commit d3b57c3)
  • Loading branch information
eespie authored and Pierre Goiffon committed Oct 30, 2020
1 parent 97d322a commit eebc29d
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 114 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
"core",
"application",
"sources/application",
"sources/Composer"
"sources/Composer",
"sources/Controller"
],
"exclude-from-classmap": [
"core/dbobjectsearch.class.php",
Expand Down
2 changes: 1 addition & 1 deletion core/metamodel.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -4181,7 +4181,7 @@ public static function AddMagicPlaceholders($aPlaceholders, $aExpectedArgs = nul
{
$oSearch = DBObjectSearch::FromOQL("SELECT Contact WHERE id = :id");
$oSet = new DBObjectSet($oSearch, array(), array('id' => UserRights::GetContactId()));
$oSet->OptimizeColumnLoad($aCurrentContact);
$oSet->OptimizeColumnLoad(['Contact' => $aCurrentContact]);
$oUser = $oSet->fetch();
foreach ($aCurrentContact as $sField)
{
Expand Down
4 changes: 2 additions & 2 deletions datamodels/2.x/itop-portal-base/portal/public/js/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

function ExportStartExport() {
var oParams = {};
oParams.operation = 'export_build';
oParams.operation = 'export_build_portal';
oParams.format = sFormat;
oParams.token = sToken;
oParams.start = 1;
Expand Down Expand Up @@ -56,7 +56,7 @@ function ExportRun(data) {
$('#export-close').show();
}
else {
oParams.operation = 'export_build';
oParams.operation = 'export_build_portal';
}

$.post(GetAbsoluteUrlAppRoot() + 'pages/ajax.render.php', oParams, function (data) {
Expand Down
1 change: 1 addition & 0 deletions lib/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@
'Combodo\\iTop\\Application\\TwigBase\\Twig\\Extension' => $baseDir . '/sources/application/TwigBase/Twig/Extension.php',
'Combodo\\iTop\\Application\\TwigBase\\Twig\\TwigHelper' => $baseDir . '/sources/application/TwigBase/Twig/TwigHelper.php',
'Combodo\\iTop\\Composer\\iTopComposer' => $baseDir . '/sources/Composer/iTopComposer.php',
'Combodo\\iTop\\Controller\\AjaxRenderController' => $baseDir . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\DesignElement' => $baseDir . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\TwigExtension' => $baseDir . '/application/twigextension.class.inc.php',
Expand Down
1 change: 1 addition & 0 deletions lib/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Application\\TwigBase\\Twig\\Extension' => __DIR__ . '/../..' . '/sources/application/TwigBase/Twig/Extension.php',
'Combodo\\iTop\\Application\\TwigBase\\Twig\\TwigHelper' => __DIR__ . '/../..' . '/sources/application/TwigBase/Twig/TwigHelper.php',
'Combodo\\iTop\\Composer\\iTopComposer' => __DIR__ . '/../..' . '/sources/Composer/iTopComposer.php',
'Combodo\\iTop\\Controller\\AjaxRenderController' => __DIR__ . '/../..' . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\DesignElement' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\TwigExtension' => __DIR__ . '/../..' . '/application/twigextension.class.inc.php',
Expand Down
120 changes: 10 additions & 110 deletions pages/ajax.render.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* You should have received a copy of the GNU Affero General Public License
*/

use Combodo\iTop\Controller\AjaxRenderController;
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;

require_once('../approot.inc.php');
Expand Down Expand Up @@ -51,17 +52,17 @@ function LogErrorMessage($sMsgPrefix, $aContextInfo) {
// Only allow export functions to portal users
switch ($operation)
{
case 'export_build':
case 'export_build_portal':
case 'export_cancel':
case 'export_download':
case 'cke_img_upload':
case 'cke_upload_and_browse':
case 'cke_browse':
$sRequestedPortalId = null;
$sRequestedPortalId = null; // Allowed for all users
break;

default:
$sRequestedPortalId = 'backoffice';
$sRequestedPortalId = 'backoffice'; // Allowed only for console users
break;
}
LoginWebPage::DoLoginEx($sRequestedPortalId, false);
Expand All @@ -79,9 +80,10 @@ function LogErrorMessage($sMsgPrefix, $aContextInfo) {
// some operations are also used in the portal though
switch ($operation)
{
case 'export_build':
case 'export_build_portal':
case 'export_download':
// do nothing : used in portal (export.js in portal-base)
break;

default:
ContextTag::AddContext(ContextTag::TAG_CONSOLE);
Expand Down Expand Up @@ -2444,113 +2446,11 @@ function(data){
break;

case 'export_build':
register_shutdown_function(function () {
$aErr = error_get_last();
if (($aErr !== null) && ($aErr['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR)))
{
ob_end_clean();
echo json_encode(array('code' => 'error', 'percentage' => 100, 'message' => Dict::Format('UI:Error_Details', $aErr['message'])));
}
});
try
{
$token = utils::ReadParam('token', null);
$sTokenForDisplay = utils::HtmlEntities($token);
$aResult = array( // Fallback error, just in case
'code' => 'error',
'percentage' => 100,
'message' => "Export not found for token: '$sTokenForDisplay'",
);
$data = '';
if ($token === null)
{
if (!ContextTag::Check('backoffice'))
{
throw new Exception('Missing token');
}
$sFormat = utils::ReadParam('format', '');
$sExpression = utils::ReadParam('expression', null, false, 'raw_data');
$iQueryId = utils::ReadParam('query', null);
if ($sExpression === null)
{
$oQuerySearch = DBObjectSearch::FromOQL('SELECT QueryOQL WHERE id = :query_id', array('query_id' => $iQueryId));
$oQuerySearch->UpdateContextFromUser();
$oQueries = new DBObjectSet($oQuerySearch);
if ($oQueries->Count() > 0)
{
$oQuery = $oQueries->Fetch();
$sExpression = $oQuery->Get('oql');
}
else
{
$aResult = array('code' => 'error', 'percentage' => 100, 'message' => "Invalid query phrasebook identifier: '$iQueryId'");
}
}
if ($sExpression !== null)
{
$oSearch = DBObjectSearch::FromOQL($sExpression);
$oSearch->UpdateContextFromUser();
$oExporter = BulkExport::FindExporter($sFormat, $oSearch);
$oExporter->SetObjectList($oSearch);
$oExporter->SetFormat($sFormat);
$oExporter->SetChunkSize(EXPORTER_DEFAULT_CHUNK_SIZE);
$oExporter->ReadParameters();
}

// First pass, generate the headers
$data .= $oExporter->GetHeader();
}
else
{
$oExporter = BulkExport::FindExporterFromToken($token);
if (utils::ReadParam('start', 0, false, 'integer') == 1)
{
// From portal, the first call is using a token
$data .= $oExporter->GetHeader();
}
}
AjaxRenderController::ExportBuild($oPage, false);
break;

if ($oExporter)
{
$data .= $oExporter->GetNextChunk($aResult);
if ($aResult['code'] != 'done')
{
$oExporter->AppendToTmpFile($data);
$aResult['token'] = $oExporter->SaveState();
}
else
{
// Last pass
$data .= $oExporter->GetFooter();
$oExporter->AppendToTmpFile($data);
$aResult['token'] = $oExporter->SaveState();
if (substr($oExporter->GetMimeType(), 0, 5) == 'text/')
{
// Result must be encoded in UTF-8 to be passed as part of a JSON structure
$sCharset = $oExporter->GetCharacterSet();
if (strtoupper($sCharset) != 'UTF-8')
{
$aResult['text_result'] = iconv($sCharset, 'UTF-8', file_get_contents($oExporter->GetTmpFilePath()));
}
else
{
$aResult['text_result'] = file_get_contents($oExporter->GetTmpFilePath());
}
$aResult['mime_type'] = $oExporter->GetMimeType();
}
$aResult['message'] = Dict::Format('Core:BulkExport:ClickHereToDownload_FileName', $oExporter->GetDownloadFileName());
}
}
$oPage->add(json_encode($aResult));
} catch (BulkExportException $e)
{
$aResult = array('code' => 'error', 'percentage' => 100, 'message' => utils::HtmlEntities($e->GetLocalizedMessage()));
$oPage->add(json_encode($aResult));
} catch (Exception $e)
{
$aResult = array('code' => 'error', 'percentage' => 100, 'message' => utils::HtmlEntities($e->getMessage()));
$oPage->add(json_encode($aResult));
}
case 'export_build_portal':
AjaxRenderController::ExportBuild($oPage, true);
break;

case 'export_download':
Expand Down
116 changes: 116 additions & 0 deletions sources/Controller/AjaxRenderController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php
/**
* @copyright Copyright (C) 2010-2020 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/

namespace Combodo\iTop\Controller;

use ajax_page;
use BulkExport;
use BulkExportException;
use DBObjectSearch;
use DBObjectSet;
use Dict;
use Exception;
use utils;

class AjaxRenderController
{
/**
* @param \ajax_page $oPage
*
* @param bool $bTokenOnly
*
* @throws \Exception
*/
public static function ExportBuild(ajax_page $oPage, bool $bTokenOnly)
{
register_shutdown_function(function () {
$aErr = error_get_last();
if (($aErr !== null) && ($aErr['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR))) {
ob_end_clean();
echo json_encode(array('code' => 'error', 'percentage' => 100, 'message' => Dict::Format('UI:Error_Details', $aErr['message'])));
}
});

try {
$token = utils::ReadParam('token', null);
$sTokenForDisplay = utils::HtmlEntities($token);
$aResult = array( // Fallback error, just in case
'code' => 'error',
'percentage' => 100,
'message' => "Export not found for token: '$sTokenForDisplay'",
);
$data = '';
if ($token === null) {
if ($bTokenOnly) {
throw new Exception('Access not allowed');
}
$sFormat = utils::ReadParam('format', '');
$sExpression = utils::ReadParam('expression', null, false, 'raw_data');
$iQueryId = utils::ReadParam('query', null);
if ($sExpression === null) {
$oQuerySearch = DBObjectSearch::FromOQL('SELECT QueryOQL WHERE id = :query_id', array('query_id' => $iQueryId));
$oQuerySearch->UpdateContextFromUser();
$oQueries = new DBObjectSet($oQuerySearch);
if ($oQueries->Count() > 0) {
$oQuery = $oQueries->Fetch();
$sExpression = $oQuery->Get('oql');
} else {
$aResult = array('code' => 'error', 'percentage' => 100, 'message' => "Invalid query phrasebook identifier: '$iQueryId'");
}
}
if ($sExpression !== null) {
$oSearch = DBObjectSearch::FromOQL($sExpression);
$oSearch->UpdateContextFromUser();
$oExporter = BulkExport::FindExporter($sFormat, $oSearch);
$oExporter->SetObjectList($oSearch);
$oExporter->SetFormat($sFormat);
$oExporter->SetChunkSize(EXPORTER_DEFAULT_CHUNK_SIZE);
$oExporter->ReadParameters();
}

// First pass, generate the headers
$data .= $oExporter->GetHeader();
} else {
$oExporter = BulkExport::FindExporterFromToken($token);
if (utils::ReadParam('start', 0, false, 'integer') == 1) {
// From portal, the first call is using a token
$data .= $oExporter->GetHeader();
}
}

if ($oExporter) {
$data .= $oExporter->GetNextChunk($aResult);
if ($aResult['code'] != 'done') {
$oExporter->AppendToTmpFile($data);
$aResult['token'] = $oExporter->SaveState();
} else {
// Last pass
$data .= $oExporter->GetFooter();
$oExporter->AppendToTmpFile($data);
$aResult['token'] = $oExporter->SaveState();
if (substr($oExporter->GetMimeType(), 0, 5) == 'text/') {
// Result must be encoded in UTF-8 to be passed as part of a JSON structure
$sCharset = $oExporter->GetCharacterSet();
if (strtoupper($sCharset) != 'UTF-8') {
$aResult['text_result'] = iconv($sCharset, 'UTF-8', file_get_contents($oExporter->GetTmpFilePath()));
} else {
$aResult['text_result'] = file_get_contents($oExporter->GetTmpFilePath());
}
$aResult['mime_type'] = $oExporter->GetMimeType();
}
$aResult['message'] = Dict::Format('Core:BulkExport:ClickHereToDownload_FileName', $oExporter->GetDownloadFileName());
}
}
$oPage->add(json_encode($aResult));
} catch (BulkExportException $e) {
$aResult = array('code' => 'error', 'percentage' => 100, 'message' => utils::HtmlEntities($e->GetLocalizedMessage()));
$oPage->add(json_encode($aResult));
} catch (Exception $e) {
$aResult = array('code' => 'error', 'percentage' => 100, 'message' => utils::HtmlEntities($e->getMessage()));
$oPage->add(json_encode($aResult));
}
}
}

0 comments on commit eebc29d

Please sign in to comment.