diff --git a/ldap/hooks/addldapmenuitem.hook.php b/ldap/hooks/addldapmenuitem.hook.php index 4fbefa9..368a80b 100644 --- a/ldap/hooks/addldapmenuitem.hook.php +++ b/ldap/hooks/addldapmenuitem.hook.php @@ -70,8 +70,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Ldap Report" + * -- while the page it opens is headed "Export LDAP Servers". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['ldap report'] = _('Export LDAP Servers'); + } /** * Add the new items beyond list/create. * diff --git a/ldap/js/fog.ldap.report.file.js b/ldap/js/fog.ldap.report.file.js index bfd9b7e..73c9d84 100644 --- a/ldap/js/fog.ldap.report.file.js +++ b/ldap/js/fog.ldap.report.file.js @@ -29,7 +29,7 @@ {data: 'nestedDepth', visible: false}, {data: 'tlsVerify', visible: false}, {data: 'tlsCaCert', visible: false} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/ldap/reports/ldap_report.report.php b/ldap/reports/ldap_report.report.php index 1846ab3..21c5fef 100644 --- a/ldap/reports/ldap_report.report.php +++ b/ldap/reports/ldap_report.report.php @@ -28,7 +28,7 @@ class LDAP_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export LDAP Servers'); + $this->title = self::reportTitle(); $this->headerData = [ _('LDAP Connection Name'), @@ -86,7 +86,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export LDAP Servers'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -98,16 +98,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('ldap'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } } diff --git a/location/hooks/addlocationmenuitem.hook.php b/location/hooks/addlocationmenuitem.hook.php index 65f6fc3..283cb13 100644 --- a/location/hooks/addlocationmenuitem.hook.php +++ b/location/hooks/addlocationmenuitem.hook.php @@ -61,8 +61,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Location Report" + * -- while the page it opens is headed "Export Locations". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['location report'] = _('Export Locations'); + } /** * Add the new items beyond list/create. * diff --git a/location/js/fog.location.report.file.js b/location/js/fog.location.report.file.js index 4d32f4e..7bbac4f 100644 --- a/location/js/fog.location.report.file.js +++ b/location/js/fog.location.report.file.js @@ -13,7 +13,7 @@ {data: 'storagegroupID', visible: false}, {data: 'storagenodeID', visible: false}, {data: 'tftp', visible: false} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/location/reports/location_report.report.php b/location/reports/location_report.report.php index 871749c..f2e7792 100644 --- a/location/reports/location_report.report.php +++ b/location/reports/location_report.report.php @@ -28,7 +28,7 @@ class Location_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export Locations'); + $this->title = self::reportTitle(); $this->headerData = [ _('Location Name'), @@ -52,7 +52,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export Locations'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -64,16 +64,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('location'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } } diff --git a/ou/hooks/addoumenuitem.hook.php b/ou/hooks/addoumenuitem.hook.php index 8c576ac..d07f08a 100644 --- a/ou/hooks/addoumenuitem.hook.php +++ b/ou/hooks/addoumenuitem.hook.php @@ -61,8 +61,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Ou Report" + * -- while the page it opens is headed "Export OUs". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['ou report'] = _('Export OUs'); + } /** * Add the new items beyond list/create. * diff --git a/ou/js/fog.ou.report.file.js b/ou/js/fog.ou.report.file.js index 08e1894..dcbf4e8 100644 --- a/ou/js/fog.ou.report.file.js +++ b/ou/js/fog.ou.report.file.js @@ -11,7 +11,7 @@ {data: 'createdBy', visible: false}, {data: 'createdTime', visible: false}, {data: 'ou'} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/ou/reports/ou_report.report.php b/ou/reports/ou_report.report.php index 433fc5d..3f71e62 100644 --- a/ou/reports/ou_report.report.php +++ b/ou/reports/ou_report.report.php @@ -28,7 +28,7 @@ class OU_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export OUs'); + $this->title = self::reportTitle(); $this->headerData = [ _('OU Name'), @@ -48,7 +48,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export OUs'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -60,16 +60,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('ou'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } } diff --git a/subnetgroup/hooks/addsubnetgroupmenuitem.hook.php b/subnetgroup/hooks/addsubnetgroupmenuitem.hook.php index 7573847..e12d3d8 100644 --- a/subnetgroup/hooks/addsubnetgroupmenuitem.hook.php +++ b/subnetgroup/hooks/addsubnetgroupmenuitem.hook.php @@ -61,8 +61,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Subnetgroup Report" + * -- while the page it opens is headed "Export Subnet Groups". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['subnetgroup report'] = _('Export Subnet Groups'); + } /** * Add the new items beyond list/create. * diff --git a/subnetgroup/js/fog.subnetgroup.report.file.js b/subnetgroup/js/fog.subnetgroup.report.file.js index 2f75fd4..e1c3430 100644 --- a/subnetgroup/js/fog.subnetgroup.report.file.js +++ b/subnetgroup/js/fog.subnetgroup.report.file.js @@ -8,7 +8,7 @@ $('#subnetgroup-report-table').registerReportTable([ {data: 'name'}, {data: 'groupID'} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/subnetgroup/reports/subnetgroup_report.report.php b/subnetgroup/reports/subnetgroup_report.report.php index e3c9196..45452b3 100644 --- a/subnetgroup/reports/subnetgroup_report.report.php +++ b/subnetgroup/reports/subnetgroup_report.report.php @@ -28,7 +28,7 @@ class SubnetGroup_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export Subnet Groups'); + $this->title = self::reportTitle(); $this->headerData = [ _('Name'), @@ -42,7 +42,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export Subnet Groups'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -54,16 +54,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('subnetgroup'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } } diff --git a/taskstateedit/hooks/addtaskstateeditmenuitem.hook.php b/taskstateedit/hooks/addtaskstateeditmenuitem.hook.php index 90a1fce..d2413fc 100644 --- a/taskstateedit/hooks/addtaskstateeditmenuitem.hook.php +++ b/taskstateedit/hooks/addtaskstateeditmenuitem.hook.php @@ -59,8 +59,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Taskstateedit Report" + * -- while the page it opens is headed "Export Task States". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['taskstateedit report'] = _('Export Task States'); + } /** * Add the new items beyond list/create. * diff --git a/taskstateedit/js/fog.taskstateedit.report.file.js b/taskstateedit/js/fog.taskstateedit.report.file.js index 8afdf9f..5eccf58 100644 --- a/taskstateedit/js/fog.taskstateedit.report.file.js +++ b/taskstateedit/js/fog.taskstateedit.report.file.js @@ -10,7 +10,7 @@ {data: 'description'}, {data: 'order', visible: false}, {data: 'icon', visible: false} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/taskstateedit/reports/taskstateedit_report.report.php b/taskstateedit/reports/taskstateedit_report.report.php index 7efec0a..80b7314 100644 --- a/taskstateedit/reports/taskstateedit_report.report.php +++ b/taskstateedit/reports/taskstateedit_report.report.php @@ -28,7 +28,7 @@ class Taskstateedit_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export Task States'); + $this->title = self::reportTitle(); $this->headerData = [ _('Name'), @@ -46,7 +46,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export Task States'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -58,16 +58,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('taskstateedit'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } } diff --git a/tasktypeedit/hooks/addtasktypeeditmenuitem.hook.php b/tasktypeedit/hooks/addtasktypeeditmenuitem.hook.php index 16b3272..feccde6 100644 --- a/tasktypeedit/hooks/addtasktypeeditmenuitem.hook.php +++ b/tasktypeedit/hooks/addtasktypeeditmenuitem.hook.php @@ -59,8 +59,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Tasktypeedit Report" + * -- while the page it opens is headed "Export Task Types". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['tasktypeedit report'] = _('Export Task Types'); + } /** * Add the new items beyond list/create. * diff --git a/tasktypeedit/js/fog.tasktypeedit.report.file.js b/tasktypeedit/js/fog.tasktypeedit.report.file.js index 2e19e43..84558b1 100644 --- a/tasktypeedit/js/fog.tasktypeedit.report.file.js +++ b/tasktypeedit/js/fog.tasktypeedit.report.file.js @@ -15,7 +15,7 @@ {data: 'isAdvanced', visible: false}, {data: 'access'}, {data: 'initrd', visible: false} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/tasktypeedit/reports/tasktypeedit_report.report.php b/tasktypeedit/reports/tasktypeedit_report.report.php index 8b9f527..6792007 100644 --- a/tasktypeedit/reports/tasktypeedit_report.report.php +++ b/tasktypeedit/reports/tasktypeedit_report.report.php @@ -28,7 +28,7 @@ class Tasktypeedit_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export Task Types'); + $this->title = self::reportTitle(); $this->headerData = [ _('Name'), @@ -56,7 +56,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export Task Types'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -68,16 +68,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('tasktypeedit'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } } diff --git a/tests/report-titles-are-registered.test.php b/tests/report-titles-are-registered.test.php new file mode 100644 index 0000000..5d783b5 --- /dev/null +++ b/tests/report-titles-are-registered.test.php @@ -0,0 +1,164 @@ +/reports/`, and if nothing names that report the label is + * `ucwords()` of the FILE name -- so `ou_report.report.php` appears as + * "Ou Report" while the page it opens is headed "Export OUs". Two names for + * one screen. `REPORT_TITLE_DATA` is the seam that fixes it, and the key it + * takes has to agree with THREE other things: the file name, the class name + * (core derives the report's own heading from it) and the base64 `f` + * parameter. Any one of them out of step gives a label that silently falls + * back -- a plausible-looking wrong name, never an error. + * + * The rows. fogproject's "CSV (All)" button posts to `sub=exportAll`, which + * serves `ReportManagement::reportRows()`. A report that still overrides + * `getList()` cannot be reached that way -- `getList()` exits, so nothing + * can take back control from it -- and the download is an EMPTY FILE. No + * error, nothing logged, a CSV that looks like it worked. So a report's JS + * may only ask for the button once the seam is in place, and this pins the + * pair together. + * + * Source analysis, not execution: this repository is fetched on its own by + * bin/fetch-plugins.sh and CI has no fogproject checkout to load core from. + * The assertions are therefore on the AGREEMENT between three files rather + * than on any one of them mentioning a symbol -- a stray mention cannot + * satisfy a cross-file equality. + * + * Usage: php tests/report-titles-are-registered.test.php + * Exit status 0 = pass, 1 = fail. + */ + +$root = dirname(__DIR__); +$fails = []; +$checks = 0; + +/** + * @param string $label what is being asserted + * @param bool $cond the assertion + * + * @return void + */ +function check($label, $cond) +{ + global $fails, $checks; + $checks++; + if (!$cond) { + $fails[] = $label; + } +} + +/** + * The menu key a report name produces: underscores as spaces, lower case. + * + * @param string $name file base name or short class name + * + * @return string + */ +function reportKey($name) +{ + return strtolower(str_replace('_', ' ', $name)); +} + +$reports = glob($root . '/*/reports/*.report.php'); +check('there are plugin reports to check', count($reports) > 4); + +foreach ($reports as $path) { + $plugin = basename(dirname(dirname($path))); + $base = basename($path, '.report.php'); + $key = reportKey($base); + $src = (string) file_get_contents($path); + $name = $plugin . '/' . basename($path); + + // 1. The class name has to produce the same key as the file name -- + // core derives the report's own title from the CLASS, the menu from + // the FILE, and nothing warns when the two disagree. + check( + "$name: declares a class", + 1 === preg_match('/^class\s+(\w+)/m', $src, $m) + ); + if (isset($m[1])) { + check( + "$name: the class name resolves to the same key as the file " + . "(class '{$m[1]}' -> '" . reportKey($m[1]) . "', file -> '$key')", + reportKey($m[1]) === $key + ); + } + + // 2. The title comes from the map, once. A literal beside it is the + // two-names-for-one-screen state this whole change removes. + check( + "$name: takes its title from self::reportTitle()", + false !== strpos($src, '$this->title = self::reportTitle();') + ); + check( + "$name: does not also set a literal title", + 1 !== preg_match('/\$this->title\s*=\s*_\(/', $src) + ); + check( + "$name: the card heading echoes that title rather than a literal", + false !== strpos($src, 'echo $this->title;') + ); + + // 3. The rows seam. getList() must be GONE, not merely accompanied by + // reportRows() -- a report keeping both would serve the grid from + // one and the export from the other. + check( + "$name: implements reportRows()", + 1 === preg_match('/function\s+reportRows\s*\(/', $src) + ); + check( + "$name: no longer overrides getList()", + 0 === preg_match('/function\s+getList\s*\(/', $src) + ); + check( + "$name: reportRows() returns rather than echoing and exiting", + false === strpos($src, 'exit;') + && false === strpos($src, "header('Content-type: application/json')") + ); + + // 4. Some hook in this plugin registers the event AND names this exact + // report. Both halves, because a listener registered under a key + // that does not match the file is the silent fallback again. + $registered = false; + $named = false; + foreach ((array) glob($root . '/' . $plugin . '/hooks/*.hook.php') as $hook) { + $h = (string) file_get_contents($hook); + if (false !== strpos($h, "'REPORT_TITLE_DATA'")) { + $registered = true; + } + if (false !== strpos($h, "\$arguments['titles']['" . $key . "']")) { + $named = true; + } + } + check("$name: a hook registers REPORT_TITLE_DATA", $registered); + check("$name: and names '$key', the key the menu will look up", $named); + + // 5. The toolbar. fullExport is only safe once reportRows() exists, and + // every report here now has it -- so its table should ask. + $js = $root . '/' . $plugin . '/js/fog.' . $plugin . '.report.file.js'; + check("$name: has its table wiring at " . basename($js), file_exists($js)); + if (file_exists($js)) { + $j = (string) file_get_contents($js); + check( + "$name: the table asks for the full export", + false !== strpos($j, 'fullExport: true') + ); + check( + "$name: and its case matches the menu key", + false !== strpos($j, "case '" . $key . "':") + ); + } +} + +if (count($fails)) { + fwrite(STDERR, 'FAIL (' . count($fails) . ' of ' . $checks . "):\n"); + foreach ($fails as $f) { + fwrite(STDERR, " - $f\n"); + } + exit(1); +} +echo 'ok ' . $checks . " checks passed\n"; diff --git a/windowskey/hooks/addwindowskeymenuitem.hook.php b/windowskey/hooks/addwindowskeymenuitem.hook.php index fa9203a..9b3d398 100644 --- a/windowskey/hooks/addwindowskeymenuitem.hook.php +++ b/windowskey/hooks/addwindowskeymenuitem.hook.php @@ -59,8 +59,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Windowskey Report" + * -- while the page it opens is headed "Export Windows Keys". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['windowskey report'] = _('Export Windows Keys'); + } /** * Add the new items beyond list/create. * diff --git a/windowskey/js/fog.windowskey.report.file.js b/windowskey/js/fog.windowskey.report.file.js index 7865a19..5d3c4f5 100644 --- a/windowskey/js/fog.windowskey.report.file.js +++ b/windowskey/js/fog.windowskey.report.file.js @@ -11,7 +11,7 @@ {data: 'createdBy', visible: false}, {data: 'createdTime', visible: false}, {data: 'key'} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/windowskey/reports/windowskey_report.report.php b/windowskey/reports/windowskey_report.report.php index c302d3c..32a138f 100644 --- a/windowskey/reports/windowskey_report.report.php +++ b/windowskey/reports/windowskey_report.report.php @@ -28,7 +28,7 @@ class WindowsKey_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export Windows Keys'); + $this->title = self::reportTitle(); $this->headerData = [ _('Windows Key Name'), @@ -48,7 +48,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export Windows Keys'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -60,16 +60,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('windowskey'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } } diff --git a/wolbroadcast/hooks/addwolbroadcastmenuitem.hook.php b/wolbroadcast/hooks/addwolbroadcastmenuitem.hook.php index b9cbb66..c31114c 100644 --- a/wolbroadcast/hooks/addwolbroadcastmenuitem.hook.php +++ b/wolbroadcast/hooks/addwolbroadcastmenuitem.hook.php @@ -59,8 +59,29 @@ public function __construct() ['PAGES_WITH_OBJECTS', 'addPageWithObject'], ['PERMISSION_REGISTRY_DATA', 'permData'], ['SUB_MENULINK_DATA', 'menuUpdate'], + ['REPORT_TITLE_DATA', 'reportTitle'], ]); } + /** + * Names this plugin's report in the Reports menu. + * + * Without this the sidebar shows ucwords() of the FILE name -- "Wolbroadcast Report" + * -- while the page it opens is headed "Export WOL Broadcasts". Two names for one + * screen, and the file name is the half nobody chose. + * + * Keyed the way the menu and the base64 `f` parameter are: the file + * name with underscores as spaces, lower case. The report reads the + * same map back through reportTitle() for its heading, so the two + * cannot drift apart again. + * + * @param mixed $arguments The titles to modify. + * + * @return void + */ + public function reportTitle($arguments) + { + $arguments['titles']['wolbroadcast report'] = _('Export WOL Broadcasts'); + } /** * Add the new items beyond list/create. * diff --git a/wolbroadcast/js/fog.wolbroadcast.report.file.js b/wolbroadcast/js/fog.wolbroadcast.report.file.js index a7b836b..da0c4ff 100644 --- a/wolbroadcast/js/fog.wolbroadcast.report.file.js +++ b/wolbroadcast/js/fog.wolbroadcast.report.file.js @@ -9,7 +9,7 @@ {data: 'name'}, {data: 'description', visible: false}, {data: 'broadcast'} - ]); + ], {fullExport: true}); break; } })(jQuery); diff --git a/wolbroadcast/reports/wolbroadcast_report.report.php b/wolbroadcast/reports/wolbroadcast_report.report.php index 6cef943..11c22c4 100644 --- a/wolbroadcast/reports/wolbroadcast_report.report.php +++ b/wolbroadcast/reports/wolbroadcast_report.report.php @@ -28,7 +28,7 @@ class Wolbroadcast_Report extends \FOG\ReportManagement */ public function file() { - $this->title = _('Export WOL Broadcasts'); + $this->title = self::reportTitle(); $this->headerData = [ _('Broadcast Name'), @@ -44,7 +44,7 @@ public function file() echo '
'; echo '
'; echo '

'; - echo _('Export WOL Broadcasts'); + echo $this->title; echo '

'; echo '

'; echo _('Use the selector to choose how many items you want exported'); @@ -56,16 +56,18 @@ public function file() echo '

'; } /** - * Returns the JSON data for this report. + * The rows this report serves. * - * @return void + * Split from the emit so the grid and the "CSV (All)" export run the + * same query -- ReportManagement::exportAll() serves this, and cannot + * take back control from a getList() that exits. + * + * @return array */ - public function getList() + protected function reportRows() { - header('Content-type: application/json'); \FOG\Router\Route::listem('wolbroadcast'); - http_response_code(\FOG\Router\HTTPResponseCodes::HTTP_SUCCESS); - echo \FOG\Router\Route::getData(); - exit; + + return (array) json_decode(\FOG\Router\Route::getData(), true); } }