Skip to content

Commit

Permalink
MDL-83862 qbank_viewcreator: Add timemodified filter
Browse files Browse the repository at this point in the history
This adds a new filter for the timemodified, displayed
in the "Modified by" column. It uses the new core
datetime filter for the UI.
  • Loading branch information
marxjohnson authored and timhunt committed Dec 24, 2024
1 parent ca45fd3 commit 588f25b
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 1 deletion.
10 changes: 9 additions & 1 deletion question/bank/viewcreator/classes/plugin_feature.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace qbank_viewcreator;

use core_question\local\bank\plugin_features_base;
use core_question\local\bank\view;

/**
* Class plugin_feature is the entrypoint for the columns.
Expand All @@ -27,11 +28,18 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class plugin_feature extends plugin_features_base {

#[\Override]
public function get_question_columns($qbank): array {
return [
new creator_name_column($qbank),
new modifier_name_column($qbank),
];
}

#[\Override]
public function get_question_filters(?view $qbank = null): array {
return [
new timemodified_condition($qbank),
];
}
}
152 changes: 152 additions & 0 deletions question/bank/viewcreator/classes/timemodified_condition.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace qbank_viewcreator;

use core\exception\moodle_exception;
use core\plugininfo\filter;
use core_question\local\bank\condition;

/**
* Filter condition for date/time modified
*
* @package qbank_viewcreator
* @copyright 2024 onwards Catalyst IT EU {@link https://catalyst-eu.net}
* @author Mark Johnson <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class timemodified_condition extends condition {
/**
* @var string Search for times before the specified date.
*/
const MODE_BEFORE = 'before';

/**
* @var string Search for times after the specified date.
*/
const MODE_AFTER = 'after';

/**
* @var string Search for times between the specified dates.
*/
const MODE_BETWEEN = 'between';

#[\Override]
public function get_title() {
return get_string('timemodified', 'qbank_viewcreator');
}

#[\Override]
public static function get_condition_key() {
return 'timemodified';
}

#[\Override]
public function get_filter_class() {
return 'core/datafilter/filtertypes/datetime';
}

/**
* Set a single valid jointype, so we don't display the jointype selector.
*
* We have a separate filter option to control how this condition is applied, Any/All/None doesn't apply here.
*
* @return array
*/
public function get_join_list(): array {
return [
self::JOINTYPE_DEFAULT,
];
}

/**
* Build an SQL WHERE condition to filter questions based on q.timemodified.
*
* $filter['values'][0] contains the datetime to search after, $filter['values'][1] contains the datetime
* to search before. Whether to use these dates to search after, before, or between these dates is determined
* by the value of $filter['fileroptions']['mode'].
*
* The datetime values are in the format YYYY-MM-DDTHH:mm, as provided by the datetime-local input type.
*
* @param array $filter ['values' => [$before, $after], 'filteroptions' => ['mode' => $mode]]
* @return array
* @throws moodle_exception If an invalid mode or range is provided.
*/
public static function build_query_from_filter(array $filter): array {
if (!isset($filter['filteroptions']['mode']) || empty($filter['values'])) {
return ['', []];
}
$mode = $filter['filteroptions']['mode'];
if (!in_array($mode, [self::MODE_AFTER, self::MODE_BEFORE, self::MODE_BETWEEN])) {
throw new moodle_exception('invaliddatetimemode', 'error', a: $filter['filteroptions']['mode']);
}
$tz = new \DateTimeZone(\core_date::get_user_timezone(99));
$datetimeafter = new \DateTime($filter['values'][0], $tz);
$datetimebefore = new \DateTime($filter['values'][1], $tz);
if ($mode === self::MODE_AFTER) {
$conditions = 'q.timemodified > :timemodifiedafter';
$params['timemodifiedafter'] = $datetimeafter->getTimestamp();
} else if ($mode === self::MODE_BEFORE) {
$conditions = 'q.timemodified < :timemodifiedbefore';
$params['timemodifiedbefore'] = $datetimebefore->getTimestamp();
} else {
if ($datetimeafter > $datetimebefore) {
throw new moodle_exception(
'invaliddatetimebetween',
'error',
a: (object) [
'before' => $datetimebefore->format('Y-m-d H:i'),
'after' => $datetimeafter->format('Y-m-d H:i'),
],
);
}
$conditions = 'q.timemodified > :timemodifiedafter AND q.timemodified < :timemodifiedbefore';
$params = [
'timemodifiedafter' => $datetimeafter->getTimestamp(),
'timemodifiedbefore' => $datetimebefore->getTimestamp(),
];
}

return [$conditions, $params];
}

