Compare commits

..

8 Commits

Author SHA1 Message Date
Eloy Lafuente (stronk7) 500c131eb4 Moodle release 3.9 2020-06-13 20:04:49 +02:00
Eloy Lafuente (stronk7) ea24bef18a NOBUG: Change travis.yml to MOODLE_39_STABLE 2020-06-13 20:04:49 +02:00
Eloy Lafuente (stronk7) 698e225d61 Merge branch 'MDL-68632' of git://github.com/aolley/moodle 2020-06-12 19:59:55 +02:00
Victor Deniz Falcon 8dbc6ebbe3 Moodle release 3.9rc3 2020-06-12 12:32:06 +01:00
Jun Pataleta 2b263bf837 Merge branch 'MDL-69026-master' of git://github.com/andrewnicols/moodle 2020-06-12 11:58:59 +08:00
Adam Olley 9db6c361fd MDL-68632 quizaccess_seb: Limit privacy queriyes to the quiz module
Without this, joins are performed against the course_modules table purely on
the instance id - other modules can share this ID, resulting in incorrect
contexts being pulled in.
2020-06-12 12:31:01 +09:30
Andrew Nicols 8d5926bead MDL-69026 user: Correct statuses => status in test 2020-06-12 10:03:06 +08:00
Andrew Nicols 8bcf74e9bc MDL-69026 user: Wrap sub-query in brackets
It is perfectly valid to have a query like:

Match None of the following:
- Role is ANY of the following:
-- 'Teacher'
-- 'Editing teacher'
-- 'Manager'; AND
- Keyword is NONE of the following:
-- 'Kevin'

However, due to the way in which the query is constructed, this leads to
a query which includes

    WHERE NOT ef.id IS NOT NULL
    AND NOT
        u.id IN (SELECT userid FROM {role_assignments} WHERE roleid IN (...) AND contextid IN (...))
    AND NOT
        NOT (u.firstname || ' ' || u.lastname LIKE '%Kevin%')

The use of NOT NOT is valid in Postgres, MariaDB, MySQL, and MSSQL, but
not in Oracle.

To counter this when the outer jointype is of type NONE, we must wrap
each of the inner WHERE clauses in a set of brackets, which makes the
query:

    WHERE NOT ef.id IS NOT NULL
    AND NOT
        (u.id IN (SELECT userid FROM {role_assignments} WHERE roleid IN (...) AND contextid IN (...)))
    AND NOT
        (NOT (u.firstname || ' ' || u.lastname LIKE '%Kevin%'))

