api.reportmaster.php 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. <?php
  2. /**
  3. * Custom user reports builder implementation
  4. */
  5. class ReportMaster {
  6. /**
  7. * Contains message helper instance
  8. *
  9. * @var object
  10. */
  11. protected $messages = '';
  12. /**
  13. * Contains all available reports as reportId=>reportData
  14. *
  15. * @var array
  16. */
  17. protected $allReports = array();
  18. /**
  19. * Contains current instance administrator login
  20. *
  21. * @var string
  22. */
  23. protected $myLogin = '';
  24. /**
  25. * Contains default wildcard expression for icons available for reportmaster.
  26. * Like rm* or something like that. May be configurable in future.
  27. *
  28. * @var string
  29. */
  30. protected $iconsPrefix = '';
  31. /**
  32. * Some predefined paths, URLs/routes etc...
  33. */
  34. const PATH_REPORTS = 'content/reports/';
  35. const URL_ME = '?module=reportmaster';
  36. const URL_TASKBAR = '?module=taskbar';
  37. const URL_USERPROFILE = '?module=userprofile&username=';
  38. const ROUTE_ADD = 'add';
  39. const ROUTE_EDIT = 'edit';
  40. const ROUTE_VIEW = 'view';
  41. const ROUTE_DELETE = 'delete';
  42. const ROUTE_RENDERER = 'renderer';
  43. const ROUTE_BASEEXPORT = 'exportuserbase';
  44. const PROUTE_INSTALL = 'installreportcode';
  45. const PROUTE_NEWTYPE = 'newreporttype';
  46. const PROUTE_NEWNAME = 'newreportname';
  47. const PROUTE_NEWQUERY = 'newquery';
  48. const PROUTE_NEWKEYS = 'newdatakeys';
  49. const PROUTE_NEWFIELDS = 'newfieldnames';
  50. const PROUTE_NEWADDR = 'newaddr';
  51. const PROUTE_NEWRNAMES = 'newrnames';
  52. const PROUTE_NEWROWCOUNT = 'newrowcount';
  53. const PROUTE_EDTYPE = 'editreporttype';
  54. const PROUTE_EDNAME = 'editreportname';
  55. const PROUTE_EDQUERY = 'editquery';
  56. const PROUTE_EDKEYS = 'editdatakeys';
  57. const PROUTE_EDFIELDS = 'editfieldnames';
  58. const PROUTE_EDADDR = 'editaddr';
  59. const PROUTE_EDRNAMES = 'editrnames';
  60. const PROUTE_EDROWCOUNT = 'editrowcount';
  61. const PROUTE_EDADMACL = 'editadminsacl';
  62. const PROUTE_EDONTB = 'editontb';
  63. const PROUTE_EDAOTD = 'editaotd';
  64. const PROUTE_EDICON = 'editicon';
  65. const MOD_PRINT = 'printable';
  66. const MOD_CSV = 'csv';
  67. const ICON_DEFAULT = 'goat.gif';
  68. const ICONS_PATH = 'skins/taskbar/';
  69. /**
  70. * Creates new ReportMaster instance
  71. */
  72. public function __construct() {
  73. // All this time I've been waiting
  74. // For someone or something to guide me
  75. // All this time I've been searching
  76. // For truth in my heart
  77. $this->initMessages();
  78. $this->setLogin();
  79. $this->loadReports();
  80. }
  81. /**
  82. * Inits message helper instance for further usage
  83. *
  84. * @return void
  85. */
  86. protected function initMessages() {
  87. $this->messages = new UbillingMessageHelper();
  88. }
  89. /**
  90. * Sets admin login for current instance. Required for per/report rights check
  91. *
  92. * @return void
  93. */
  94. protected function setLogin() {
  95. $this->myLogin = whoami();
  96. }
  97. /**
  98. * Returns array of existing reports as reportId=>reportData
  99. *
  100. * @return string
  101. */
  102. public function getReports() {
  103. return ($this->allReports);
  104. }
  105. /**
  106. * Checks have current user access for some report
  107. *
  108. * @param string $reportId
  109. *
  110. * @return bool
  111. */
  112. public function isMeAllowed($reportId) {
  113. $result = true;
  114. //root administrators have access for all reports by default
  115. if (!cfr('ROOT')) {
  116. $result = false;
  117. if (isset($this->allReports[$reportId])) {
  118. if (!empty($this->allReports[$reportId]['REPORT_ALLOWADMINS'])) {
  119. $admAcl = explode(',', $this->allReports[$reportId]['REPORT_ALLOWADMINS']);
  120. $admAcl = array_flip($admAcl);
  121. if (isset($admAcl[$this->myLogin])) {
  122. //i`m listed there?
  123. $result = true;
  124. }
  125. } else {
  126. //empty admins ACL means access for all
  127. $result = true;
  128. }
  129. } else {
  130. //no access for reports which not exists, lol.
  131. $result = false;
  132. }
  133. }
  134. return ($result);
  135. }
  136. /**
  137. * Loads all available reports from filesystem
  138. *
  139. * @return void
  140. */
  141. protected function loadReports() {
  142. $allReports = rcms_scandir(self::PATH_REPORTS);
  143. if (!empty($allReports)) {
  144. foreach ($allReports as $eachReport) {
  145. $reportData = rcms_parse_ini_file(self::PATH_REPORTS . $eachReport);
  146. //legacy reports is SQL by default
  147. if (!isset($reportData['REPORT_TYPE'])) {
  148. $reportData['REPORT_TYPE'] = 'SQL';
  149. }
  150. //legacy reports allowed for all by default
  151. if (!isset($reportData['REPORT_ALLOWADMINS'])) {
  152. $reportData['REPORT_ALLOWADMINS'] = '';
  153. }
  154. //on TB and icon options disabled by default
  155. if (!isset($reportData['REPORT_ONTB'])) {
  156. $reportData['REPORT_ONTB'] = 0;
  157. }
  158. if (!isset($reportData['REPORT_ICON'])) {
  159. $reportData['REPORT_ICON'] = '';
  160. }
  161. //advice of the day is disabled by default
  162. if (!isset($reportData['REPORT_AOTD'])) {
  163. $reportData['REPORT_AOTD'] = 0;
  164. }
  165. $this->allReports[$eachReport] = $reportData;
  166. }
  167. }
  168. }
  169. /**
  170. * Renders available reports list
  171. *
  172. * @return string
  173. */
  174. public function renderReportsList() {
  175. $result = '';
  176. if (!empty($this->allReports)) {
  177. $cells = wf_TableCell(__('Report name'));
  178. if (cfr('REPORTMASTERADM')) {
  179. $cells .= wf_TableCell(__('Actions'));
  180. }
  181. $rows = wf_TableRow($cells, 'row1');
  182. foreach ($this->allReports as $eachReport => $reportData) {
  183. if ($this->isMeAllowed($eachReport)) {
  184. $cells = wf_TableCell(wf_Link(self::URL_ME . '&' . self::ROUTE_VIEW . '=' . $eachReport, __($reportData['REPORT_NAME'])));
  185. if (cfr('REPORTMASTERADM')) {
  186. $actControls = '';
  187. if (empty($reportData['REPORT_ALLOWADMINS'])) {
  188. $reportAccessLabel = wf_img('skins/icon_unlock.png', __('Access for all')) . ' ';
  189. } else {
  190. $reportAccessLabel = wf_img('skins/icon_key.gif', __('Access restricted')) . ' ';
  191. }
  192. if (empty($reportData['REPORT_ONTB'])) {
  193. $reportTblabel = wf_img('skins/icon_hidden.png', __('Taskbar') . ': ' . __('Hidden')) . ' ';;
  194. } else {
  195. $reportTblabel = wf_img('skins/icon_visible.png', __('Taskbar') . ': ' . __('Visible')) . ' ';;
  196. }
  197. $actControls .= $reportTblabel;
  198. $actControls .= $reportAccessLabel;
  199. $actControls .= wf_JSAlert(self::URL_ME . '&' . self::ROUTE_DELETE . '=' . $eachReport, web_delete_icon(), $this->messages->getDeleteAlert()) . ' ';
  200. $actControls .= wf_JSAlert(self::URL_ME . '&' . self::ROUTE_EDIT . '=' . $eachReport, web_edit_icon(), $this->messages->getEditAlert()) . ' ';
  201. $cells .= wf_TableCell($actControls);
  202. }
  203. $rows .= wf_TableRow($cells, 'row5');
  204. }
  205. }
  206. $result .= wf_TableBody($rows, '100%', 0, 'sortable');
  207. } else {
  208. $result .= $this->messages->getStyledMessage(__('Nothing to show'), 'warning');
  209. }
  210. return ($result);
  211. }
  212. /**
  213. * Exports existing userbase as CSV format
  214. *
  215. * @return void
  216. */
  217. public function exportUserbaseCsv() {
  218. $result = '';
  219. $allusers = zb_UserGetAllStargazerData();
  220. $allrealnames = zb_UserGetAllRealnames();
  221. $alladdress = zb_AddressGetFulladdresslist();
  222. $allcontracts = zb_UserGetAllContracts();
  223. $allmac = zb_UserGetAllIpMACs();
  224. $delimiter = ';';
  225. $curDate = curdatetime();
  226. $headers = array(
  227. __('Login'),
  228. __('Password'),
  229. __('IP'),
  230. __('MAC'),
  231. __('Tariff'),
  232. __('Cash'),
  233. __('Credit'),
  234. __('Credit expire'),
  235. __('Address'),
  236. __('Real Name'),
  237. __('Contract'),
  238. __('AlwaysOnline'),
  239. __('Disabled'),
  240. __('User passive')
  241. );
  242. if (!empty($allusers)) {
  243. $result .= implode($delimiter, $headers) . PHP_EOL;
  244. foreach ($allusers as $io => $eachuser) {
  245. $creditexpire = '';
  246. $usermac = '';
  247. //credit expirity
  248. if ($eachuser['CreditExpire'] != 0) {
  249. $creditexpire = date("Y-m-d", $eachuser['CreditExpire']);
  250. }
  251. //user mac
  252. if (isset($allmac[$eachuser['IP']])) {
  253. $usermac = $allmac[$eachuser['IP']];
  254. }
  255. $rowData = array(
  256. $eachuser['login'],
  257. $eachuser['Password'],
  258. $eachuser['IP'],
  259. $usermac,
  260. $eachuser['Tariff'],
  261. $eachuser['Cash'],
  262. $eachuser['Credit'],
  263. $creditexpire,
  264. @$alladdress[$eachuser['login']],
  265. @$allrealnames[$eachuser['login']],
  266. @$allcontracts[$eachuser['login']],
  267. $eachuser['AlwaysOnline'],
  268. $eachuser['Down'],
  269. $eachuser['Passive']
  270. );
  271. $result .= implode($delimiter, $rowData) . PHP_EOL;
  272. }
  273. log_register('DOWNLOAD FILE `userbase_' . $curDate . '.csv`');
  274. // push data for csv handler
  275. header('Content-type: application/ms-excel');
  276. header('Content-Disposition: attachment; filename=userbase_' . $curDate . '.csv');
  277. print($result);
  278. die();
  279. }
  280. }
  281. /**
  282. * Renders default back control
  283. *
  284. * @return string
  285. */
  286. public function renderBackControl() {
  287. $result = '';
  288. $backUrl = self::URL_ME;
  289. if (ubRouting::get('back') == 'tb') {
  290. $backUrl = self::URL_TASKBAR;
  291. }
  292. $result .= wf_BackLink($backUrl);
  293. return ($result);
  294. }
  295. /**
  296. * Creates new report template file.
  297. *
  298. * @param string $type report template type: SQL or ONEPUNCH
  299. * @param string $name report name
  300. * @param string $query SQL query for SQL-type reports or existing one-punch script alias for ONEPUNCH
  301. * @param string $keys field keys to use in SQL report
  302. * @param string $fields field names to associate with keys in SQL report
  303. * @param int $addr address rendering by login field flag
  304. * @param int $rn realname rendering by login field flag
  305. * @param int $rowcount result rows count rendering flag
  306. *
  307. * @return void
  308. */
  309. public function createReport($type, $name, $query, $keys = '', $fields = '', $addr = 0, $rn = 0, $rowcount = 0) {
  310. $fileName = 'rm' . time();
  311. $pathToSave = self::PATH_REPORTS . $fileName;
  312. $isOk = false;
  313. if (!empty($type) and ! empty($name) and ! empty($query)) {
  314. //base params here?
  315. $isOk = true;
  316. }
  317. $reportBody = '';
  318. $reportBody .= 'REPORT_NAME="' . $name . '"' . PHP_EOL;
  319. $reportBody .= 'REPORT_TYPE="' . $type . '"' . PHP_EOL;
  320. $reportBody .= 'REPORT_ALLOWADMINS=""' . PHP_EOL; //allows all by default
  321. $reportBody .= 'REPORT_QUERY="' . $query . '"' . PHP_EOL;
  322. $reportBody .= 'REPORT_ONTB="0"' . PHP_EOL;
  323. $reportBody .= 'REPORT_AOTD="0"' . PHP_EOL;
  324. $reportBody .= 'REPORT_ICON=""' . PHP_EOL;
  325. if ($type == 'SQL') {
  326. $reportBody .= 'REPORT_KEYS="' . $keys . '"' . PHP_EOL;
  327. $reportBody .= 'REPORT_FIELD_NAMES="' . $fields . '"' . PHP_EOL;
  328. $reportBody .= 'REPORT_ADDR="' . $addr . '"' . PHP_EOL;
  329. $reportBody .= 'REPORT_RNAMES="' . $rn . '"' . PHP_EOL;
  330. $reportBody .= 'REPORT_ROW_COUNT="' . $rowcount . '"' . PHP_EOL;
  331. }
  332. if ($type == 'onepunch') {
  333. //script exists?
  334. $onePunch = new OnePunch($query);
  335. $scriptCode = $onePunch->getScriptContent($query);
  336. if (!empty($scriptCode)) {
  337. $isOk = true;
  338. } else {
  339. $isOk = false;
  340. }
  341. }
  342. if ($isOk) {
  343. file_put_contents($pathToSave, $reportBody);
  344. log_register('REPORTMASTER CREATE ' . $type . ' REPORT `' . $fileName . '`');
  345. } else {
  346. log_register('REPORTMASTER CREATE FAIL ' . $type . ' REPORT `' . $fileName . '`');
  347. }
  348. }
  349. /**
  350. * Renders new report creation form
  351. *
  352. * @return string
  353. */
  354. public function renderCreateForm($type = 'sql') {
  355. $result = '';
  356. $sup = wf_tag('sup') . '*' . wf_tag('sup', true);
  357. $result .= wf_Link(self::URL_ME . '&' . self::ROUTE_ADD . '=sql', wf_img('skins/icon_restoredb.png') . ' ' . __('SQL Query'), false, 'ubButton') . ' ';
  358. $result .= wf_Link(self::URL_ME . '&' . self::ROUTE_ADD . '=onepunch', wf_img('skins/icon_php.png') . ' ' . __('One-Punch') . ' ' . __('Script'), false, 'ubButton') . ' ';
  359. $result .= wf_Link(self::URL_ME . '&' . self::ROUTE_ADD . '=install', wf_img('skins/icon_clone.png') . ' ' . __('Install third party report'), false, 'ubButton') . ' ';
  360. $result .= wf_delimiter(1);
  361. $inputs = '';
  362. if ($type == 'sql') {
  363. $inputs .= wf_HiddenInput(self::PROUTE_NEWTYPE, 'SQL');
  364. $inputs .= wf_TextInput(self::PROUTE_NEWNAME, __('Report name') . $sup, '', true, 40);
  365. $inputs .= wf_TextInput(self::PROUTE_NEWQUERY, __('SQL Query') . $sup, '', true, 60);
  366. $inputs .= wf_TextInput(self::PROUTE_NEWKEYS, __('Data keys, separated by comma') . $sup, '', true, 40);
  367. $inputs .= wf_TextInput(self::PROUTE_NEWFIELDS, __('Field names, separated by comma') . $sup, '', true, 40);
  368. $inputs .= web_TriggerSelector(self::PROUTE_NEWADDR) . ' ' . __('Show full address by login key') . wf_tag('br');
  369. $inputs .= web_TriggerSelector(self::PROUTE_NEWRNAMES) . ' ' . __('Show Real Names by login key') . wf_tag('br');
  370. $inputs .= web_TriggerSelector(self::PROUTE_NEWROWCOUNT) . ' ' . __('Show data query row count') . wf_tag('br');
  371. }
  372. if ($type == 'onepunch') {
  373. $aliasSelector = array();
  374. $onePunch = new OnePunch();
  375. $allScripts = $onePunch->getAllScripts();
  376. if (!empty($allScripts)) {
  377. foreach ($allScripts as $io => $eachScript) {
  378. $aliasSelector[$eachScript['alias']] = $eachScript['name'];
  379. }
  380. }
  381. $inputs .= wf_HiddenInput(self::PROUTE_NEWTYPE, 'ONEPUNCH');
  382. $inputs .= wf_TextInput(self::PROUTE_NEWNAME, __('Report name') . $sup, '', true, 40);
  383. $inputs .= wf_Selector(self::PROUTE_NEWQUERY, $aliasSelector, __('One-Punch') . ' ' . __('script') . $sup, '', true);
  384. }
  385. if ($type == 'install') {
  386. $inputs .= __('Paste third party report code here. Be careful, it may be dangerous.') . wf_tag('br');
  387. $inputs .= wf_TextArea(self::PROUTE_INSTALL, '', '', true, '80x25');
  388. }
  389. $inputs .= wf_delimiter(0);
  390. $inputs .= wf_Submit(__('Create'));
  391. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  392. return ($result);
  393. }
  394. /**
  395. * Deletes existing report by its name
  396. *
  397. * @param string $reportname
  398. *
  399. * @return void
  400. */
  401. public function deleteReport($reportname) {
  402. unlink(self::PATH_REPORTS . $reportname);
  403. log_register('REPORTMASTER DELETE REPORT `' . $reportname . '`');
  404. }
  405. /**
  406. * Renders some SQL report into viewport
  407. *
  408. * @param string $reportfile
  409. * @param string $report_name
  410. * @param array $titles
  411. * @param array $keys
  412. * @param array $alldata
  413. * @param bool $address
  414. * @param bool $realnames
  415. * @param bool $rowcount
  416. *
  417. * @return void
  418. */
  419. protected function showSqlReport($reportfile, $report_name, $titles, $keys, $alldata, $address = 0, $realnames = 0, $rowcount = 0) {
  420. $report_name = __($report_name) . ' ';
  421. $urlPrint = self::URL_ME . '&' . self::ROUTE_VIEW . '=' . $reportfile . '&' . self::ROUTE_RENDERER . '=' . self::MOD_PRINT;
  422. $urlCsv = self::URL_ME . '&' . self::ROUTE_VIEW . '=' . $reportfile . '&' . self::ROUTE_RENDERER . '=' . self::MOD_CSV;
  423. $report_name .= wf_Link($urlPrint, web_icon_print(), false, '', 'target="_BLANK"') . ' ';
  424. $report_name .= wf_Link($urlCsv, wf_img('skins/excel.gif', __('Export') . ' CSV'), false) . ' ';
  425. $result = $this->getReportData($reportfile, $report_name, $titles, $keys, $alldata, $address, $realnames, $rowcount);
  426. $result .= wf_delimiter(1);
  427. $result .= $this->renderBackControl();
  428. show_window($report_name, $result);
  429. }
  430. /**
  431. * Renders report as CSV file to download
  432. *
  433. * @param string $reportfile
  434. * @param string $report_name
  435. * @param array $titles
  436. * @param array $keys
  437. * @param array $alldata
  438. * @param bool $address
  439. * @param bool $realnames
  440. * @param bool $rowcount
  441. *
  442. * @return void
  443. */
  444. protected function exportSqlToCSV($reportfile, $report_name, $titles, $keys, $alldata, $address = 0, $realnames = 0, $rowcount = 0) {
  445. $result = '';
  446. $delimiter = ';';
  447. $filename = zb_TranslitString($report_name);
  448. $filename = str_replace(' ', '_', $filename) . '_' . date("Y-m-d_His") . '.csv';
  449. $allrealnames = zb_UserGetAllRealnames();
  450. $alladdress = zb_AddressGetFulladdresslist();
  451. $i = 0;
  452. //report titles
  453. foreach ($titles as $eachtitle) {
  454. $result .= __($eachtitle) . $delimiter;
  455. }
  456. if ($address) {
  457. $result .= __('Full address') . $delimiter;
  458. }
  459. if ($realnames) {
  460. $result .= __('Real Name') . $delimiter;
  461. }
  462. $result .= PHP_EOL;
  463. //report data cells
  464. if (!empty($alldata)) {
  465. foreach ($alldata as $io => $eachdata) {
  466. $i++;
  467. foreach ($keys as $eachkey) {
  468. if (array_key_exists($eachkey, $eachdata)) {
  469. $result .= $eachdata[$eachkey] . $delimiter;
  470. }
  471. }
  472. if ($address) {
  473. $result .= @$alladdress[$eachdata['login']] . $delimiter;
  474. }
  475. if ($realnames) {
  476. $result .= @$allrealnames[$eachdata['login']] . $delimiter;
  477. }
  478. $result .= PHP_EOL;
  479. }
  480. }
  481. header('Content-type: application/ms-excel');
  482. header('Content-Disposition: attachment; filename=' . $filename);
  483. die($result);
  484. }
  485. /**
  486. * Renders SQL report as printable table
  487. *
  488. * @param string $reportfile
  489. * @param string $report_name
  490. * @param array $titles
  491. * @param array $keys
  492. * @param array $alldata
  493. * @param bool $address
  494. * @param bool $realnames
  495. * @param bool $rowcount
  496. *
  497. * @return void
  498. */
  499. protected function showSqlPrintable($reportfile, $report_name, $titles, $keys, $alldata, $address = 0, $realnames = 0, $rowcount = 0) {
  500. $result = $this->getReportData($report_name, $report_name, $titles, $keys, $alldata, $address, $realnames, $rowcount);
  501. $result = zb_ReportPrintable(__($report_name), $result);
  502. die($result);
  503. }
  504. /**
  505. * Returns custom-report data
  506. *
  507. * @param string $reportfile
  508. * @param string $report_name
  509. * @param array $titles
  510. * @param array $keys
  511. * @param array $alldata
  512. * @param bool $address
  513. * @param bool $realnames
  514. * @param bool $rowcount
  515. *
  516. * @return string
  517. */
  518. protected function getReportData($reportfile, $report_name, $titles, $keys, $alldata, $address = 0, $realnames = 0, $rowcount = 0) {
  519. $result = '';
  520. $allrealnames = zb_UserGetAllRealnames();
  521. $alladdress = zb_AddressGetFulladdresslist();
  522. $i = 0;
  523. $result = wf_tag('table', false, '', 'width="100%" class="sortable" border="0"');
  524. $result .= wf_tag('tr', false, 'row1');
  525. foreach ($titles as $eachtitle) {
  526. $result .= wf_tag('td') . __($eachtitle) . wf_tag('td', true);
  527. }
  528. if ($address) {
  529. $result .= wf_tag('td') . __('Full address') . wf_tag('td', true);
  530. }
  531. if ($realnames) {
  532. $result .= wf_tag('td') . __('Real Name') . wf_tag('td', true);
  533. }
  534. $result .= wf_tag('tr', true);
  535. if (!empty($alldata)) {
  536. foreach ($alldata as $io => $eachdata) {
  537. $i++;
  538. $result .= wf_tag('tr', false, 'row5');
  539. foreach ($keys as $eachkey) {
  540. if (array_key_exists($eachkey, $eachdata)) {
  541. $result .= wf_tag('td') . $eachdata[$eachkey] . wf_tag('td', true);
  542. }
  543. }
  544. if ($address) {
  545. $result .= wf_tag('td') . @$alladdress[$eachdata['login']] . wf_tag('td', true);
  546. }
  547. if ($realnames) {
  548. $result .= wf_tag('td') . wf_Link(self::URL_USERPROFILE . $eachdata['login'], web_profile_icon() . ' ' . @$allrealnames[$eachdata['login']]) . wf_tag('td', true);
  549. }
  550. $result .= wf_tag('tr', true);
  551. }
  552. }
  553. $result .= wf_tag('table', true);
  554. if ($rowcount) {
  555. $result .= wf_tag('strong') . __('Total') . ': ' . $i . wf_tag('strong', true);
  556. }
  557. return ($result);
  558. }
  559. /**
  560. * Renders some report by its reportId aka template name
  561. *
  562. * @param string $reportId
  563. *
  564. * @return void/script for One-Punch based report
  565. */
  566. public function renderReport($reportId) {
  567. $result = '';
  568. if (isset($this->allReports[$reportId])) {
  569. if ($this->isMeAllowed($reportId)) {
  570. $reportData = $this->allReports[$reportId];
  571. //need some advice?
  572. if ($reportData['REPORT_AOTD']) {
  573. $fga = new FGA();
  574. $awesomeAdvice = $fga->getAdviceOfTheDay();
  575. show_info(__('Advice of the day') . ': ' . $awesomeAdvice);
  576. }
  577. //normal SQL report
  578. if ($reportData['REPORT_TYPE'] == 'SQL') {
  579. $data_query = simple_queryall($reportData['REPORT_QUERY']);
  580. $keys = explode(',', $reportData['REPORT_KEYS']);
  581. $titles = explode(',', $reportData['REPORT_FIELD_NAMES']);
  582. //detecting renderer type
  583. if (ubRouting::checkGet(self::ROUTE_RENDERER)) {
  584. //CSV export modifier
  585. if (ubRouting::get(self::ROUTE_RENDERER) == self::MOD_CSV) {
  586. $this->exportSqlToCSV($reportId, $reportData['REPORT_NAME'], $titles, $keys, $data_query, $reportData['REPORT_ADDR'], $reportData['REPORT_RNAMES'], $reportData['REPORT_ROW_COUNT']);
  587. }
  588. //Printable view modifier
  589. if (ubRouting::get(self::ROUTE_RENDERER) == self::MOD_PRINT) {
  590. $this->showSqlPrintable($reportId, $reportData['REPORT_NAME'], $titles, $keys, $data_query, $reportData['REPORT_ADDR'], $reportData['REPORT_RNAMES'], $reportData['REPORT_ROW_COUNT']);
  591. }
  592. } else {
  593. //just render as normal table
  594. $this->showSqlReport($reportId, $reportData['REPORT_NAME'], $titles, $keys, $data_query, $reportData['REPORT_ADDR'], $reportData['REPORT_RNAMES'], $reportData['REPORT_ROW_COUNT']);
  595. }
  596. }
  597. //One-Punch type report?
  598. if ($reportData['REPORT_TYPE'] == 'ONEPUNCH') {
  599. $onePunch = new OnePunch($reportData['REPORT_QUERY']);
  600. $reportCode = $onePunch->getScriptContent($reportData['REPORT_QUERY']);
  601. if (!empty($reportCode)) {
  602. // we dont exectute code right here, and returns it outside of method
  603. // just for letting him a chance to be executed as normal One-Punch script
  604. // outside of current protected scope.
  605. $result .= $reportCode;
  606. } else {
  607. show_error(__('One-Punch') . ' ' . __('script') . ' [' . $reportData['REPORT_QUERY'] . '] ' . __('Not exists'));
  608. }
  609. }
  610. } else {
  611. log_register('REPORTMASTER VIEW FAIL REPORT `' . $reportId . '` ACCESS VIOLATION');
  612. show_error(__('Access denied'));
  613. show_window('', $this->renderBackControl());
  614. }
  615. } else {
  616. show_error(__('Unknown report'));
  617. }
  618. return ($result);
  619. }
  620. /**
  621. * Returns list of available taskbar icons
  622. *
  623. * @return array
  624. */
  625. protected function getAvailableIcons() {
  626. $result = array('' => __('-'));
  627. $all = rcms_scandir(self::ICONS_PATH, $this->iconsPrefix);
  628. if (!empty($all)) {
  629. foreach ($all as $io => $each) {
  630. $result[$each] = pathinfo($each, PATHINFO_FILENAME);
  631. }
  632. }
  633. return ($result);
  634. }
  635. /**
  636. * Renders existing report editing form
  637. *
  638. * @param string $reportId
  639. *
  640. * @return string
  641. */
  642. public function renderEditForm($reportId) {
  643. $result = '';
  644. $sup = wf_tag('sup') . '*' . wf_tag('sup', true);
  645. $reportId = ubRouting::filters($reportId, 'mres');
  646. if (isset($this->allReports[$reportId])) {
  647. $reportData = $this->allReports[$reportId];
  648. $reportType = $reportData['REPORT_TYPE'];
  649. $inputs = '';
  650. if ($reportType == 'SQL') {
  651. $inputs .= wf_HiddenInput(self::PROUTE_EDTYPE, 'SQL');
  652. $inputs .= wf_TextInput(self::PROUTE_EDNAME, __('Report name') . $sup, $reportData['REPORT_NAME'], true, 40);
  653. $inputs .= wf_TextInput(self::PROUTE_EDQUERY, __('SQL Query') . $sup, $reportData['REPORT_QUERY'], true, 60);
  654. $inputs .= wf_TextInput(self::PROUTE_EDKEYS, __('Data keys, separated by comma') . $sup, $reportData['REPORT_KEYS'], true, 40);
  655. $inputs .= wf_TextInput(self::PROUTE_EDFIELDS, __('Field names, separated by comma') . $sup, $reportData['REPORT_FIELD_NAMES'], true, 40);
  656. $inputs .= web_TriggerSelector(self::PROUTE_EDADDR, $reportData['REPORT_ADDR']) . ' ' . __('Show full address by login key') . wf_tag('br');
  657. $inputs .= web_TriggerSelector(self::PROUTE_EDRNAMES, $reportData['REPORT_RNAMES']) . ' ' . __('Show Real Names by login key') . wf_tag('br');
  658. $inputs .= web_TriggerSelector(self::PROUTE_EDROWCOUNT, $reportData['REPORT_ROW_COUNT']) . ' ' . __('Show data query row count') . wf_tag('br');
  659. }
  660. if ($reportType == 'ONEPUNCH') {
  661. $aliasSelector = array();
  662. $onePunch = new OnePunch();
  663. $allScripts = $onePunch->getAllScripts();
  664. if (!empty($allScripts)) {
  665. foreach ($allScripts as $io => $eachScript) {
  666. $aliasSelector[$eachScript['alias']] = $eachScript['name'];
  667. }
  668. }
  669. $inputs .= wf_HiddenInput(self::PROUTE_EDTYPE, 'ONEPUNCH');
  670. $inputs .= wf_TextInput(self::PROUTE_EDNAME, __('Report name') . $sup, $reportData['REPORT_NAME'], true, 40);
  671. $inputs .= wf_Selector(self::PROUTE_EDQUERY, $aliasSelector, __('One-Punch') . ' ' . __('script') . $sup, $reportData['REPORT_QUERY'], true);
  672. }
  673. $availableIcons = $this->getAvailableIcons();
  674. $inputs .= web_TriggerSelector(self::PROUTE_EDAOTD, $reportData['REPORT_AOTD']) . ' ' . __('Advice of the day') . wf_tag('br');
  675. $inputs .= __('Access') . ':' . wf_tag('br');
  676. $inputs .= wf_TextInput(self::PROUTE_EDADMACL, __('Allowed administrators logins') . ' ' . __('(separator - comma)'), $reportData['REPORT_ALLOWADMINS'], true, 40);
  677. $inputs .= wf_Selector(self::PROUTE_EDICON, $availableIcons, __('Icon'), $reportData['REPORT_ICON'], true);
  678. $inputs .= web_TriggerSelector(self::PROUTE_EDONTB, $reportData['REPORT_ONTB']) . ' ' . __('Show on taskbar') . wf_tag('br');
  679. $inputs .= wf_delimiter(0);
  680. $inputs .= wf_Submit(__('Save'));
  681. $result .= wf_Form('', 'POST', $inputs, 'glamour');
  682. $result .= $this->renderTbPreview($reportId);
  683. $result .= wf_delimiter(1);
  684. $result .= $this->renderCopyPasteForm($reportId);
  685. } else {
  686. $result .= $this->messages->getStyledMessage(__('Unknown report') . ': ' . $reportId, 'error');
  687. }
  688. $result .= wf_delimiter(1);
  689. $result .= $this->renderBackControl();
  690. return ($result);
  691. }
  692. /**
  693. * Renders preview if report will be rendered on task bar.
  694. *
  695. * @param string $reportId
  696. *
  697. * @return string
  698. */
  699. protected function renderTbPreview($reportId) {
  700. $result = '';
  701. if (isset($this->allReports[$reportId])) {
  702. $reportData = $this->allReports[$reportId];
  703. if ($reportData['REPORT_ONTB']) {
  704. $result .= wf_delimiter(1);
  705. $icon = $reportData['REPORT_ICON'];
  706. $reportLabel = __($reportData['REPORT_NAME']);
  707. $availableIcons = $this->getAvailableIcons();
  708. if (!isset($availableIcons[$icon]) or empty($icon)) {
  709. $icon = self::ICON_DEFAULT;
  710. }
  711. $result .= wf_tag('div', false, '');
  712. $result .= wf_tag('strong') . __('Preview') . wf_tag('strong', true) . wf_tag('br');
  713. $result .= wf_tag('div', false, 'dashtask') . wf_img_sized(self::ICONS_PATH . $icon, $reportLabel, '128');
  714. $result .= wf_tag('br') . $reportLabel;
  715. $result .= wf_tag('div', true);
  716. $result .= wf_CleanDiv();
  717. $result .= wf_tag('div', true);
  718. }
  719. }
  720. return ($result);
  721. }
  722. /**
  723. * Renders report as string to backup/send it to someone
  724. *
  725. * @param string $reportId
  726. *
  727. * @return string
  728. */
  729. protected function renderCopyPasteForm($reportId) {
  730. $reportCodeRaw = '';
  731. $opScript = '';
  732. $reportToPack = array();
  733. $packedData = '';
  734. $result = '';
  735. if (isset($this->allReports[$reportId])) {
  736. //Script integrity or validity flag
  737. $isOk = true;
  738. $reportData = $this->allReports[$reportId];
  739. if (empty($reportData)) {
  740. $isOk = false; // report not exists?
  741. }
  742. foreach ($reportData as $key => $value) {
  743. $reportCodeRaw .= $key . '="' . $value . '"' . PHP_EOL;
  744. }
  745. if ($reportData['REPORT_TYPE'] == 'ONEPUNCH') {
  746. $onePunch = new OnePunch($reportData['REPORT_QUERY']);
  747. $opScript = $onePunch->getAllScripts();
  748. if (isset($opScript[$reportData['REPORT_QUERY']])) {
  749. $opScript = $opScript[$reportData['REPORT_QUERY']];
  750. } else {
  751. $opScript = '';
  752. }
  753. if (empty($opScript)) {
  754. //onepunch script requred for this report not exists?
  755. $isOk = false;
  756. }
  757. }
  758. @$release = file_get_contents('RELEASE');
  759. $release = trim($release);
  760. if (empty($release)) {
  761. $isOk = false;
  762. }
  763. if ($isOk) {
  764. $reportToPack['SOURCE'] = 'ReportMaster: Ubilling ' . $release;
  765. $reportToPack['REPORTID'] = $reportId;
  766. $reportToPack['REPORTCODE'] = $reportCodeRaw;
  767. $reportToPack['OPSCRIPT'] = $opScript;
  768. $packedData = json_encode($reportToPack);
  769. $packedData = base64_encode($packedData);
  770. $result .= __('You can copy&paste current report as text') . wf_tag('br');
  771. $result .= wf_TextInput('COPYPASTE', '', $packedData, false, 70, '', 'glamour');
  772. $result .= wf_CleanDiv();
  773. } else {
  774. $result .= $this->messages->getStyledMessage(__('Something went wrong') . ': ' . __('Report') . ' ' . __('is corrupted'), 'error');
  775. }
  776. }
  777. return ($result);
  778. }
  779. /**
  780. * Installs some packed report
  781. *
  782. * @param string $packedData
  783. *
  784. * @return void/string
  785. */
  786. public function installReport($packedData) {
  787. $result = '';
  788. $packedData = trim($packedData);
  789. $unpackedData = array();
  790. if (!empty($packedData)) {
  791. $unpackedData = base64_decode($packedData);
  792. if (!empty($unpackedData)) {
  793. @$unpackedData = json_decode($unpackedData, true);
  794. if (!empty($unpackedData) and is_array($unpackedData)) {
  795. if (isset($unpackedData['SOURCE']) and isset($unpackedData['REPORTID']) and isset($unpackedData['REPORTCODE']) and isset($unpackedData['OPSCRIPT'])) {
  796. $reportSource = trim($unpackedData['SOURCE']);
  797. $reportId = $unpackedData['REPORTID'];
  798. $reportCode = $unpackedData['REPORTCODE'];
  799. $opScript = $unpackedData['OPSCRIPT'];
  800. if (!isset($this->allReports[$reportId])) {
  801. $reportIdF = strip_tags($reportId);
  802. $reportCodeToSave = '';
  803. $reportCodeToSave .= '; Source: ' . $reportSource . PHP_EOL;
  804. $reportCodeToSave .= '; Installation date: ' . curdatetime() . PHP_EOL;
  805. $reportCodeToSave .= $reportCode;
  806. //just save report as normal SQL report
  807. if (empty($opScript)) {
  808. file_put_contents(self::PATH_REPORTS . $reportId, $reportCodeToSave);
  809. log_register('REPORTMASTER INSTALL SQL REPORT `' . $reportIdF . '`');
  810. } else {
  811. //One-Punch checks and script installation is required
  812. $onePunch = new OnePunch();
  813. if ($onePunch->isAliasFree($opScript['alias'])) {
  814. $opInstallResult = $onePunch->installScript($opScript);
  815. if (empty($opInstallResult)) {
  816. //seems everything ok
  817. file_put_contents(self::PATH_REPORTS . $reportId, $reportCodeToSave);
  818. log_register('REPORTMASTER INSTALL ONEPUNCH REPORT `' . $reportIdF . '`');
  819. } else {
  820. //script installation failed
  821. $result .= $opInstallResult;
  822. }
  823. } else {
  824. $result .= __('One-Punch') . ' ' . __('Alias') . ' [' . $opScript['alias'] . '] ' . __('already exists');
  825. }
  826. }
  827. } else {
  828. $result .= __('Report') . ' [' . $reportId . '], "' . $this->allReports[$reportId]['REPORT_NAME'] . '" ' . __('already exists');
  829. }
  830. } else {
  831. $result .= __('Report') . ' ' . __('is corrupted');
  832. }
  833. } else {
  834. $result .= __('Report') . ' ' . __('is corrupted');
  835. }
  836. } else {
  837. $result .= __('Report') . ' ' . __('is corrupted');
  838. }
  839. } else {
  840. $result .= __('Report') . ' ' . __('is corrupted');
  841. }
  842. return ($result);
  843. }
  844. /**
  845. * Saves report on its editing
  846. *
  847. * @param string $reportId
  848. *
  849. * @return void/string on error
  850. */
  851. public function saveReport($reportId) {
  852. $result = '';
  853. $reportId = ubRouting::filters($reportId, 'mres');
  854. //report exists?
  855. if (isset($this->allReports[$reportId])) {
  856. //basic options received
  857. if (ubRouting::checkPost(array(self::PROUTE_EDNAME, self::PROUTE_EDQUERY, self::PROUTE_EDTYPE))) {
  858. $fileName = $reportId;
  859. $pathToSave = self::PATH_REPORTS . $fileName;
  860. $isOk = false;
  861. $newReportType = ubRouting::post(self::PROUTE_EDTYPE);
  862. $newReportName = ubRouting::post(self::PROUTE_EDNAME);
  863. $newReportQuery = ubRouting::post(self::PROUTE_EDQUERY);
  864. $newReportKeys = ubRouting::post(self::PROUTE_EDKEYS);
  865. $newReportFields = ubRouting::post(self::PROUTE_EDFIELDS);
  866. $newReportAddr = ubRouting::post(self::PROUTE_EDADDR);
  867. $newReportRenderNames = ubRouting::post(self::PROUTE_EDRNAMES);
  868. $newReportRowCount = ubRouting::post(self::PROUTE_EDROWCOUNT);
  869. $newReportAdmAcl = ubRouting::post(self::PROUTE_EDADMACL);
  870. $newReportIcon = ubRouting::post(self::PROUTE_EDICON);
  871. $newReportOnTb = ubRouting::post(self::PROUTE_EDONTB);
  872. $newReportAotd = ubRouting::post(self::PROUTE_EDAOTD);
  873. if (!empty($newReportType) and ! empty($newReportName) and ! empty($newReportQuery)) {
  874. //base params here?
  875. $isOk = true;
  876. } else {
  877. $result .= __('All fields marked with an asterisk are mandatory');
  878. }
  879. $reportBody = '';
  880. $reportBody .= 'REPORT_NAME="' . $newReportName . '"' . PHP_EOL;
  881. $reportBody .= 'REPORT_TYPE="' . $newReportType . '"' . PHP_EOL;
  882. $reportBody .= 'REPORT_ALLOWADMINS="' . $newReportAdmAcl . '"' . PHP_EOL; //allows all by default
  883. $reportBody .= 'REPORT_QUERY="' . $newReportQuery . '"' . PHP_EOL;
  884. $reportBody .= 'REPORT_ONTB="' . $newReportOnTb . '"' . PHP_EOL;
  885. $reportBody .= 'REPORT_AOTD="' . $newReportAotd . '"' . PHP_EOL;
  886. $reportBody .= 'REPORT_ICON="' . $newReportIcon . '"' . PHP_EOL;
  887. if ($newReportType == 'SQL') {
  888. $reportBody .= 'REPORT_KEYS="' . $newReportKeys . '"' . PHP_EOL;
  889. $reportBody .= 'REPORT_FIELD_NAMES="' . $newReportFields . '"' . PHP_EOL;
  890. $reportBody .= 'REPORT_ADDR="' . $newReportAddr . '"' . PHP_EOL;
  891. $reportBody .= 'REPORT_RNAMES="' . $newReportRenderNames . '"' . PHP_EOL;
  892. $reportBody .= 'REPORT_ROW_COUNT="' . $newReportRowCount . '"' . PHP_EOL;
  893. }
  894. if ($newReportType == 'ONEPUNCH') {
  895. //script exists?
  896. $onePunch = new OnePunch($newReportQuery);
  897. $scriptCode = $onePunch->getScriptContent($newReportQuery);
  898. if (!empty($scriptCode)) {
  899. $isOk = true;
  900. } else {
  901. $isOk = false;
  902. $result .= __('One-Punch') . ' ' . __('script') . ' ' . $newReportQuery . ' ' . __('Not exists');
  903. }
  904. }
  905. if ($isOk) {
  906. file_put_contents($pathToSave, $reportBody);
  907. log_register('REPORTMASTER SAVE ' . $newReportType . ' REPORT `' . $fileName . '`');
  908. } else {
  909. log_register('REPORTMASTER SAVE FAIL ' . $newReportType . ' REPORT `' . $fileName . '`');
  910. }
  911. }
  912. }
  913. return ($result);
  914. }
  915. /**
  916. *
  917. * @return array
  918. */
  919. public function getTaskBarReports() {
  920. $result = array();
  921. if (!empty($this->allReports)) {
  922. foreach ($this->allReports as $eachReport => $eachReportData) {
  923. if ($eachReportData['REPORT_ONTB']) {
  924. if ($this->isMeAllowed($eachReport)) {
  925. $reportId = 'RM_' . $eachReport;
  926. $result[$eachReport]['ID'] = $reportId;
  927. $result[$eachReport]['NAME'] = $eachReportData['REPORT_NAME'];
  928. $result[$eachReport]['URL'] = self::URL_ME . '&' . self::ROUTE_VIEW . '=' . $eachReport . '&back=tb';
  929. if (!empty($eachReportData['REPORT_ICON'])) {
  930. $reportIcon = $eachReportData['REPORT_ICON'];
  931. } else {
  932. $reportIcon = self::ICON_DEFAULT;
  933. }
  934. $result[$eachReport]['ICON'] = $reportIcon;
  935. $result[$eachReport]['NEED_RIGHT'] = 'REPORTMASTER';
  936. $result[$eachReport]['NEED_OPTION'] = 'TB_REPORTMASTER';
  937. $result[$eachReport]['TYPE'] = 'icon';
  938. }
  939. }
  940. }
  941. }
  942. return ($result);
  943. }
  944. }