tools.php 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  1. <?php
  2. namespace MGModule\DNSManager2\controllers\addon\admin;
  3. use MGModule\DNSManager2 as main;
  4. use MGModule\DNSManager2\helpers\WHMCS\Domain;
  5. use MGModule\DNSManager2\helpers\WHMCS\Service;
  6. use MGModule\DNSManager2\mgLibs\custom;
  7. use MGModule\DNSManager2\mgLibs\custom\AjaxResponse;
  8. use MGModule\DNSManager2\mgLibs\custom\dns;
  9. use MGModule\DNSManager2\mgLibs\custom\helpers;
  10. use MGModule\DNSManager2\mgLibs\MySQL as mysql;
  11. use MGModule\DNSManager2\models\custom\clientfiles;
  12. use MGModule\DNSManager2\models\custom\globalsetting;
  13. use MGModule\DNSManager2\models\custom\server;
  14. use MGModule\DNSManager2\models\custom\task;
  15. class tools extends main\mgLibs\process\abstractController{
  16. function indexHTML($input, $vars = array()) {
  17. $cron_last_run = globalsetting\GlobalSetting::byKey(globalsetting\GlobalSettingEnum::CRON_LAST_RUN)->value;
  18. $vars['cron_path'] = main\addon::getMainDIR() . DS . 'cron' . DS . 'cron.php';
  19. $vars['cron_last_run'] = custom\helpers\TimeDiffHelper::diff($cron_last_run)->minutes;
  20. $vars['cron_run_time_period'] = globalsetting\GlobalSetting::byKey(globalsetting\GlobalSettingEnum::CRON_RUN_TIME_PERIOD)->value;
  21. $vars['available_record_types'] = dns\Core::getAvailableRecordTypes();
  22. $vars['available_no_active_domains'] = Domain::getDomainsStatusesAvailableToDelete();
  23. $vars['available_no_active_service'] = Service::getServicesStatusesAvailableToDelete();
  24. $vars['minutes'] = array(0,5,10,15,20,40,60,120,180,360,720,1440,2880,4320,10080,43200);
  25. $vars['settings'] = array();
  26. foreach(globalsetting\Repository::factory()->get() as $setting) {
  27. $vars['settings'][$setting->key] = $setting->value;
  28. }
  29. $vars['settings']['cron_cleaner_zone_at_least_one'] = unserialize($vars['settings']['cron_cleaner_zone_at_least_one']);
  30. $vars['settings']['cron_cleaner_no_active_domains'] = unserialize($vars['settings']['cron_cleaner_no_active_domains']);
  31. $vars['settings']['cron_cleaner_no_active_service'] = unserialize($vars['settings']['cron_cleaner_no_active_service']);
  32. $vars['cron_last_run'] = intval($vars['cron_last_run']);
  33. $then = new \DateTime(date('Y-m-d H:i:s', time() - $vars['cron_last_run'] * 60));
  34. $now = new \DateTime(date('Y-m-d H:i:s',time()));
  35. $diff = $then->diff($now);
  36. $vars['cron_last_run_years'] = $diff->y;
  37. $vars['cron_last_run_months'] = $diff->m;
  38. $vars['cron_last_run_days'] = $diff->d;
  39. $vars['cron_last_run_hours'] = $diff->h;
  40. $vars['cron_last_run_minutes'] = $diff->i;
  41. return array(
  42. 'tpl' => 'main',
  43. 'vars' => $vars
  44. );
  45. }
  46. public function cronJSON($input, $vars = array()) {
  47. return AjaxResponse::I()->refreshPage($this->cronHTML($input, $vars))->toArray();
  48. }
  49. public function cronHTML($input, $vars = array())
  50. {
  51. return $this->indexHTML($input, $vars);
  52. }
  53. public function saveCronSettingsJSON($input, $vars = array())
  54. {
  55. $input['settings']['cron_cleaner_zone_at_least_one'] = serialize($input['settings']['cron_cleaner_zone_at_least_one']);
  56. $input['settings']['cron_cleaner_no_active_service'] = serialize($input['settings']['cron_cleaner_no_active_service']);
  57. $input['settings']['cron_cleaner_no_active_domains'] = serialize($input['settings']['cron_cleaner_no_active_domains']);
  58. foreach($input['settings'] as $k => $v)
  59. {
  60. $v = ($k == 'cron_cleaner_notify_only' && empty($v)) ? 0 : $v;
  61. globalsetting\GlobalSetting::set($k, $v);
  62. }
  63. $response = AjaxResponse::I()->addInfo('changes_saved');
  64. if((int)$input['settings']['cron_cleaner_run_each'] > 0 && $input['settings']['cron_cleaner_notify_only'] != 'on')
  65. {
  66. $response->addWarning('cron_cleaner_warning');
  67. }
  68. return $response->toArray();
  69. }
  70. //===========================================================================================================
  71. //===========================================MIGRATION=======================================================
  72. //===========================================================================================================
  73. public function migrationJSON($input, $vars = array()) {
  74. return AjaxResponse::I()->refreshPage($this->migrationHTML($input, $vars))->toArray();
  75. }
  76. public function migrationHTML($input, $vars = array()) {
  77. $vars['imports'] = array();
  78. $new_migrations = custom\TaskManager::getXTasksObjects(0, 'Migration:main', 0, task\TaskStatusEnum::START);
  79. foreach($new_migrations as $migration) {
  80. $desc = $migration->description();
  81. $vars['migrations'][] = array(
  82. 'id' => $migration->obj()->id,
  83. 'desc' => $desc,
  84. 'zones_moved' => '-',
  85. 'zones_total' => '-',
  86. 'progress' => -1,
  87. 'error' => $desc == 'Migration:main'?main\mgLibs\lang::T('one_of_servers_has_been_removed'):false,
  88. );
  89. }
  90. $in_progress_migrations = custom\TaskManager::getXTasksObjects(0, 'Migration:main', 0, task\TaskStatusEnum::IN_PROGRESS);
  91. $finished_migrations = custom\TaskManager::getXTasksObjects(0, 'Migration:main', 0, task\TaskStatusEnum::FINISHED);
  92. $migrations = array_merge($in_progress_migrations,$finished_migrations);
  93. foreach($migrations as $migration) {
  94. $rep = new task\Repository();
  95. $rep->byParentID($migration->obj()->id)->byName('Migration:migrate');
  96. $zones_total = $rep->count();
  97. $rep->byStatus(task\TaskStatusEnum::FINISHED);
  98. $zones_moved = $rep->count();
  99. $task = custom\TaskManager::getXTasksObjects(1, 'Migration:fetchZonesList', $migration->obj()->id, false);
  100. if(end($task))
  101. {
  102. $error2 = $this->getTaskError(end($task));
  103. }
  104. $desc = $migration->description();
  105. $error = $desc == 'Migration:main'?main\mgLibs\lang::T('one_of_servers_has_been_removed'):false;
  106. $vars['migrations'][] = array(
  107. 'id' => $migration->obj()->id,
  108. 'desc' => $desc,
  109. 'zones_moved' => $zones_moved,
  110. 'zones_total' => $zones_total,
  111. 'progress' => $zones_total == 0 ? 0 : ceil($zones_moved * 100 / $zones_total),
  112. 'error' => $error?:$error2,
  113. );
  114. }
  115. return array(
  116. 'tpl' => 'migration',
  117. 'vars' => $vars
  118. );
  119. }
  120. public function addMigrationJSON($input, $vars = array()) {
  121. $vars['servers'] = server\Repository::factory()->get();
  122. return AjaxResponse::I()->modal('add-migration', $vars)->toArray();
  123. }
  124. public function addMigrationSaveJSON($input, $vars = array()) {
  125. if( !isset($input['from_server'], $input['to_server']) )
  126. {
  127. return AjaxResponse::I()->toArray();
  128. }
  129. if($input['from_server'] == $input['to_server']) {
  130. AjaxResponse::I()->addError('you_have_to_choose_two_diffrent_servers');
  131. return AjaxResponse::I()->toArray();
  132. }
  133. server\Server::factory($input['from_server'])->getModule()->testConnection();
  134. server\Server::factory($input['to_server'])->getModule()->testConnection();
  135. $moveZone = $input['cron_migration_move_zone'] === 'on';
  136. custom\TaskManager::addTask('Migration:main', ['from' => $input['from_server'], 'to' => $input['to_server'], 'move_zone' => $moveZone]);
  137. AjaxResponse::I()->refreshPage($this->migrationHTML($input, $vars));
  138. AjaxResponse::I()->addInfo('new_task_added');
  139. return AjaxResponse::I()->toArray();
  140. }
  141. public function removeMigrationJSON($input, $vars = array()) {
  142. custom\TaskManager::removeTask($input['id']);
  143. AjaxResponse::I()->refreshPage($this->migrationHTML($input, $vars));
  144. AjaxResponse::I()->addInfo('migration_removed');
  145. return AjaxResponse::I()->toArray();
  146. }
  147. public function showListMigrationJSON($input, $vars = array()) {
  148. $vars['migrationid'] = $input['id'];
  149. $task = custom\TaskManager::getXTasks(1, 'Migration:fetchZonesList', $input['id'], false);
  150. $task = end($task);
  151. $vars['list'] = custom\TaskManager::getTaskResults($task->id);
  152. AjaxResponse::I()->refreshPage(array('tpl' => 'migration-list', 'vars' => $vars));
  153. return AjaxResponse::I()->toArray();
  154. }
  155. function refreshMigrationTableJSON($input, $vars = array()) {
  156. $task = custom\TaskManager::getXTasks(1, 'Migration:fetchZonesList', $input['id'], false);
  157. $task = end($task);
  158. $rep = task\result\Repository::factory()->byTaskID($task->id);
  159. $helper = new main\mgLibs\custom\RepoTableHelper($rep, $input, array('data'));
  160. $vars = $helper->getDataTableArray();
  161. foreach($helper->get() as $task) {
  162. $vars['data'][] = $this->dataTablesParseRow('migration-row', array('item' => $task, 'migrationid' => $input['id']));
  163. }
  164. return $vars;
  165. }
  166. public function migrateZonesJSON($input, $vars = array()) {
  167. foreach($input['zone'] as $result_id => $data) {
  168. if($data['migrate'] != 'on' && !isset($input['justOne']))
  169. continue;
  170. $result = new task\result\TaskResult($result_id);
  171. $task = custom\TaskManager::getTaskObjectByID($result->taskid);
  172. $main_task = $task->getParent(); //TODO: można zmniejszyć ilość danych poprzez odwołanie się do resulta
  173. $child = $main_task->addChild('migrate', array(
  174. 'domain' => $result->data['domain'],
  175. 'ip' => $result->data['ip'],
  176. 'resultid' => $result_id
  177. ));
  178. $result->data['status'] = 'migrating';
  179. $result->data['taskid'] = $child->obj()->id;
  180. $result->save();
  181. if(isset($input['runNow'])) {
  182. $child->run();
  183. if($child->getStatus() != 'finished') {
  184. AjaxResponse::I()->addError('something_went_wrong_during_migration');
  185. } else {
  186. AjaxResponse::I()->addInfo('zone_migrated');
  187. }
  188. }
  189. }
  190. if(!isset($input['runNow'])) {
  191. AjaxResponse::I()->addInfo('new_task_added');
  192. }
  193. return AjaxResponse::I()->toArray();
  194. //return $this->showListMigrationJSON($input, $vars);
  195. }
  196. public function scheduleMigrationJSON($input, $vars = array()) {
  197. custom\TaskManager::getTaskObjectByID($input['id'])->run();
  198. AjaxResponse::I()->addInfo('migration_scheduled');
  199. AjaxResponse::I()->refreshPage($this->migrationHTML($input, $vars));
  200. return AjaxResponse::I()->toArray();
  201. }
  202. //===========================================================================================================
  203. //===========================================IMPORT==========================================================
  204. //===========================================================================================================
  205. public function importJSON($input, $vars = array()) {
  206. return AjaxResponse::I()->refreshPage($this->importHTML($input, $vars))->toArray();
  207. }
  208. public function getClientsListJSON( $input, $vars = [] )
  209. {
  210. $repo = new main\models\whmcs\clients\repository();
  211. $search = explode(' ', trim($input['q']));
  212. if( count($search) >= 2 )
  213. {
  214. $repo = new main\models\whmcs\clients\repository();
  215. $repo->addAndSearch(['firstname', 'lastname', 'companyname'], [$search[0], $search[1]]);
  216. }
  217. else
  218. {
  219. $repo->search($input['q'], ['id', 'firstname', 'lastname', 'companyname']);
  220. $total = $repo->count();
  221. $repo = new main\models\whmcs\clients\repository();
  222. $repo->search($input['q'], ['id', 'firstname', 'lastname', 'companyname']);
  223. }
  224. $repo->limit(30);
  225. $repo->offset(($input['page'] - 1) * 30);
  226. $items = [];
  227. foreach( $repo->get() as $client )
  228. {
  229. $name = $client->firstname . ' ' . $client->lastname;
  230. $name .= $client->companyname ? ' ( ' . $client->companyname . ' )' : '';
  231. $items[] = [
  232. 'id' => $client->id,
  233. 'name' => $name,
  234. ];
  235. }
  236. AjaxResponse::I()->items = $items;
  237. AjaxResponse::I()->total = $total;
  238. echo json_encode(AjaxResponse::I()->toArray(), JSON_HEX_QUOT | JSON_HEX_TAG);
  239. die();
  240. }
  241. public function importHTML($input, $vars = array())
  242. {
  243. $vars['imports'] = array();
  244. $newImports = custom\TaskManager::getXTasksObjects(0, 'Import:main', 0, task\TaskStatusEnum::START);
  245. $this->parseNewImportTaskList($newImports, $vars['imports']);
  246. $newImportsToFile = custom\TaskManager::getXTasksObjects(0, 'ImportToFile:main', 0, task\TaskStatusEnum::START);
  247. $this->parseNewImportTaskList($newImportsToFile, $vars['imports']);
  248. $imports = custom\TaskManager::getXTasksObjects(0, 'Import:main', 0, task\TaskStatusEnum::IN_PROGRESS);
  249. $this->parseInProgresImportTaskList($imports, $vars['imports']);
  250. $toFileImports = custom\TaskManager::getXTasksObjects(0, 'ImportToFile:main', 0, task\TaskStatusEnum::IN_PROGRESS);
  251. $this->parseInProgresImportTaskList($toFileImports, $vars['imports'], 'ImportToFile');
  252. return array(
  253. 'tpl' => 'import',
  254. 'vars' => $vars
  255. );
  256. }
  257. private function getTaskError($task) {
  258. $erorr = false;
  259. if($task->getStatus() == task\TaskStatusEnum::ERROR) {
  260. $erorr = 'Error';
  261. $results = $task->getResults();
  262. $result = end($results);
  263. if(isset($result->data['error'])) {
  264. $erorr .= ' (' . $result->data['error'] . ')';
  265. }
  266. }
  267. return $erorr;
  268. }
  269. public function showListImportJSON($input, $vars = array())
  270. {
  271. $vars['importid'] = $input['id'];
  272. $autocheckMatches = globalsetting\Repository::factory()->byKey(
  273. globalsetting\GlobalSettingEnum::IMPORT_AUTOCHECK_MATCHES)->one();
  274. $vars['autocheckMatches'] = $autocheckMatches->value == 'on' ? true : false;
  275. AjaxResponse::I()->refreshPage(array('tpl' => 'import-list', 'vars' => $vars));
  276. return AjaxResponse::I()->toArray();
  277. }
  278. function refreshImportTableJSON($input, $vars = array())
  279. {
  280. $pRep = task\Repository::factory()->byParentID($input['id'])->one();
  281. $pRepName = explode(':', $pRep->name);
  282. $task = custom\TaskManager::getXTasks(1, $pRepName[0].':fetchZonesList', $input['id'], false);
  283. $task = end($task);
  284. $rep = task\result\Repository::factory()->byTaskID($task->id);
  285. $helper = new main\mgLibs\custom\RepoTableHelper($rep, $input, array('data'));
  286. $vars = $helper->getDataTableArray();
  287. foreach($helper->get() as $task)
  288. {
  289. $hostingDomainUserId = $this->getUserIdByHostingDomain($task->data['domain']);
  290. $domainUserId = $this->getUserIdByDomain($task->data['domain']);
  291. if( $hostingDomainUserId && $domainUserId )
  292. {
  293. $itemPriority = custom\manager\GlobalSettingHelper::getSetting(globalsetting\GlobalSettingEnum::IMPORT_PRIORITY);
  294. $userid = (int)$itemPriority === 1 ? $hostingDomainUserId : $domainUserId;
  295. }
  296. else
  297. {
  298. $userid = $hostingDomainUserId ?? $domainUserId;
  299. }
  300. $user = false;
  301. if(!empty($userid))
  302. {
  303. $user = new main\models\whmcs\clients\client($userid);
  304. }
  305. $vars['data'][] = $this->dataTablesParseRow('import-row',
  306. array(
  307. 'item' => $task,
  308. 'importid' => $input['id'],
  309. 'user' => $user
  310. )
  311. );
  312. }
  313. return $vars;
  314. }
  315. public function importZonesJSON($input, $vars = array()) {
  316. $add = false;
  317. foreach($input['zone'] as $result_id => $data) {
  318. if($data['import'] != 'on' && !isset($input['justOne']) || empty($data['client']))
  319. continue;
  320. $result = new task\result\TaskResult($result_id);
  321. $task = custom\TaskManager::getTaskObjectByID($result->taskid);
  322. $main_task = $task->getParent(); //TODO: można zmniejszyć ilość danych poprzez odwołanie się do resulta
  323. $ex = explode('::', $data['service']);
  324. $child = $main_task->addChild('import', array(
  325. 'clientid' => $data['client'],
  326. 'domain' =>helpers\IdnaHelper::idnaDecode( $result->data['domain'] ),
  327. 'ip' => $result->data['ip'],
  328. 'resultid' => $result_id,
  329. 'type' => $ex[0],
  330. 'relid' => $ex[1],
  331. ));
  332. $result->data['status'] = 'importing';
  333. $result->data['taskid'] = $child->obj()->id;
  334. $result->save();
  335. if(isset($input['runNow'])) {
  336. $child->run();
  337. if($child->getStatus() != 'finished') {
  338. AjaxResponse::I()->addError('something_went_wrong_during_import');
  339. } else {
  340. AjaxResponse::I()->addInfo('zone_imported');
  341. }
  342. } else {
  343. if($add === false) {
  344. AjaxResponse::I()->addInfo('new_task_added');
  345. $add = true;
  346. }
  347. }
  348. }
  349. return AjaxResponse::I()->toArray();
  350. //return $this->showListImportJSON($input, $vars);
  351. }
  352. public function addImportJSON($input, $vars = array())
  353. {
  354. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
  355. $vars['isWritable'] = $fileManager->isStorageWritable();
  356. $vars['storagePath'] = $fileManager->getStoragePath();
  357. $rep = new server\Repository();
  358. $vars['servers'] = $rep->get();
  359. AjaxResponse::I()->modal('add-import', $vars);
  360. return AjaxResponse::I()->toArray();
  361. }
  362. public function addImportSaveJSON($input, $vars = array())
  363. {
  364. if(!isset($input['from_server']))
  365. {
  366. return ;
  367. }
  368. $server = server\Server::factory($input['from_server']);
  369. $server->getModule()->testConnection();
  370. if($input['toFile'] == 'on')
  371. {
  372. $fileName = helpers\ImportExportFileHelper::generateNewExportFileName($server->name);
  373. custom\TaskManager::addTask('ImportToFile:main', array('from' => $input['from_server'], 'toFile' => $fileName));
  374. }
  375. else
  376. {
  377. custom\TaskManager::addTask('Import:main', array('from' => $input['from_server']));
  378. }
  379. AjaxResponse::I()->refreshPage($this->importHTML($input, $vars));
  380. AjaxResponse::I()->addInfo('new_task_added');
  381. return AjaxResponse::I()->toArray();
  382. }
  383. public function removeImportJSON($input, $vars = array()) {
  384. custom\TaskManager::removeTask($input['id']);
  385. AjaxResponse::I()->refreshPage($this->importHTML($input, $vars));
  386. AjaxResponse::I()->addInfo('import_removed');
  387. return AjaxResponse::I()->toArray();
  388. }
  389. public function scheduleImportJSON($input, $vars = array()) {
  390. custom\TaskManager::getTaskObjectByID($input['id'])->run(true);
  391. AjaxResponse::I()->addInfo('import_scheduled');
  392. AjaxResponse::I()->refreshPage($this->importHTML($input, $vars));
  393. return AjaxResponse::I()->toArray();
  394. }
  395. public function getUserServicesJSON($input, $vars = array()) {
  396. $services = custom\manager\Par::getSortedArray($input['clientid']);
  397. $services[] = array(
  398. 'group_name' => main\mgLibs\lang::T('none'),
  399. 'package_name' => '',
  400. 'type' => 0,
  401. 'relid' => 0,
  402. );
  403. $vars['domain'] = strtolower($input['domain']);
  404. $vars['services'] = $services;
  405. $vars['id'] = $input['itemid'];
  406. AjaxResponse::I()->html = main\mgLibs\smarty::I()->view('user-services', $vars, main\addon::getModuleTemplatesDir().DS.'pages' . DS . 'tools');
  407. session_write_close();
  408. return AjaxResponse::I()->toArray();
  409. }
  410. //===========================================================================================================
  411. //===========================================TASKS===========================================================
  412. //===========================================================================================================
  413. public function tasksHTML($input, $vars = array()) {
  414. return array(
  415. 'tpl' => 'tasks',
  416. 'vars' => $vars
  417. );
  418. }
  419. public function tasksJSON($input, $vars = array()) {
  420. return AjaxResponse::I()->refreshPage($this->tasksHTML($input, $vars))->toArray();
  421. }
  422. public function refreshTasksTableJSON($input, $vars = array()) {
  423. $query = "SELECT dns_manager2_task.id AS id, dns_manager2_task.name AS name, dns_manager2_task.status AS status, dns_manager2_task.lastrun AS lastrun,
  424. dns_manager2_task.nextrun AS nextrun, dns_manager2_task.date AS date
  425. FROM dns_manager2_task
  426. WHERE parentid = 0";
  427. $columns = array('id', 'name', 'status', 'lastrun', 'nextrun', 'date');
  428. $helper = new main\mgLibs\custom\RawQueryTableHelper($query, $input, $columns);
  429. $vars = $helper->getDataTableArray();
  430. $vars['setRecord'] = array();
  431. foreach($helper->get() as $task) {
  432. $obj = custom\TaskManager::getTaskObject(new task\Task($task['id']));
  433. $setRecords = $this->parseInProgresSetRecordList($obj, $vars['setRecord']);
  434. if($task['name'] != 'DnsRecord:main')
  435. {
  436. $setRecords[0] = null;
  437. }
  438. $vars['data'][] = $this->dataTablesParseRow('task-row', array('task' => $task,'setRecord' => $setRecords[0], 'name' => $obj->description()));
  439. }
  440. return $vars;
  441. }
  442. public function taskRunNowJSON($input, $vars = array()) {
  443. custom\TaskManager::getTaskObjectByID($input['id'])->run(true);
  444. return AjaxResponse::I()->addInfo('task_finished')->toArray();
  445. }
  446. public function removeTaskJSON($input, $vars = array()) {
  447. custom\TaskManager::getTaskObjectByID($input['id'])->remove();
  448. return AjaxResponse::I()->addInfo('task_removed')->toArray();
  449. }
  450. public function removeTasksWithErrorsJSON() {
  451. $rep = main\models\custom\task\Repository::factory()->byStatus(main\models\custom\task\TaskStatusEnum::ERROR);
  452. foreach($rep->get() as $task) {
  453. $obj = custom\TaskManager::getTaskObject($task);
  454. $obj->remove();
  455. }
  456. return AjaxResponse::I()->addInfo('success')->toArray();
  457. }
  458. public function getUserIdByHostingDomain($domainName)
  459. {
  460. if(helpers\IdnaHelper::isDomainIdn($domainName))
  461. {
  462. $userid = mysql\query::query("SELECT userid FROM tblhosting WHERE BINARY domain = BINARY :domain OR BINARY domain = BINARY :idnDomain",
  463. array('domain' => $domainName, 'idnDomain' => helpers\IdnaHelper::idnaDecode($domainName))
  464. )->fetchColumn("userid");
  465. }
  466. else
  467. {
  468. $userid = mysql\query::query("SELECT userid FROM tblhosting WHERE BINARY domain = BINARY :domain",
  469. array('domain' => $domainName))->fetchColumn("userid");
  470. }
  471. return $userid;
  472. }
  473. public function getUserIdByDomain($domainName)
  474. {
  475. if(helpers\IdnaHelper::isDomainIdn($domainName))
  476. {
  477. $userid = mysql\query::query("SELECT userid FROM tbldomains WHERE BINARY domain = BINARY :domain OR BINARY domain = BINARY :idnDomain",
  478. array('domain' => $domainName, 'idnDomain' => helpers\IdnaHelper::idnaDecode($domainName))
  479. )->fetchColumn("userid");
  480. }
  481. else
  482. {
  483. $userid = mysql\query::query("SELECT userid FROM tbldomains WHERE BINARY domain = BINARY ?",
  484. array($domainName))->fetchColumn("userid");
  485. }
  486. return $userid;
  487. }
  488. public function parseNewImportTaskList($list, &$vars)
  489. {
  490. foreach($list as $import)
  491. {
  492. $vars[] = array(
  493. 'id' => $import->obj()->id,
  494. 'desc' => $import->description(),
  495. 'parsedDesc' => $this->praseTaskDescription($import->description()),
  496. 'zones_imported' => '-',
  497. 'zones_total' => '-',
  498. 'progress' => -1,
  499. 'type' => $import->getTaskTypeCode()
  500. );
  501. }
  502. }
  503. private function praseTaskDescription($desc)
  504. {
  505. $parts = explode(' from: ', $desc);
  506. $parts[0] .= ' from: ';
  507. $tmpParts = explode(' to: ', $parts[1]);
  508. if(count($tmpParts) > 1)
  509. {
  510. $parts[1] = $tmpParts[0];
  511. $parts[2] = ' to: ';
  512. $parts[3] = $tmpParts[1];
  513. }
  514. return $parts;
  515. }
  516. public function parseInProgresImportTaskList($list, &$vars, $type = 'Import')
  517. {
  518. foreach($list as $import)
  519. {
  520. $rep = new task\Repository();
  521. $childTaskType = strpos($type, 'Export') === 0 ? 'export' : 'import';
  522. $rep->byParentID($import->obj()->id)->byName($type.':'.$childTaskType);
  523. $zones_total = $rep->count();
  524. $rep->byStatus(task\TaskStatusEnum::FINISHED);
  525. $zones_imported = $rep->count();
  526. $task = custom\TaskManager::getXTasksObjects(1, $type.':fetchZonesList', $import->obj()->id, false);
  527. if(end($task))
  528. {
  529. $error = $this->getTaskError(end($task));
  530. }
  531. $vars[] = array(
  532. 'id' => $import->obj()->id,
  533. 'desc' => $import->description(),
  534. 'zones_imported' => $zones_imported,
  535. 'zones_total' => $zones_total,
  536. 'progress' => $zones_total == 0 ? 0 : ceil($zones_imported * 100 / $zones_total),
  537. 'error' => $error,
  538. 'parsedDesc' => $this->praseTaskDescription($import->description()),
  539. 'type' => $import->getTaskTypeCode()//strpos($import->description(), 'Import') === 0 ? 'Import' : 'Export'
  540. );
  541. }
  542. }
  543. public function addExportJSON($input, $vars = array())
  544. {
  545. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
  546. $vars['isReadable'] = $fileManager->isStorageReadable();
  547. $vars['storagePath'] = $fileManager->getStoragePath();
  548. $rep = new server\Repository();
  549. $vars['servers'] = $rep->get();
  550. $filesList = main\mgLibs\custom\helpers\ImportExportFileHelper::listFilesForBulkExport($fileManager);
  551. $vars['bFiles'] = $filesList;
  552. AjaxResponse::I()->modal('add-export', $vars);
  553. return AjaxResponse::I()->toArray();
  554. }
  555. public function addExportSaveJSON($input, $vars = array())
  556. {
  557. if(!isset($input['toServer']))
  558. {
  559. return ;
  560. }
  561. $server = server\Server::factory($input['toServer']);
  562. $server->getModule()->testConnection();
  563. custom\TaskManager::addTask('ExportFromFile:main', array('fromFile' => $input['fromFile'], 'toServer' => $input['toServer']));
  564. AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
  565. AjaxResponse::I()->addInfo('new_task_added');
  566. return AjaxResponse::I()->toArray();
  567. }
  568. public function backupsHTML($input, $vars = array())
  569. {
  570. $vars['backupsTasks'] = array();
  571. $newImportsToFile = custom\TaskManager::getXTasksObjects(0, 'ImportToFileWHMCS:main', 0, task\TaskStatusEnum::START);
  572. $this->parseNewImportTaskList($newImportsToFile, $vars['backupsTasks']);
  573. $toFileImports = custom\TaskManager::getXTasksObjects(0, 'ImportToFileWHMCS:main', 0, task\TaskStatusEnum::IN_PROGRESS);
  574. $this->parseInProgresImportTaskList($toFileImports, $vars['backupsTasks'], 'ImportToFileWHMCS');
  575. $newImportsToFile = custom\TaskManager::getXTasksObjects(0, 'ExportFromFile:main', 0, task\TaskStatusEnum::START);
  576. $this->parseNewImportTaskList($newImportsToFile, $vars['backupsTasks']);
  577. $toFileImports = custom\TaskManager::getXTasksObjects(0, 'ExportFromFile:main', 0, task\TaskStatusEnum::IN_PROGRESS);
  578. $this->parseInProgresImportTaskList($toFileImports, $vars['backupsTasks'], 'ExportFromFile');
  579. return array(
  580. 'tpl' => 'backups',
  581. 'vars' => $vars
  582. );
  583. }
  584. public function backupsJSON($input, $vars = array())
  585. {
  586. return AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars))->toArray();
  587. }
  588. public function downloandBackupFileJSON($input, $vars = array())
  589. {
  590. $type = $input['type'];
  591. $fileName = $input['id'];
  592. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.$type.'Zones');
  593. if(!$fileManager->fileExists($fileName))
  594. {
  595. AjaxResponse::I()-> addError('fileDoesNotExist', array('file' => $fileName));
  596. return AjaxResponse::I()->toArray();
  597. }
  598. $filePatch = $fileManager->getStoragePath().$fileName;
  599. $url = html_entity_decode(str_replace('mg-action=backups', 'mg-action=downloandBackupFile', $_SERVER['HTTP_REFERER']));
  600. return array('seturlto' => $url.'&path='.$filePatch);
  601. }
  602. public function downloandBackupFileHTML($input, $vars = array())
  603. {
  604. $filePatch = $_GET['path'];
  605. if(!strpos($filePatch, 'DNSManager2'.DIRECTORY_SEPARATOR.'storage'.DIRECTORY_SEPARATOR.'zonesFilesStorage'))
  606. {
  607. $filePatch = false;
  608. }
  609. ob_clean();
  610. header('Content-Description: File Transfer');
  611. header('Content-Type: application/octet-stream');
  612. header('Content-Disposition: attachment; filename="'.basename($filePatch).'"');
  613. header('Expires: 0');
  614. header('Cache-Control: must-revalidate');
  615. header('Pragma: public');
  616. header('Content-Length: '.filesize($filePatch));
  617. readfile($filePatch);
  618. die();
  619. }
  620. public function removeBackupFileJSON($input, $vars = array())
  621. {
  622. $type = $input['type'];
  623. $fileName = $input['id'];
  624. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.$type.'Zones');
  625. if(!$fileManager->fileExists($fileName))
  626. {
  627. AjaxResponse::I()-> addError('fileDoesNotExist', array('file' => $fileName));
  628. return AjaxResponse::I()->toArray();
  629. }
  630. if($fileManager->deleteFile($fileName))
  631. {
  632. $clientId = explode('_', $fileName)[0];
  633. main\helpers\custom\ClientFilesManage::delete($clientId, $fileName);
  634. AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
  635. AjaxResponse::I()->addInfo('fileRemoved');
  636. return AjaxResponse::I()->toArray();
  637. }
  638. AjaxResponse::I()-> addError('fileDeleteFailed', array('file' => $fileName));
  639. return AjaxResponse::I()->toArray();
  640. }
  641. public function addBackupFileJSON($input, $vars = array())
  642. {
  643. AjaxResponse::I()->modal('add-backupFile', $vars);
  644. return AjaxResponse::I()->toArray();
  645. }
  646. public function uploadBackupFileJSON($input, $vars = array())
  647. {
  648. $fileName = main\mgLibs\custom\FileManager::removeFakePath($input['fileName']);
  649. if(!main\mgLibs\custom\FileManager::checkIfFileWasSent($fileName))
  650. {
  651. AjaxResponse::I()-> addError('sendingFailed', array('file' => $fileName));
  652. return AjaxResponse::I()->toArray();
  653. }
  654. $type = main\mgLibs\custom\FileManager::checkTypeByContent($fileName);
  655. if($type !== 'single' && $type !== 'bulk')
  656. {
  657. AjaxResponse::I()->addError('invalidContent', array('file' => $fileName));
  658. return AjaxResponse::I()->toArray();
  659. }
  660. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.$type.'Zones');
  661. if(!$fileManager->isStorageReadable() || !$fileManager->isStorageWritable())
  662. {
  663. AjaxResponse::I()-> addError('directoryPermissionWritableReadable', array('storageDir' => $fileManager->getStoragePath()));
  664. return AjaxResponse::I()->toArray();
  665. }
  666. if($fileManager->fileExists($fileName))
  667. {
  668. AjaxResponse::I()-> addError('fileAlreadyExist', array('file' => $fileName));
  669. return AjaxResponse::I()->toArray();
  670. }
  671. if($fileManager->uploadFile($fileName))
  672. {
  673. AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
  674. AjaxResponse::I()->addInfo('uploadSuccesfull');
  675. return AjaxResponse::I()->toArray();
  676. }
  677. if(!main\mgLibs\custom\FileManager::checkIfFileWasSent($fileName))
  678. {
  679. AjaxResponse::I()-> addError('sendingFailed', array('file' => $fileName));
  680. return AjaxResponse::I()->toArray();
  681. }
  682. }
  683. public function refreshBackupsTableJSON($input, $vars = array())
  684. {
  685. $vars['data'] = array();
  686. $vars['recordsTotal'] = 0;
  687. $vars['recordsFiltered'] = 0;
  688. $limit = $input['limit'];
  689. $offset = $input['offset'];
  690. $order = $input['order']['dir'] == 'desc' ? 1 : 0;
  691. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
  692. $filesList = main\mgLibs\custom\helpers\ImportExportFileHelper::listFilesForBulkExport($fileManager, false, $order);
  693. foreach($filesList as $fileName)
  694. {
  695. $fileRecord = clientfiles\Repository::factory()->byFile($fileName)->one();
  696. $client = !$fileRecord ? '-' : custom\manager\ClientHelper::getClientLink($fileRecord->clientid);
  697. $fileNameDisplay = $fileName;
  698. $result = explode('_', $fileNameDisplay);
  699. if($client != '-')
  700. {
  701. unset($result[count($result) -1]);
  702. }
  703. $fileNameDisplay = implode("_", $result);
  704. $vars['recordsTotal']++;
  705. if($input['search'] && $this->isFilenameMatch($fileName, $input['search']))
  706. {
  707. $vars['data'][] = $this->dataTablesParseRow('backup-row', array(
  708. 'fileName' => $fileName,
  709. 'fileNameDisplay' => $fileNameDisplay,
  710. 'client' => $client,
  711. 'type' => 'bulk'
  712. ));
  713. $vars['recordsFiltered']++;
  714. }
  715. elseif(!$input['search'])
  716. {
  717. $vars['data'][] = $this->dataTablesParseRow('backup-row', array(
  718. 'fileName' => $fileName,
  719. 'fileNameDisplay' => $fileNameDisplay,
  720. 'client' => $client,
  721. 'type' => 'bulk'
  722. ));
  723. }
  724. }
  725. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'singleZones');
  726. $filesList = main\mgLibs\custom\helpers\ImportExportFileHelper::listFilesForBulkExport($fileManager);
  727. foreach($filesList as $fileName)
  728. {
  729. $vars['recordsTotal']++;
  730. if($input['search'] && $this->isFilenameMatch($fileName, $input['search']))
  731. {
  732. $vars['data'][] = $this->dataTablesParseRow('backup-row', array('fileName' => $fileName, 'client' => '-','type' => 'single'));
  733. $vars['recordsFiltered']++;
  734. }
  735. elseif(!$input['search'])
  736. {
  737. $vars['data'][] = $this->dataTablesParseRow('backup-row', array('fileName' => $fileName, 'client' => '-', 'type' => 'single'));
  738. }
  739. }
  740. $vars['recordsFiltered'] = $input['search'] ? $vars['recordsFiltered'] : $vars['recordsTotal'];
  741. $vars['data'] = array_slice($vars['data'], $offset, $limit);
  742. return $vars;
  743. }
  744. private function isFilenameMatch($fileName, $search)
  745. {
  746. if(strpos($fileName, $search) || strpos($fileName, $search) === 0)
  747. {
  748. return true;
  749. }
  750. return false;
  751. }
  752. public function addExportToFIleJSON($input, $vars = array())
  753. {
  754. $fileManager = new main\mgLibs\custom\FileManager('zonesFilesStorage'.DIRECTORY_SEPARATOR.'bulkZones');
  755. $vars['isWritable'] = $fileManager->isStorageWritable();
  756. $vars['storagePath'] = $fileManager->getStoragePath();
  757. $rep = new server\Repository();
  758. $vars['servers'] = $rep->get();
  759. AjaxResponse::I()->modal('add-exportToFile', $vars);
  760. return AjaxResponse::I()->toArray();
  761. }
  762. public function addExportToFileSaveJSON($input, $vars = array())
  763. {
  764. if(!isset($input['from_server']))
  765. {
  766. return ;
  767. }
  768. $server = server\Server::factory($input['from_server']);
  769. $server->getModule()->testConnection();
  770. $fileName = helpers\ImportExportFileHelper::generateNewExportFileName($server->name);
  771. custom\TaskManager::addTask('ImportToFile:main', array('from' => $input['from_server'], 'toFile' => $fileName));
  772. AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
  773. AjaxResponse::I()->addInfo('new_task_added');
  774. return AjaxResponse::I()->toArray();
  775. }
  776. public function backupScheduleImportJSON($input, $vars = array())
  777. {
  778. custom\TaskManager::getTaskObjectByID($input['id'])->run(true);
  779. AjaxResponse::I()->addInfo('import_scheduled');
  780. AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
  781. return AjaxResponse::I()->toArray();
  782. }
  783. public function backupScheduleExportJSON($input, $vars = array())
  784. {
  785. custom\TaskManager::getTaskObjectByID($input['id'])->run(true);
  786. AjaxResponse::I()->addInfo('exportScheduled');
  787. AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
  788. return AjaxResponse::I()->toArray();
  789. }
  790. public function backupRemoveTaskJSON($input, $vars = array())
  791. {
  792. custom\TaskManager::removeTask($input['id']);
  793. AjaxResponse::I()->refreshPage($this->backupsHTML($input, $vars));
  794. AjaxResponse::I()->addInfo('taskRemoved');
  795. return AjaxResponse::I()->toArray();
  796. }
  797. public function showListExportJSON($input, $vars = array())
  798. {
  799. $vars['exportId'] = $input['id'];
  800. $autocheckMatches = globalsetting\Repository::factory()->byKey(
  801. globalsetting\GlobalSettingEnum::IMPORT_AUTOCHECK_MATCHES)->one();
  802. $vars['autocheckMatches'] = $autocheckMatches->value == 'on' ? true : false;
  803. AjaxResponse::I()->refreshPage(array('tpl' => 'export-list', 'vars' => $vars));
  804. return AjaxResponse::I()->toArray();
  805. }
  806. function refreshExportTableJSON($input, $vars = array())
  807. {
  808. $pRep = task\Repository::factory()->byParentID($input['id'])->one();
  809. $pRepName = explode(':', $pRep->name);
  810. $task = custom\TaskManager::getXTasks(1, $pRepName[0].':fetchZonesList', $input['id'], false);
  811. $task = end($task);
  812. $rep = task\result\Repository::factory()->byTaskID($task->id);
  813. $helper = new main\mgLibs\custom\RepoTableHelper($rep, $input, array('data'));
  814. $vars = $helper->getDataTableArray();
  815. foreach($helper->get() as $task)
  816. {
  817. $userid = $this->getUserIdByHostingDomain($task->data['domain']);
  818. if(empty($userid))
  819. {
  820. $userid = $this->getUserIdByDomain($task->data['domain']);
  821. }
  822. $user = false;
  823. if(!empty($userid))
  824. {
  825. $user = new main\models\whmcs\clients\client($userid);
  826. }
  827. $vars['data'][] = $this->dataTablesParseRow('export-row',
  828. array(
  829. 'item' => $task,
  830. 'exportId' => $input['id'],
  831. 'user' => $user
  832. )
  833. );
  834. }
  835. return $vars;
  836. }
  837. public function showListImportToFileJSON($input, $vars = array())
  838. {
  839. $vars['importid'] = $input['id'];
  840. $autocheckMatches = globalsetting\Repository::factory()->byKey(
  841. globalsetting\GlobalSettingEnum::IMPORT_AUTOCHECK_MATCHES)->one();
  842. $vars['autocheckMatches'] = $autocheckMatches->value == 'on' ? true : false;
  843. AjaxResponse::I()->refreshPage(array('tpl' => 'import-list-to-file', 'vars' => $vars));
  844. return AjaxResponse::I()->toArray();
  845. }
  846. public function backupImportZonesJSON($input, $vars = array())
  847. {
  848. $add = false;
  849. foreach($input['zone'] as $resultId => $data)
  850. {
  851. if($data['import'] != 'on' && !isset($input['justOne']))
  852. {
  853. continue;
  854. }
  855. $result = new task\result\TaskResult($resultId);
  856. $task = custom\TaskManager::getTaskObjectByID($result->taskid);
  857. $main_task = $task->getParent();
  858. $ex = explode('::', $data['service']);
  859. $child = $main_task->addChild('import', array(
  860. 'clientid' => $data['client'],
  861. 'domain' => $result->data['domain'],
  862. 'ip' => $result->data['ip'],
  863. 'resultid' => $resultId,
  864. 'type' => $ex[0],
  865. 'relid' => $ex[1],
  866. ));
  867. $result->data['status'] = 'importing';
  868. $result->data['taskid'] = $child->obj()->id;
  869. $result->save();
  870. if(isset($input['runNow']))
  871. {
  872. $child->run();
  873. if($child->getStatus() !== 'finished')
  874. {
  875. AjaxResponse::I()->addError('something_went_wrong_during_import');
  876. }
  877. else
  878. {
  879. AjaxResponse::I()->addInfo('zone_imported');
  880. }
  881. }
  882. else
  883. {
  884. if($add === false)
  885. {
  886. AjaxResponse::I()->addInfo('new_task_added');
  887. $add = true;
  888. }
  889. }
  890. }
  891. return AjaxResponse::I()->toArray();
  892. }
  893. public function exportZonesJSON($input, $vars = array())
  894. {
  895. $add = false;
  896. foreach($input['zone'] as $result_id => $data)
  897. {
  898. if($data['export'] != 'on' && !isset($input['justOne']))
  899. {
  900. continue;
  901. }
  902. $result = new task\result\TaskResult($result_id);
  903. $task = custom\TaskManager::getTaskObjectByID($result->taskid);
  904. $main_task = $task->getParent(); //TODO: można zmniejszyć ilość danych poprzez odwołanie się do resulta
  905. $ex = explode('::', $data['service']);
  906. $child = $main_task->addChild('export', array(
  907. 'clientid' => $data['client'],
  908. 'domain' => $result->data['domain'],
  909. 'ip' => $result->data['ip'],
  910. 'resultid' => $result_id,
  911. 'type' => $ex[0],
  912. 'relid' => $ex[1],
  913. ));
  914. $result->data['status'] = 'exporting';
  915. $result->data['taskid'] = $child->obj()->id;
  916. $result->save();
  917. if(isset($input['runNow']))
  918. {
  919. $child->run();
  920. if($child->getStatus() !== 'finished')
  921. {
  922. AjaxResponse::I()->addError('something_went_wrong_during_import');
  923. }
  924. else
  925. {
  926. AjaxResponse::I()->addInfo('zone_imported');
  927. }
  928. }
  929. else
  930. {
  931. if($add === false)
  932. {
  933. AjaxResponse::I()->addInfo('new_task_added');
  934. $add = true;
  935. }
  936. }
  937. }
  938. return AjaxResponse::I()->toArray();
  939. }
  940. public function parseInProgresSetRecordList($record, $vars, $type = 'DnsRecord')
  941. {
  942. $rep = new task\Repository();
  943. $rep->byParentID($record->obj()->id)->byName($type.':changeRecordSet');
  944. $tasks_total = $rep->count();
  945. $rep->byStatus(task\TaskStatusEnum::FINISHED);
  946. $tasks_done = $rep->count();
  947. $task = custom\TaskManager::getXTasksObjects(1, $type.':changeRecordSet', $record->obj()->id, false);
  948. if(end($task))
  949. {
  950. $error = $this->getTaskError(end($task));
  951. }
  952. $vars[] = array(
  953. 'id' => $record->obj()->id,
  954. 'tasks_done' => $tasks_done,
  955. 'tasks_total' => $tasks_total,
  956. 'progress' => $tasks_total == 0 ? 0 : ceil($tasks_done * 100 / $tasks_total),
  957. 'error' => $error,
  958. );
  959. return $vars;
  960. }
  961. }