Skip to content

Commit

Permalink
Merge pull request #2 from catalyst/main-catalyst-updated
Browse files Browse the repository at this point in the history
Main catalyst updated
  • Loading branch information
jay-oswald authored Dec 13, 2023
2 parents 7b44f4a + 626efc3 commit 98fe1d7
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:

services:
postgres:
image: postgres:10
image: postgres:12
env:
POSTGRES_USER: 'postgres'
POSTGRES_HOST_AUTH_METHOD: 'trust'
Expand Down
4 changes: 2 additions & 2 deletions db/install.xml
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="report/customsql/db" VERSION="20150630" COMMENT="XMLDB file for Moodle report/customsql"
<XMLDB PATH="report/customsql/db" VERSION="20151013" COMMENT="XMLDB file for Moodle report/customsql"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
Expand Down Expand Up @@ -43,4 +43,4 @@
</KEYS>
</TABLE>
</TABLES>
</XMLDB>
</XMLDB>
11 changes: 11 additions & 0 deletions edit_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ public function definition() {
$mform->disabledIf('singlerow', 'runable', 'eq', 'manual');
$mform->disabledIf('at', 'runable', 'ne', 'daily');
$mform->disabledIf('emailto', 'runable', 'eq', 'manual');
$mform->disabledIf('customdir', 'runable', 'eq', 'manual');
$mform->disabledIf('emailwhat', 'runable', 'eq', 'manual');

$this->add_action_buttons();
Expand Down Expand Up @@ -301,6 +302,16 @@ public function validation($data, $files) {
}
}

// Check that the custom directory is writable and a directory, if provided.
if (isset($data['customdir']) && !empty($data['customdir'])) {
if (!is_dir($data['customdir'])) {
$errors['customdir'] = get_string('notadirectory', 'report_customsql');
}
else if (!is_writable($data['customdir'])) {
$errors['customdir'] = get_string('directorynotwritable', 'report_customsql');
}
}

return $errors;
}
}
1 change: 1 addition & 0 deletions lang/en/report_customsql.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
$string['deletecategoryyesno'] = '<p>Are you really sure you want to delete this category? </p>';
$string['deletereportx'] = 'Delete query \'{$a}\'';
$string['description'] = 'Description';
$string['directorynotwritable'] = 'The directory you provided is not writable.';
$string['displayname'] = 'Query name';
$string['displaynamex'] = 'Query name: {$a}';
$string['displaynamerequired'] = 'You must enter a query name';
Expand Down
2 changes: 1 addition & 1 deletion lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ function report_customsql_pluginfile($course, $cm, $context, $filearea, $args, $
if ($report->runable !== 'manual') {
$runtime = $report->lastrun;
}
$csvtimestamp = \report_customsql_generate_csv($report, $runtime);
$csvtimestamp = \report_customsql_generate_csv($report, $runtime, true);
}
list($csvfilename) = report_customsql_csv_filename($report, $csvtimestamp);

Expand Down
23 changes: 22 additions & 1 deletion locallib.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,29 @@ function report_customsql_get_element_type($name) {
return 'text';
}

function report_customsql_generate_csv($report, $timenow) {
/**
* Generate customsql csv file.
*
* @param stdclass $report report record from customsql table.
* @param int $timetimenow unix timestamp - usually "now()"
* @param bool $returnheaderwhenempty if true, a CSV file with headers will always be generated, even if there are no results.
*/
function report_customsql_generate_csv($report, $timenow, $returnheaderwhenempty = false) {
global $DB;
$starttime = microtime(true);

$sql = report_customsql_prepare_sql($report, $timenow);

$queryparams = !empty($report->queryparams) ? unserialize($report->queryparams) : array();
$querylimit = $report->querylimit ?? get_config('report_customsql', 'querylimitdefault');
if ($returnheaderwhenempty) {
// We want the export to always generate a CSV file so we modify the query slightly
// to generate an extra "null" values row, so we can get the column names,
// then we ignore rows that contain null records in every row when generating the csv.
$sql = "SELECT subq.*
FROM (SELECT 1) as ignoreme
LEFT JOIN ($sql) as subq on true";
}
// Query one extra row, so we can tell if we hit the limit.
$rs = report_customsql_execute_query($sql, $queryparams, $querylimit + 1);

Expand All @@ -124,6 +139,11 @@ function report_customsql_generate_csv($report, $timenow) {
}

$data = get_object_vars($row);

if ($returnheaderwhenempty && array_unique(array_values($data)) === [null]) {
// This is a row with all null values - ignore it.
continue;
}
foreach ($data as $name => $value) {
if (report_customsql_get_element_type($name) == 'date_time_selector' &&
report_customsql_is_integer($value) && $value > 0) {
Expand All @@ -146,6 +166,7 @@ function report_customsql_generate_csv($report, $timenow) {
fclose($handle);
}


// Update the execution time in the DB.
$updaterecord = new stdClass();
$updaterecord->id = $report->id;
Expand Down
22 changes: 22 additions & 0 deletions tests/behat/behat_report_customsql.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,28 @@ public function adhoc_database_queries_thinks_the_time_is($time) {
set_config('behat_fixed_time', $value, 'report_customsql');
}

/**
* Simulates downloading an empty report to ensure it shows table headers.
*
* For example:
* When downloading the empty custom sql report "Frog" it contains the headers "frogname,freddy"
*
* @Then /^downloading custom sql report "(?P<REPORT_NAME>[^"]*)" returns a file with headers "([^"]*)"$/
* @param string $reportname the name of the report to go to.
* @param string $headers the headers that shuold be returned.
*/
public function downloading_custom_sql_report_x_returns_a_file_with_headers(string $reportname, string $headers) {
$report = $this->get_report_by_name($reportname);
$url = new \moodle_url('/pluginfile.php/1/'.'report_customsql'. '/'.'download'. '/'. $report->id, ['dataformat' => 'csv']);

$session = $this->getSession()->getCookie('MoodleSession');
$filecontent = trim(download_file_content($url, array('Cookie' => 'MoodleSession=' . $session)));
$filecontent = core_text::trim_utf8_bom($filecontent);
if ($filecontent != $headers) {
throw new \Behat\Mink\Exception\ExpectationException("File headers: $filecontent did not match expected: $headers", $this->getSession());
}
}

/**
* Find a report by name and get all the details.
*
Expand Down
7 changes: 7 additions & 0 deletions tests/behat/report_customsql.feature
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ Feature: Ad-hoc database queries report
And I view the "Test query" custom sql report
Then I should see "This query did not return any data."

Scenario: Download an Ad-hoc database query that returns no data but includes headers
Given the following custom sql report exists:
| name | Test query |
| querysql | SELECT * FROM {config} WHERE name = '-1' |
When I log in as "admin"
Then downloading custom sql report "Test query" returns a file with headers "id,name,value"

Scenario: Create an Ad-hoc database queries category
When I log in as "admin"
And I navigate to "Reports > Ad-hoc database queries" in site administration
Expand Down
2 changes: 1 addition & 1 deletion tests/privacy_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public function test_export_user_data(): void {
$subcontext = [
get_string('privacy:metadata:reportcustomsqlqueries', 'report_customsql')
];
$data = $writer->get_data($subcontext);
$data = (array)$writer->get_data($subcontext);
$this->assertEquals('Report of user 1', reset($data)['displayname']);
}

Expand Down

0 comments on commit 98fe1d7

Please sign in to comment.