Whilst Oracle does not support the use of `AND NOT NOT ...`, it does support
`AND NOT (NOT ...)`
2020-06-12 10:03:06 +08:00
6 changed files with 77 additions and 32 deletions
+1 -1
View File
@@ -206,7 +206,7 @@ before_script:
# We need the official upstream for comparison
git remote add upstream https://github.com/moodle/moodle.git;
git fetch upstream master;
git fetch upstream MOODLE_39_STABLE;
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
export GIT_COMMIT="$TRAVIS_COMMIT";
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
@@ -93,12 +93,14 @@ class provider implements
$sql = "SELECT c.id
FROM {quizaccess_seb_quizsettings} qs
JOIN {course_modules} cm ON cm.instance = qs.quizid
JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :context
WHERE qs.usermodified = :userid
GROUP BY c.id";
$params = [
'context' => CONTEXT_MODULE,
'modulename' => 'quiz',
'userid' => $userid
];
@@ -108,6 +110,7 @@ class provider implements
FROM {quizaccess_seb_template} tem
JOIN {quizaccess_seb_quizsettings} qs ON qs.templateid = tem.id
JOIN {course_modules} cm ON cm.instance = qs.quizid
JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
JOIN {context} c ON c.instanceid = cm.id AND c.contextlevel = :context
WHERE qs.usermodified = :userid
GROUP BY c.id";
@@ -139,6 +142,7 @@ class provider implements
}
list($insql, $params) = $DB->get_in_or_equal($cmids, SQL_PARAMS_NAMED);
$params['modulename'] = 'quiz';
// SEB quiz settings.
$sql = "SELECT qs.id as id,
@@ -148,6 +152,7 @@ class provider implements
qs.timemodified as timemodified
FROM {quizaccess_seb_quizsettings} qs
JOIN {course_modules} cm ON cm.instance = qs.quizid
JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
WHERE cm.id {$insql}";
$quizsettingslist = $DB->get_records_sql($sql, $params);
@@ -180,6 +185,7 @@ class provider implements
FROM {quizaccess_seb_template} tem
JOIN {quizaccess_seb_quizsettings} qs ON qs.templateid = tem.id
JOIN {course_modules} cm ON cm.instance = qs.quizid
JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
WHERE cm.id {$insql}";
$templatesettingslist = $DB->get_records_sql($sql, $params);
@@ -262,8 +268,9 @@ class provider implements
$sql = "SELECT qs.usermodified AS userid
FROM {quizaccess_seb_quizsettings} qs
JOIN {course_modules} cm ON cm.instance = qs.quizid
JOIN {modules} m ON cm.module = m.id AND m.name = ?
WHERE cm.id = ?";
$params = [$context->instanceid];
$params = ['quiz', $context->instanceid];
$userlist->add_from_sql('userid', $sql, $params);
}
@@ -99,6 +99,15 @@ class quizaccess_seb_provider_testcase extends advanced_testcase {
$context = context_module::instance($this->quiz->cmid);
// Add another course_module of a differenty type - doing this lets us
// test that the data exporter is correctly limiting its selection to
// the quiz and not anything with the same instance id.
// (note this is only effective with databases not using fed (+1000) sequences
// per table, like postgres and mysql do, rendering this useless. In any
// case better to have the situation covered by some DBs,
// like sqlsrv or oracle than by none).
$this->getDataGenerator()->create_module('label', array('course' => $this->course->id));
$contextlist = provider::get_contexts_for_userid($this->user->id);
$approvedcontextlist = new approved_contextlist(
$this->user,
@@ -283,6 +283,14 @@ class participants_search {
case $this->filterset::JOINTYPE_NONE:
$wherenot = ' NOT ';
$wheresjoin = ' AND NOT ';
// Some of the $where conditions may begin with `NOT` which results in `AND NOT NOT ...`.
// To prevent this from breaking on Oracle the inner WHERE clause is wrapped in brackets, making it
// `AND NOT (NOT ...)` which is valid in all DBs.
$wheres = array_map(function($where) {
return "({$where})";
}, $wheres);
break;
default:
// Default to 'Any' jointype.
+48 -27
View File
@@ -1253,8 +1253,8 @@ class participants_search_test extends advanced_testcase {
foreach ($usersdata as $username => $userdata) {
$user = $this->getDataGenerator()->create_user(['username' => $username]);
if (array_key_exists('statuses', $userdata)) {
foreach ($userdata['statuses'] as $enrolmethod => $status) {
if (array_key_exists('status', $userdata)) {
foreach ($userdata['status'] as $enrolmethod => $status) {
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'student', $enrolmethod, 0, 0, $status);
}
}
@@ -1304,27 +1304,27 @@ class participants_search_test extends advanced_testcase {
'Users with different enrolment statuses' => (object) [
'users' => [
'a' => [
'statuses' => [
'status' => [
'manual' => ENROL_USER_ACTIVE,
]
],
'b' => [
'statuses' => [
'status' => [
'self' => ENROL_USER_ACTIVE,
]
],
'c' => [
'statuses' => [
'status' => [
'manual' => ENROL_USER_SUSPENDED,
]
],
'd' => [
'statuses' => [
'status' => [
'self' => ENROL_USER_SUSPENDED,
]
],
'e' => [
'statuses' => [
'status' => [
'manual' => ENROL_USER_ACTIVE,
'self' => ENROL_USER_SUSPENDED,
]
@@ -1333,7 +1333,7 @@ class participants_search_test extends advanced_testcase {
'expect' => [
// Tests for jointype: ANY.
'ANY: No filter' => (object) [
'statuses' => [],
'status' => [],
'jointype' => filter::JOINTYPE_ANY,
'count' => 5,
'expectedusers' => [
@@ -1345,7 +1345,7 @@ class participants_search_test extends advanced_testcase {
],
],
'ANY: Filter on active only' => (object) [
'statuses' => [ENROL_USER_ACTIVE],
'status' => [ENROL_USER_ACTIVE],
'jointype' => filter::JOINTYPE_ANY,
'count' => 3,
'expectedusers' => [
@@ -1355,7 +1355,7 @@ class participants_search_test extends advanced_testcase {
],
],
'ANY: Filter on suspended only' => (object) [
'statuses' => [ENROL_USER_SUSPENDED],
'status' => [ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_ANY,
'count' => 3,
'expectedusers' => [
@@ -1365,7 +1365,7 @@ class participants_search_test extends advanced_testcase {
],
],
'ANY: Filter on multiple statuses' => (object) [
'statuses' => [ENROL_USER_ACTIVE, ENROL_USER_SUSPENDED],
'status' => [ENROL_USER_ACTIVE, ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_ANY,
'count' => 5,
'expectedusers' => [
@@ -1379,7 +1379,7 @@ class participants_search_test extends advanced_testcase {
// Tests for jointype: ALL.
'ALL: No filter' => (object) [
'statuses' => [],
'status' => [],
'jointype' => filter::JOINTYPE_ALL,
'count' => 5,
'expectedusers' => [
@@ -1391,7 +1391,7 @@ class participants_search_test extends advanced_testcase {
],
],
'ALL: Filter on active only' => (object) [
'statuses' => [ENROL_USER_ACTIVE],
'status' => [ENROL_USER_ACTIVE],
'jointype' => filter::JOINTYPE_ALL,
'count' => 3,
'expectedusers' => [
@@ -1401,7 +1401,7 @@ class participants_search_test extends advanced_testcase {
],
],
'ALL: Filter on suspended only' => (object) [
'statuses' => [ENROL_USER_SUSPENDED],
'status' => [ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_ALL,
'count' => 3,
'expectedusers' => [
@@ -1411,7 +1411,7 @@ class participants_search_test extends advanced_testcase {
],
],
'ALL: Filter on multiple statuses' => (object) [
'statuses' => [ENROL_USER_ACTIVE, ENROL_USER_SUSPENDED],
'status' => [ENROL_USER_ACTIVE, ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_ALL,
'count' => 1,
'expectedusers' => [
@@ -1421,7 +1421,7 @@ class participants_search_test extends advanced_testcase {
// Tests for jointype: NONE.
'NONE: No filter' => (object) [
'statuses' => [],
'status' => [],
'jointype' => filter::JOINTYPE_NONE,
'count' => 5,
'expectedusers' => [
@@ -1433,7 +1433,7 @@ class participants_search_test extends advanced_testcase {
],
],
'NONE: Filter on active only' => (object) [
'statuses' => [ENROL_USER_ACTIVE],
'status' => [ENROL_USER_ACTIVE],
'jointype' => filter::JOINTYPE_NONE,
'count' => 3,
'expectedusers' => [
@@ -1443,7 +1443,7 @@ class participants_search_test extends advanced_testcase {
],
],
'NONE: Filter on suspended only' => (object) [
'statuses' => [ENROL_USER_SUSPENDED],
'status' => [ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_NONE,
'count' => 3,
'expectedusers' => [
@@ -1453,7 +1453,7 @@ class participants_search_test extends advanced_testcase {
],
],
'NONE: Filter on multiple statuses' => (object) [
'statuses' => [ENROL_USER_ACTIVE, ENROL_USER_SUSPENDED],
'status' => [ENROL_USER_ACTIVE, ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_NONE,
'count' => 0,
'expectedusers' => [],
@@ -1467,7 +1467,7 @@ class participants_search_test extends advanced_testcase {
foreach ($testdata->expect as $expectname => $expectdata) {
$finaltests["{$testname} => {$expectname}"] = [
'users' => $testdata->users,
'statuses' => $expectdata->statuses,
'status' => $expectdata->status,
'jointype' => $expectdata->jointype,
'count' => $expectdata->count,
'expectedusers' => $expectdata->expectedusers,
@@ -3044,8 +3044,8 @@ class participants_search_test extends advanced_testcase {
'jointype' => filter::JOINTYPE_ALL,
],
// Match Sarah only.
'statuses' => [
'values' => ['active', 'suspended'],
'status' => [
'values' => [ENROL_USER_ACTIVE, ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_ALL,
],
// Match Colin only.
@@ -3119,8 +3119,8 @@ class participants_search_test extends advanced_testcase {
'jointype' => filter::JOINTYPE_NONE,
],
// Exclude Colin and Tony.
'statuses' => [
'values' => ['active'],
'status' => [
'values' => [ENROL_USER_ACTIVE],
'jointype' => filter::JOINTYPE_ALL,
],
// Exclude Barbara.
@@ -3190,8 +3190,8 @@ class participants_search_test extends advanced_testcase {
'jointype' => filter::JOINTYPE_NONE,
],
// Excludes Colin, Tony and Sarah.
'statuses' => [
'values' => ['suspended'],
'status' => [
'values' => [ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_ALL,
],
// Excludes Adam, Colin, Tony, Sarah, Morgan and Jonathan.
@@ -3203,7 +3203,7 @@ class participants_search_test extends advanced_testcase {
'accesssince' => [
'values' => ['-6 months'],
'jointype' => filter::JOINTYPE_ALL,
],
],
],
'jointype' => filter::JOINTYPE_NONE,
'count' => 1,
@@ -3211,6 +3211,27 @@ class participants_search_test extends advanced_testcase {
'barbara.bennett',
],
],
'NONE: Filterset combining several filter types and a double-negative on keyword' => (object) [
'jointype' => filter::JOINTYPE_NONE,
'filterdata' => [
// Note: This is a jointype NONE on the parent jointype NONE.
// The result therefore negated in this instance.
// Include Adam and Anthony.
'keywords' => [
'values' => ['ant'],
'jointype' => filter::JOINTYPE_NONE,
],
// Excludes Tony.
'status' => [
'values' => [ENROL_USER_SUSPENDED],
'jointype' => filter::JOINTYPE_ALL,
],
],
'count' => 1,
'expectedusers' => [
'adam.ant',
],
],
],
],
];
+3 -3
View File
@@ -29,9 +29,9 @@
defined('MOODLE_INTERNAL') || die();
$version = 2020061200.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2020061500.00; // 20200615 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '3.9rc2 (Build: 20200612)'; // Human-friendly version name
$release = '3.9 (Build: 20200615)'; // Human-friendly version name
$branch = '39'; // This version's branch.
$maturity = MATURITY_RC; // This version's maturity level.
$maturity = MATURITY_STABLE; // This version's maturity level.