*/ namespace oat\taoDeliveryRdf\scripts\tools; use oat\oatbox\extension\AbstractAction; use oat\generis\model\OntologyAwareTrait; use oat\taoDelivery\model\execution\OntologyDeliveryExecution; use oat\taoDelivery\model\execution\ServiceProxy; use oat\taoDeliveryRdf\model\DeliveryAssemblyService; use oat\taoDelivery\model\execution\implementation\KeyValueService; use oat\taoResultServer\models\classes\implementation\ResultServerService; /** * Start your way from this * php index.php "oat\taoDeliveryRdf\scripts\tools\jMeterCleaner" it will provide you your path * * But be careful not all ways are safe, make sure that you have dump of the DB before use this * * Class jMeterCleaner * @package oat\taoAct\scripts\tools */ class jMeterCleaner extends AbstractAction { use OntologyAwareTrait; /** * @var \common_report_Report */ private $report; /** * If one of the sections has been already done * @var bool */ private $done = false; /** * All passed params * @var array */ private $params = []; private $testTakerClass; private $deliveryClass; public function __invoke($params) { // Load needed constants \common_ext_ExtensionsManager::singleton()->getExtensionById('taoDelivery'); $extensionManager = $this->getServiceManager()->get(\common_ext_ExtensionsManager::SERVICE_ID); $extensionManager->getExtensionById('taoDeliveryRdf'); $extensionManager->getExtensionById('taoDeliveryRdf'); $this->params = $params; // since lti uses #user then we can't use #subject (but subject is the subclass of user then it will work) $this->testTakerClass = $this->getClass('http://www.tao.lu/Ontologies/generis.rdf#User'); $deliveryService = DeliveryAssemblyService::singleton(); $this->deliveryClass = $deliveryService->getRootClass(); $this->report = \common_report_Report::createInfo('Report'); $this->usage(); $this->run(); return $this->report; } // how it works private function usage() { if (empty($this->params)) { $usageHelper = \common_report_Report::createInfo('USAGE: What you could do here:'); $usageHelper->add(\common_report_Report::createSuccess('Please, Note that sections must not intersect otherwise it will work according to priority')); $countDeliveriesForUsers = \common_report_Report::createInfo('1. Count how many deliveries has each of the user'); $countDeliveriesForUsers->add(\common_report_Report::createInfo('--count-deliveries-by-user')); $countDeliveriesForUsers->add(\common_report_Report::createInfo('--open-out `show all deliveries and executions id`')); $usageHelper->add($countDeliveriesForUsers); $openDeliveriesForUser = \common_report_Report::createInfo('2. Detailed report about deliveries for user'); $openDeliveriesForUser->add(\common_report_Report::createInfo('--detailed-report')); $openDeliveriesForUser->add(\common_report_Report::createInfo('--detailed-user=[userId]')); $openDeliveriesForUser->add(\common_report_Report::createInfo('--open-out `show all deliveries and executions id`')); $usageHelper->add($openDeliveriesForUser); $cleaner = \common_report_Report::createInfo('2. Clean test data that you want (The greater the force, the greater the responsibility)'); $cleaner->add(\common_report_Report::createFailure('Note: everything will be deleted even user')); $cleaner->add(\common_report_Report::createInfo('--run-cleaner')); $cleaner->add(\common_report_Report::createInfo('--clean-user=[userId] `will be deleted user, executions and states`')); $cleaner->add(\common_report_Report::createInfo('--clean-user-with-his-deliveries `will be deleted user, executions, states, DELIVERIES and RESULTS`')); $cleaner->add(\common_report_Report::createInfo('--clean-delivery=[deliveryId] `not required. If provided, then will be deleted only that delivery and results`')); $usageHelper->add($cleaner); $executionsCleaner = \common_report_Report::createInfo('3. Delete only executions and test results (The greater the force, the greater the responsibility)'); $executionsCleaner->add(\common_report_Report::createFailure('Note: will be deleted results, executions and services states')); $executionsCleaner->add(\common_report_Report::createInfo('--run-executions-cleaner')); $executionsCleaner->add(\common_report_Report::createInfo('--clean-user=[userId] `will be deleted executions, results and states`')); $executionsCleaner->add(\common_report_Report::createInfo('--clean-users-whose-label-begin-with=[string] `min length 3 symbols. Will be deleted executions, results and states only for the users whose labels begin with specified string.`')); $usageHelper->add($executionsCleaner); $this->report->add($usageHelper); } } // entry for the actions private function run() { $this->counter(); $this->detailed(); $this->cleaner(); $this->executionsCleaner(); } /** * First section with general information about users */ private function counter() { if (!$this->done && in_array('--count-deliveries-by-user', $this->params)) { $this->done = true; $counterReport = \common_report_Report::createInfo('List of Users:'); $helper = new ConsoleTableHelper(); $helper->addHeader(['TestTaker', 'Deliveries', 'Executions']); $helper->addRows($this->getCountersByUsers(!in_array('--open-out', $this->params))); $counterReport->add($helper->generateReport()); $this->report->add($counterReport); } } private function getCountersByUsers($counted = true) { $deliveries = $this->deliveryClass->getInstances(true); $testTakers = $this->testTakerClass->getInstances(true); $src = []; foreach ($deliveries as $delivery) { foreach ($testTakers as $testTaker) { $this->getUserDeliveryData($testTaker, $delivery, $counted, $src); } } return $this->convertSrcToData($src, $counted); } private function convertSrcToData($src, $counted) { if ($counted) { $data = []; foreach ($src as $ttLabel => $ttData) { $row = []; $row[] = $ttLabel; $row[] = count($ttData); // count of the deliveries $row[] = array_sum($ttData); // count of the executions $data[] = $row; } } else { $data = $src; } return $data; } private function getUserDeliveryData($testTaker, $delivery, $counted, &$src) { $executions = ServiceProxy::singleton()->getUserExecutions($delivery, $testTaker->getUri()); foreach ($executions as $execution) { /* * Uncounted source */ if (!$counted) { $row = []; $row[] = $testTaker->getUri() . ' (' . $testTaker->getLabel() . ')'; $row[] = $delivery->getUri(); $row[] = $execution->getIdentifier(); $src[] = $row; } else { $ttLabel = $testTaker->getUri() . ' (' . $testTaker->getLabel() . ')'; if (isset($src[$ttLabel])) { if (isset($src[$ttLabel][$delivery->getUri()])) { $src[$ttLabel][$delivery->getUri()]++; } else { $src[$ttLabel][$delivery->getUri()] = 1; } } else { $src[$ttLabel] = [ $delivery->getUri() => 1]; } } } } /** * Second section with detailed information about the specified user */ private function detailed() { if (!$this->done && in_array('--detailed-report', $this->params)) { $this->done = true; $details = $this->getDetailsForUser(!in_array('--open-out', $this->params)); if ($details !== false) { $counterReport = \common_report_Report::createInfo('Detailed report for the user'); $helper = new ConsoleTableHelper(); $helper->addHeader(['TestTaker', 'Deliveries', 'Executions']); $helper->addRows($details); $counterReport->add($helper->generateReport()); $this->report->add($counterReport); } } } /** * Get parameter from the list of parameters as Resource * @param string $prefix * @return bool|\core_kernel_classes_Resource */ private function getResourceFromParameter($prefix = '--unique-prefix') { $resource = null; $hasParameter = false; $val = $this->getParameterValue($prefix); if ($val) { $hasParameter = true; $resource = $this->getResource($val); if (!$resource->exists()) { $resource = null; } } return $hasParameter ? $resource : false; } private function getParameterValue($prefix = '--unique-prefix') { $value = false; foreach ($this->params as $param) { if (mb_strpos($param, $prefix) !== false) { $value = str_replace($prefix, '', $param); $value = trim($value, '[]'); break; } } return $value; } private function getDetailsForUser($counted = true) { $testTaker = $this->getResourceFromParameter('--detailed-user='); if (!$testTaker) { $this->report->add(\common_report_Report::createFailure('--detailed-user=[userId] is required and need to be a Resource')); return false; } return $this->getDataByTestTaker($testTaker, $counted); } private function getDataByTestTaker($testTaker, $counted) { $deliveries = $this->deliveryClass->getInstances(true); $src = []; foreach ($deliveries as $delivery) { $this->getUserDeliveryData($testTaker, $delivery, $counted, $src); } return $this->convertSrcToData($src, $counted); } /** * The most dangerous of the sections which will affect on the stored data */ private function cleaner() { if (!$this->done && in_array('--run-cleaner', $this->params)) { $this->done = true; $testTaker = $this->getResourceFromParameter('--clean-user='); if (!$testTaker) { $this->report->add(\common_report_Report::createFailure('--clean-user=[userId] is required and need to be a Resource')); return false; } $delivery = $this->getResourceFromParameter('--clean-delivery='); if ($delivery) { $this->report->add(\common_report_Report::createInfo('Deleting of the delivery data [' . $delivery->getUri() . ']')); } elseif ($delivery === null) { $this->report->add(\common_report_Report::createFailure('Delivery does not found')); return false; } else { $this->report->add(\common_report_Report::createInfo('Deleting of the TestTaker data [' . $testTaker->getUri() . ']')); } $ttData = $this->getDataByTestTaker($testTaker, false); if (!count($ttData)) { $this->report->add(\common_report_Report::createFailure('TestTaker with id [' . $testTaker->getUri() . '] has not been found')); return false; } elseif ($delivery) { $hasDelivery = false; foreach ($ttData as $row) { if ($row[1] == $delivery->getUri()) { $hasDelivery = true; break; } } if (!$hasDelivery) { $this->report->add(\common_report_Report::createFailure('Delivery with id [' . $testTaker->getUri() . '] has not been found')); return false; } } if ($delivery) { $this->deleteDelivery($delivery); } else { $this->deleteTestTaker($testTaker, $ttData); } } return true; } private function executionsCleaner() { if (!$this->done && in_array('--run-executions-cleaner', $this->params)) { $this->done = true; $testTaker = $this->getResourceFromParameter('--clean-user='); $labelBeginWith = $this->getParameterValue('--clean-users-whose-label-begin-with='); if (!$testTaker && !$labelBeginWith) { $this->report->add(\common_report_Report::createFailure('You should use one of the --clean-user or --clean-users-whose-label-begin-with, not together')); return false; } if ($testTaker && $labelBeginWith) { $this->report->add(\common_report_Report::createFailure('You can use --clean-user or --clean-users-whose-label-begin-with, not together')); return false; } if (mb_strlen($labelBeginWith) < 3) { $this->report->add(\common_report_Report::createFailure('Value of the --clean-users-whose-label-begin-with can not be less then 3 symbols')); return false; } if ($testTaker) { // clean his data $this->cleanTestTakersExecutions($testTaker); } if ($labelBeginWith) { // clean all test takers according to this mask $this->cleanExecutionsByMask($labelBeginWith); } } return true; } private function cleanTestTakersExecutions($testTaker) { $ttData = $this->getDataByTestTaker($testTaker, false); if (!count($ttData)) { $this->report->add(\common_report_Report::createFailure('TestTaker with id [' . $testTaker->getUri() . '] has not been found')); return false; } // delete deliveries results $deliveries = []; foreach ($ttData as $row) { if (isset($row[1])) { $deliveries[] = $row[1]; } } $removeResultsReport = $this->removeResults($deliveries); $this->report->add($removeResultsReport); // delete executions $executionRemovedReport = $this->removeDeliveryExecutions($testTaker->getUri()); $this->report->add($executionRemovedReport); // delete states $statesRemovedReport = $this->removeServiceState($testTaker->getUri()); $this->report->add($statesRemovedReport); $this->report->add(\common_report_Report::createSuccess('TestTakers data about results and executions were cleaned')); } private function cleanExecutionsByMask($labelBeginWith = '') { $data = $this->getCountersByUsers(); foreach ($data as $row) { if ($pos = mb_strpos($row[0], '(' . $labelBeginWith)) { $uri = trim(mb_substr($row[0], 0, $pos)); $testTaker = $this->getResource($uri); $this->cleanTestTakersExecutions($testTaker); } } } private function deleteDelivery($delivery) { if (!$delivery->exists()) { return false; } $resultRemoveReport = $this->removeResults((array)$delivery->getUri()); $this->report->add($resultRemoveReport); $delivery->delete(true); $this->report->add(\common_report_Report::createSuccess('Delivery deleted')); } private function deleteTestTaker($testTaker, $ttData) { if (in_array('--clean-user-with-his-deliveries', $this->params)) { foreach ($ttData as $executionRow) { if (isset($executionRow[1])) { $this->deleteDelivery($this->getResource($executionRow[1])); } } } $executionRemovedReport = $this->removeDeliveryExecutions($testTaker->getUri()); $this->report->add($executionRemovedReport); $statesRemovedReport = $this->removeServiceState($testTaker->getUri()); $this->report->add($statesRemovedReport); $testTaker->delete(true); $this->report->add(\common_report_Report::createSuccess('TestTaker deleted')); } private function removeResults(array $deliveries) { $report = new \common_report_Report(\common_report_Report::TYPE_SUCCESS); try { /** @var ResultServerService $resultService */ $resultService = $this->getServiceLocator()->get(ResultServerService::SERVICE_ID); $count = 0; foreach ($deliveries as $delivery) { $implementation = $resultService->getResultStorage($delivery); foreach ($implementation->getResultByDelivery([$delivery]) as $result) { if ($implementation->deleteResult($result['deliveryResultIdentifier'])) { $count++; } else { $report->setType(\common_report_Report::TYPE_ERROR); $report->setMessage('Cannot cleanup results for ' . $result['deliveryResultIdentifier']); } } } $report->setMessage('Removed ' . $count . ' on ' . count($deliveries) . ' RDS results'); } catch (\common_Exception $e) { $report->setType(\common_report_Report::TYPE_ERROR); $report->setMessage('Cannot cleanup Results: ' . $e->getMessage()); } return $report; } private function removeDeliveryExecutions($userUri) { $report = new \common_report_Report(\common_report_Report::TYPE_SUCCESS); // deliveryExecutions $extension = \common_ext_ExtensionsManager::singleton()->getExtensionById('taoDelivery'); $deliveryService = $extension->getConfig('execution_service'); if ($deliveryService instanceof KeyValueService) { $persistenceOption = $deliveryService->getOption(KeyValueService::OPTION_PERSISTENCE); $persistence = \common_persistence_KeyValuePersistence::getPersistence($persistenceOption); $count = 0; foreach ($persistence->keys('kve_*' . $userUri . '*') as $key) { if (substr($key, 0, 4) == 'kve_') { $persistence->del($key); $count++; } } $report->setMessage('Removed ' . $count . ' key-value delivery executions of ' . $userUri); } elseif ($deliveryService instanceof OntologyDeliveryExecution) { $count = 0; $deliveryExecutionClass = new \core_kernel_classes_Class(OntologyDeliveryExecution::CLASS_URI); $deliveryExecutions = $deliveryExecutionClass->searchInstances([OntologyDeliveryExecution::PROPERTY_SUBJECT => $userUri]); /** @var \core_kernel_classes_Class $deliveryExecution */ foreach ($deliveryExecutions as $deliveryExecution) { $deliveryExecution->delete(true); $count++; } $report->setMessage('Removed ' . $count . ' ontology delivery executions of ' . $userUri); } else { $report->setType(\common_report_Report::TYPE_ERROR); $report->setMessage('Cannot cleanup delivery executions from ' . get_class($deliveryService)); } return $report; } private function removeServiceState($userUri) { $report = new \common_report_Report(\common_report_Report::TYPE_SUCCESS); // service states $persistence = \common_persistence_KeyValuePersistence::getPersistence(\tao_models_classes_service_StateStorage::PERSISTENCE_ID); if ($persistence instanceof \common_persistence_AdvKeyValuePersistence) { $count = 0; foreach ($persistence->keys('tao:state:' . $userUri . '*') as $key) { if (substr($key, 0, 10) == 'tao:state:') { $persistence->del($key); $count++; } } $report->setMessage('Removed ' . $count . ' states ' . $userUri); } elseif ($persistence instanceof \common_persistence_KeyValuePersistence) { try { if ($persistence->purge()) { $report->setMessage('States correctly removed'); } } catch (\common_exception_NotImplemented $e) { $report->setType(\common_report_Report::TYPE_ERROR); $report->setMessage($e->getMessage()); } } else { $report->setType(\common_report_Report::TYPE_ERROR); $report->setMessage('Cannot cleanup states from ' . get_class($persistence)); } return $report; } }