public function testSecurityExceptionThrownDuringExport() { $super = User::getByUsername('super'); Yii::app()->user->userModel = $super; SecurityTestHelper::createAccounts(); $billy = User::getByUsername('billy'); Yii::app()->user->userModel = $billy; AllPermissionsOptimizationUtil::rebuild(); $numberOfUserNotifications = Notification::getCountByTypeAndUser('ExportProcessCompleted', $billy); $account = new Account(false); $searchForm = new AccountsSearchForm($account); $dataProvider = ExportTestHelper::makeRedBeanDataProvider($searchForm, 'Account', 0, $billy->id); $totalItems = $dataProvider->getTotalItemCount(); $this->assertEquals(3, $totalItems); $exportItem = new ExportItem(); $exportItem->isCompleted = 0; $exportItem->exportFileType = 'csv'; $exportItem->exportFileName = 'test7'; $exportItem->modelClassName = 'Account'; $exportItem->serializedData = serialize($dataProvider); $exportItem->owner = $billy; $this->assertTrue($exportItem->save()); $id = $exportItem->id; $exportItem->forget(); unset($exportItem); //Delete queued jobs from test exportItems created above Yii::app()->jobQueue->deleteAll(); $accounts = Account::getByName('Microsoft'); $account = $accounts[0]; $account->owner = $super; $this->assertTrue($account->save()); $job = new ExportJob(); //ReadPermissionSubscriptionUpdate should get added to jobQueue $this->assertEquals(0, count(Yii::app()->jobQueue->getAll())); $this->assertTrue($job->run()); $this->assertEquals(0, count(Yii::app()->jobQueue->getAll())); $exportItem = ExportItem::getById($id); $fileModel = $exportItem->exportFileModel; $this->assertEquals(1, $exportItem->isCompleted); $this->assertEquals('csv', $exportItem->exportFileType); $this->assertEquals('test7', $exportItem->exportFileName); $this->assertTrue($fileModel instanceof ExportFileModel); $data = array(); $rows = $dataProvider->getData(); $modelToExportAdapter = new ModelToExportAdapter($rows[0]); $headerData = $modelToExportAdapter->getHeaderData(); foreach ($rows as $model) { //billy lost access to Microsoft account if ($model->id != $account->id) { $modelToExportAdapter = new ModelToExportAdapter($model); $data[] = $modelToExportAdapter->getData(); } } $output = ExportItemToCsvFileUtil::export($data, $headerData, 'test7.csv', false); $this->assertEquals($output, $fileModel->fileContent->content); }
/** * Test if background export job generated csv file, * check if content of this csv file is correct, and * finally check if user got notification message that * his downloads are completed. */ public function testRun() { $super = User::getByUsername('super'); Yii::app()->user->userModel = $super; $numberOfUserNotifications = Notification::getCountByTypeAndUser('ExportProcessCompleted', Yii::app()->user->userModel); $account = new Account(); $account->owner = $super; $account->name = 'Test Account'; $account->officePhone = '1234567890'; $this->assertTrue($account->save()); $account = new Account(); $account->owner = $super; $account->name = 'Test Account 2'; $account->officePhone = '1234567899'; $this->assertTrue($account->save()); $account = new Account(false); $searchForm = new AccountsSearchForm($account); $dataProvider = ExportTestHelper::makeRedBeanDataProvider($searchForm, 'Account', 0, Yii::app()->user->userModel->id); $totalItems = $dataProvider->getTotalItemCount(); $this->assertEquals(2, $totalItems); $exportItem = new ExportItem(); $exportItem->isCompleted = 0; $exportItem->exportFileType = 'csv'; $exportItem->exportFileName = 'test'; $exportItem->modelClassName = 'Account'; $exportItem->serializedData = serialize($dataProvider); $this->assertTrue($exportItem->save()); $id = $exportItem->id; $exportItem->forget(); unset($exportItem); $job = new ExportJob(); $this->assertTrue($job->run()); $exportItem = ExportItem::getById($id); $fileModel = $exportItem->exportFileModel; $this->assertEquals(1, $exportItem->isCompleted); $this->assertEquals('csv', $exportItem->exportFileType); $this->assertEquals('test', $exportItem->exportFileName); $this->assertTrue($fileModel instanceof ExportFileModel); // Get csv string via regular csv export process(directly, not in background) // We suppose that csv generated thisway is corrected, this function itself // is tested in another test. $data = array(); $rows = $dataProvider->getData(); $modelToExportAdapter = new ModelToExportAdapter($rows[0]); $headerData = $modelToExportAdapter->getHeaderData(); foreach ($rows as $model) { $modelToExportAdapter = new ModelToExportAdapter($model); $data[] = $modelToExportAdapter->getData(); } $output = ExportItemToCsvFileUtil::export($data, $headerData, 'test.csv', false); $this->assertEquals($output, $fileModel->fileContent->content); // Check if user got notification message, and if its type is ExportProcessCompleted $this->assertEquals($numberOfUserNotifications + 1, Notification::getCountByTypeAndUser('ExportProcessCompleted', Yii::app()->user->userModel)); }
protected function export($stickySearchKey = null, $modelClassName = null, $exportFileName = null) { assert('$stickySearchKey == null || is_string($stickySearchKey)'); assert('$modelClassName == null || is_string($modelClassName)'); assert('$exportFileName == null || is_string($exportFileName)'); if ($modelClassName == null) { $modelClassName = $this->getModelName(); } $searchFormClassName = static::getSearchFormClassName(); $pageSize = null; $model = new $modelClassName(false); if ($searchFormClassName != null) { $searchForm = new $searchFormClassName($model); } else { throw new NotSupportedException(); } $stateMetadataAdapterClassName = $this->resolveStateMetadataAdapterClassNameForExport(); $dataProvider = $this->getDataProviderByResolvingSelectAllFromGet($searchForm, $pageSize, Yii::app()->user->userModel->id, $stateMetadataAdapterClassName, $stickySearchKey); if (!$dataProvider) { $idsToExport = array_filter(explode(",", trim($_GET['selectedIds'], " ,"))); // Not Coding Standard } $totalItems = static::getSelectedRecordCountByResolvingSelectAllFromGet($dataProvider, false); $data = array(); if ($totalItems > 0) { if ($totalItems <= ExportModule::$asynchronousThreshold) { // Output csv file directly to user browser if ($dataProvider) { $modelsToExport = ExportUtil::getDataForExport($dataProvider); if (count($modelsToExport) > 0) { $modelToExportAdapter = new ModelToExportAdapter($modelsToExport[0]); $headerData = $modelToExportAdapter->getHeaderData(); } foreach ($modelsToExport as $model) { if (ControllerSecurityUtil::doesCurrentUserHavePermissionOnSecurableItem($model, Permission::READ)) { $modelToExportAdapter = new ModelToExportAdapter($model); $data[] = $modelToExportAdapter->getData(); } } } else { $headerData = array(); foreach ($idsToExport as $idToExport) { $model = $modelClassName::getById(intval($idToExport)); if (ControllerSecurityUtil::doesCurrentUserHavePermissionOnSecurableItem($model, Permission::READ)) { $modelToExportAdapter = new ModelToExportAdapter($model); $data[] = $modelToExportAdapter->getData(); if (count($headerData) == 0) { $headerData = $modelToExportAdapter->getHeaderData(); } } } } // Output data if (count($data)) { if ($exportFileName == null) { $fileName = $this->getModule()->getName() . ".csv"; } else { $fileName = $exportFileName . ".csv"; } $output = ExportItemToCsvFileUtil::export($data, $headerData, $fileName, true); } else { Yii::app()->user->setFlash('notification', Zurmo::t('ZurmoModule', 'There is no data to export.')); } } else { if ($dataProvider) { $serializedData = ExportUtil::getSerializedDataForExport($dataProvider); } else { $serializedData = serialize($idsToExport); } // Create background job $exportItem = new ExportItem(); $exportItem->isCompleted = false; $exportItem->exportFileType = 'csv'; $exportItem->exportFileName = $this->getModule()->getName(); $exportItem->modelClassName = $modelClassName; $exportItem->serializedData = $serializedData; $exportItem->isJobRunning = false; $exportItem->cancelExport = false; $exportItem->save(); $exportItem->forget(); Yii::app()->user->setFlash('notification', Zurmo::t('ZurmoModule', 'A large amount of data has been requested for export. You will receive ' . 'a notification with the download link when the export is complete.')); } } else { Yii::app()->user->setFlash('notification', Zurmo::t('ZurmoModule', 'There is no data to export.')); } $this->redirect(array($this->getId() . '/index')); }
/** * @depends testGetDataWithAllHasOneOrOwnedRelationsSet */ public function testGetDataWithHasOneRelatedModel() { $super = User::getByUsername('super'); Yii::app()->user->userModel = $super; $currencies = Currency::getAll(); $currencyValue = new CurrencyValue(); $currencyValue->value = 100; $currencyValue->currency = $currencies[0]; $this->assertEquals('USD', $currencyValue->currency->code); $testItem2 = new ExportTestModelItem2(); $testItem2->name = 'John'; $this->assertTrue($testItem2->save()); $testItem4 = new ExportTestModelItem4(); $testItem4->name = 'John'; $this->assertTrue($testItem4->save()); //HAS_MANY and MANY_MANY relationships should be ignored. $testItem3_1 = new ExportTestModelItem3(); $testItem3_1->name = 'Kevin'; $this->assertTrue($testItem3_1->save()); $testItem3_2 = new ExportTestModelItem3(); $testItem3_2->name = 'Jim'; $this->assertTrue($testItem3_2->save()); $testItem = new ExportTestModelItem(); $testItem->firstName = 'Bob3'; $testItem->lastName = 'Bob3'; $testItem->boolean = true; $testItem->date = '2002-04-03'; $testItem->dateTime = '2002-04-03 02:00:43'; $testItem->float = 54.22; $testItem->integer = 10; $testItem->phone = '21313213'; $testItem->string = 'aString'; $testItem->textArea = 'Some Text Area'; $testItem->url = 'http://www.asite.com'; $testItem->email = '*****@*****.**'; $testItem->owner = $super; $testItem->currencyValue = $currencyValue; $testItem->hasOne = $testItem2; $testItem->hasMany->add($testItem3_1); $testItem->hasMany->add($testItem3_2); $testItem->hasOneAlso = $testItem4; $createStamp = strtotime(DateTimeUtil::convertTimestampToDbFormatDateTime(time())); $this->assertTrue($testItem->save()); $id = $testItem->id; $testItem->forget(); unset($testItem); $testItem = ExportTestModelItem::getById($id); $adapter = new ModelToExportAdapter($testItem); $data = $adapter->getData(); $headerData = $adapter->getHeaderData(); $compareData = array($id, 'stubDateTime', 'stubDateTime', 'super', 'super', 'super', 'Bob3', 'Bob3', '1', '2002-04-03', '2002-04-03 02:00:43', 54.22, 10, '21313213', 'aString', 'Some Text Area', 'http://www.asite.com', '*****@*****.**', null, 100, 'USD', null, null, null, null, '(None)', '(None)', null, null, null, null, null, null, null, null, null, null, null, null, null); $compareHeaderData = array($testItem->getAttributeLabel('id'), $testItem->getAttributeLabel('createdDateTime'), $testItem->getAttributeLabel('modifiedDateTime'), $testItem->getAttributeLabel('createdByUser'), $testItem->getAttributeLabel('modifiedByUser'), $testItem->getAttributeLabel('owner'), $testItem->getAttributeLabel('firstName'), $testItem->getAttributeLabel('lastName'), $testItem->getAttributeLabel('boolean'), $testItem->getAttributeLabel('date'), $testItem->getAttributeLabel('dateTime'), $testItem->getAttributeLabel('float'), $testItem->getAttributeLabel('integer'), $testItem->getAttributeLabel('phone'), $testItem->getAttributeLabel('string'), $testItem->getAttributeLabel('textArea'), $testItem->getAttributeLabel('url'), $testItem->getAttributeLabel('email'), $testItem->getAttributeLabel('currency'), $testItem->getAttributeLabel('currencyValue'), $testItem->getAttributeLabel('currencyValue') . ' ' . 'Currency', $testItem->getAttributeLabel('dropDown'), $testItem->getAttributeLabel('radioDropDown'), $testItem->getAttributeLabel('multiDropDown'), $testItem->getAttributeLabel('tagCloud'), $testItem->getAttributeLabel('hasOne') . ' - ' . 'Name', $testItem->getAttributeLabel('hasOneAlso') . ' - ' . 'Name', 'Primary Email - Email Address', 'Primary Email - Is Invalid', 'Primary Email - Opt Out', 'Primary Address - City', 'Primary Address - Country', 'Primary Address - Postal Code', 'Primary Address - Street 1', 'Primary Address - Street 2', 'Primary Address - State', 'Secondary Email - Email Address', 'Secondary Email - Is Invalid', 'Secondary Email - Opt Out', $testItem->getAttributeLabel('user')); // Because small delay in IO operation, allow tresholds $createdDateTimeKey = array_search($testItem->getAttributeLabel('createdDateTime'), $headerData); $modifiedDateTimeKey = array_search($testItem->getAttributeLabel('modifiedDateTime'), $headerData); $this->assertEquals($createStamp, strtotime($data[$createdDateTimeKey]), '', 2); $this->assertEquals($createStamp, strtotime($data[$modifiedDateTimeKey]), '', 2); $data[$createdDateTimeKey] = 'stubDateTime'; $data[$modifiedDateTimeKey] = 'stubDateTime'; $this->assertEquals($compareData, $data); $this->assertEquals($compareHeaderData, $headerData); }
/** * Get the header row data which includes a label for each column * @return array $data */ public function getHeaderData() { $data = array(); $data[] = $this->resolveIdLabelToTitleCaseForExport($this->model->getAttributeLabel('id')); $retrievableAttributes = static::resolveExportableAttributesByModel($this->model); foreach ($this->model->getAttributes($retrievableAttributes) as $attributeName => $notUsed) { if (null !== ($adapterClassName = $this->getRedBeanModelAttributeValueToExportValueAdapterClassName($attributeName)) && !($this->model->isRelation($attributeName) && $this->model->getRelationType($attributeName) != RedBeanModel::HAS_ONE)) { //Non-relation attribute $adapter = new $adapterClassName($this->model, $attributeName); $adapter->resolveHeaderData($data); } elseif ($this->isHasOneVariationOwnedRelation($attributeName)) { //Owned relation attribute if ($this->model->{$attributeName}->id > 0) { $util = new ModelToExportAdapter($this->model->{$attributeName}); $relatedData = $util->getData(); foreach ($relatedData as $relatedDataAttribute => $notUsed) { if (strtolower($relatedDataAttribute) != 'id') { $exportAttributeName = static::getLabelFromTwoAttributeStrings($this->model->getAttributeLabel($attributeName), $relatedDataAttribute); $data[] = $exportAttributeName; } } } else { $data = array_merge($data, $this->getAllAtttributesDataAsLabels($attributeName)); } } elseif ($this->model->isRelation($attributeName) && $this->model->getRelationType($attributeName) == RedBeanModel::HAS_ONE) { //Non-owned relation if ($this->model->{$attributeName}->id > 0) { $label = static::getLabelFromTwoAttributeStrings($this->model->getAttributeLabel($attributeName), Zurmo::t('ExportModule', 'Name')); $data[] = $label; } else { $data[] = $this->model->getAttributeLabel($attributeName); } } } return $data; }
protected function isValidCsvConversion($textAreaContent) { $super = User::getByUsername('super'); Yii::app()->user->userModel = $super; $testItem = new ExportTestModelItem(); $testItem->firstName = 'Bob3'; $testItem->lastName = 'Bob3'; $testItem->boolean = true; $testItem->date = '2002-04-03'; $testItem->dateTime = '2002-04-03 02:00:43'; $testItem->float = 54.22; $testItem->integer = 10; $testItem->phone = '21313213'; $testItem->string = 'aString'; $testItem->textArea = $textAreaContent; $testItem->url = 'http://www.asite.com'; $testItem->email = '*****@*****.**'; $testItem->save(); $id = $testItem->id; $testItem->forget(); unset($testItem); $data = array(); $testItem = ExportTestModelItem::getById($id); $adapter = new ModelToExportAdapter($testItem); $data[] = $adapter->getData(); $headerData = $adapter->getHeaderData(); // Export data to csv, and then revert csv back to array, so we compare data $csvData = ExportItemToCsvFileUtil::export($data, $headerData, 'exports.csv', false); $revertedData = CsvParser::parseFromString($csvData); // We are testing ModelToExportAdapter in details in another test // so in this test we suppose that ModelToExportAdapter::getData // return correct results $adapter = new ModelToExportAdapter($testItem); $compareData = $adapter->getData(); $compareHeaderData = $adapter->getHeaderData(); // Using === here would fail as we are not setting all keys part of getData()'s return array if ($compareData == array_values($revertedData[0]) && $compareHeaderData == array_keys($revertedData[0])) { return true; } return false; }
/** * @param array $models * @param array $headerData * @param array $data * @param bool $resolveForHeader */ protected function processExportModels(array $models, &$headerData, &$data, $resolveForHeader = true) { foreach ($models as $model) { $canRead = ControllerSecurityUtil::doesCurrentUserHavePermissionOnSecurableItem($model, Permission::READ); if ($canRead) { $modelToExportAdapter = new ModelToExportAdapter($model); if (count($headerData) == 0 && $resolveForHeader) { $headerData = $modelToExportAdapter->getHeaderData(); } $data[] = $modelToExportAdapter->getData(); unset($modelToExportAdapter); } $this->runGarbageCollection($model); } unset($models); }
public function run() { $exportItems = ExportItem::getUncompletedItems(); if (count($exportItems) > 0) { foreach ($exportItems as $exportItem) { if (isset($exportItem->exportFileModel)) { //continue; } $unserializedData = unserialize($exportItem->serializedData); if ($unserializedData instanceof RedBeanModelDataProvider) { $formattedData = $unserializedData->getData(); } else { $formattedData = array(); foreach ($unserializedData as $idToExport) { $model = call_user_func(array($exportItem->modelClassName, 'getById'), intval($idToExport)); $formattedData[] = $model; } } if ($exportItem->exportFileType == 'csv') { $headerData = array(); foreach ($formattedData as $model) { if (ControllerSecurityUtil::doesCurrentUserHavePermissionOnSecurableItem($model, Permission::READ)) { $modelToExportAdapter = new ModelToExportAdapter($model); if (count($headerData) == 0) { $headerData = $modelToExportAdapter->getHeaderData(); } $data[] = $modelToExportAdapter->getData(); } } $output = ExportItemToCsvFileUtil::export($data, $headerData); $fileContent = new FileContent(); $fileContent->content = $output; $exportFileModel = new ExportFileModel(); $exportFileModel->fileContent = $fileContent; $exportFileModel->name = $exportItem->exportFileName . ".csv"; $exportFileModel->type = 'application/octet-stream'; $exportFileModel->size = strlen($output); $saved = $exportFileModel->save(); if ($saved) { $exportItem->isCompleted = 1; $exportItem->exportFileModel = $exportFileModel; $exportItem->save(); $message = new NotificationMessage(); $message->htmlContent = Zurmo::t('ExportModule', 'Export of {fileName} requested on {dateTime} is completed. <a href="{url}">Click here</a> to download file!', array('{fileName}' => $exportItem->exportFileName, '{url}' => Yii::app()->createUrl('export/default/download', array('id' => $exportItem->id)), '{dateTime}' => DateTimeUtil::convertDbFormattedDateTimeToLocaleFormattedDisplay($exportItem->createdDateTime, 'long'))); $rules = new ExportProcessCompletedNotificationRules(); NotificationsUtil::submit($message, $rules); } } } } else { return true; } return true; }
public function testHasOneAndNotOwnedVariants() { $super = User::getByUsername('super'); Yii::app()->user->userModel = $super; $adapter = new ModelToExportAdapter($super); $data = $adapter->getData(); $headerData = $adapter->getHeaderData(); $this->assertTrue(in_array($super->getAttributeLabel('language'), $headerData)); $this->assertTrue(in_array($super->getAttributeLabel('locale'), $headerData)); $this->assertTrue(in_array($super->getAttributeLabel('timeZone'), $headerData)); $this->assertTrue(in_array($super->getAttributeLabel('role'), $headerData)); $this->assertEquals(count($headerData), count($data)); }