/**
* Return the default datetime values for the filter.
*
* This generates values formatted for datetime-local fields. The first value returned is the current time,
* for use as the default "before" datetime. The second is midnight 1 week ago, for use as the default "after"
* datetime.
*
* @return array[]
*/
public function get_initial_values(): array {
$tz = new \DateTimeZone(\core_date::get_user_timezone());
// Datetime format used by the <input type="datetime-local"> field.
$format = 'Y-m-d\TH:i';
$now = (new \DateTime('now', $tz))->format($format);
$oneweek = (new \DateTime('midnight 1 week ago', $tz))->format($format);
return [
[
'value' => $now,
'title' => $now,
],
[
'value' => $oneweek,
'title' => $oneweek,
],
];
}
}
1 change: 1 addition & 0 deletions question/bank/viewcreator/lang/en/qbank_viewcreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/

$string['modifiedby'] = 'Modified by';
$string['timemodified'] = 'Time modified';
$string['pluginname'] = 'View creator';
$string['privacy:metadata'] = 'The View creator question bank plugin does not store any personal data.';
$string['version'] = 'Version {$a}';
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
@qbank @qbank_viewcreator @javascript
Feature: Time modified filter condition
As a teacher
In order to organise my questions
I want to filter the list of questions by the time and date of last modification

Background:
Given the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| qbank | Qbank 1 | Question bank 1 | C1 | qbank1 |
And the following "question categories" exist:
| contextlevel | reference | name |
| Activity module | qbank1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | First question | Answer the first question |
| Test questions | truefalse | Second question | Answer the second question |
| Test questions | truefalse | Third question | Answer the third question |
And the following "core_question > updated questions" exist:
| questioncategory | question | name | timemodified |
| Test questions | First question | First question | ## 2024-01-10 10:00 ## |
| Test questions | Second question | Second question | ## 2024-01-10 11:00 ## |
| Test questions | Third question | Third question | ## 2024-01-10 12:00 ## |
Given I am on the "Qbank 1" "core_question > question bank" page logged in as "admin"
And I should see "First question"
And I should see "Second question"
And I should see "Third question"

Scenario: Filter by questions modified before time
When I add question bank filter "Time modified"
And the field "Time modified before" matches value "## now ##%FT%R##"
And I set the field "Time modified before" to "2024-01-10T10:59"
And I press "Apply filters"
Then I should see "First question"
And I should not see "Second question"
And I should not see "Third question"

Scenario: Filter by questions modified after time
When I add question bank filter "Time modified"
And I set the field "Select dates" to "After"
And the field "Time modified after" matches value "## midnight 1 week ago ##%FT%R##"
And I set the field "Time modified after" to "2024-01-10T10:59"
And I press "Apply filters"
Then I should not see "First question"
And I should see "Second question"
And I should see "Third question"

Scenario: Filter by questions modified between times
When I add question bank filter "Time modified"
And I set the field "Select dates" to "Between"
And I set the field "Time modified after" to "2024-01-10T10:59"
And I set the field "Time modified before" to "2024-01-10T11:01"
And I press "Apply filters"
Then I should not see "First question"
And I should see "Second question"
And I should not see "Third question"

Scenario: Apply filter between invalid times
When I add question bank filter "Time modified"
And I set the field "Select dates" to "Between"
And I set the field "Time modified after" to "2024-01-10T10:59"
And I set the field "Time modified before" to "2024-01-10T11:01"
And I press "Apply filters"
And I should not see "First question"
And I should see "Second question"
And I should not see "Third question"
And I set the field "Time modified after" to "2024-01-10T11:01"
And I set the field "Time modified before" to "2024-01-10T10:59"
And I press "Apply filters"
# Invalid filters should not be applied.
And I should not see "First question"
And I should see "Second question"
And I should not see "Third question"
# Invalid values should not be set in the URL.
And I reload the page
And the field "Time modified after" matches value "2024-01-10T10:59"
And the field "Time modified before" matches value "2024-01-10T11:01"
And I should not see "First question"
And I should see "Second question"
And I should not see "Third question"

0 comments on commit 588f25b

Please sign in to comment.