mirror of
https://github.com/moodle/moodle.git
synced 2025-01-19 14:27:22 +01:00
Merge branch 'wip-MDL-61308-master' of git://github.com/abgreeve/moodle
This commit is contained in:
commit
1c42b1d6ed
116
mod/assign/classes/privacy/assign_plugin_request_data.php
Normal file
116
mod/assign/classes/privacy/assign_plugin_request_data.php
Normal file
@ -0,0 +1,116 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This file contains the mod_assign assign_plugin_request_data class
|
||||
*
|
||||
* For assign plugin privacy data to fulfill requests.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_assign\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* An object for fulfilling an assign plugin data request.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assign_plugin_request_data {
|
||||
|
||||
/** @var context The context that we are dealing with. */
|
||||
protected $context;
|
||||
|
||||
/** @var object For submisisons the submission object, for feedback the grade object. */
|
||||
protected $pluginobject;
|
||||
|
||||
/** @var array The path or location that we are exporting data to. */
|
||||
protected $subcontext;
|
||||
|
||||
/** @var object If set then only export data related directly to this user. */
|
||||
protected $user;
|
||||
|
||||
/** @var assign The assign object */
|
||||
protected $assign;
|
||||
|
||||
/**
|
||||
* Object creator for assign plugin request data.
|
||||
*
|
||||
* @param \context $context Context object.
|
||||
* @param \stdClass $pluginobject The grade object.
|
||||
* @param array $subcontext Directory / file location.
|
||||
* @param \stdClass $user The user object.
|
||||
* @param \assign $assign The assign object.
|
||||
*/
|
||||
public function __construct(\context $context, \assign $assign, \stdClass $pluginobject = null, array $subcontext = [],
|
||||
\stdClass $user = null) {
|
||||
$this->context = $context;
|
||||
$this->pluginobject = $pluginobject;
|
||||
$this->subcontext = $subcontext;
|
||||
$this->user = $user;
|
||||
$this->assign = $assign;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for this attribute.
|
||||
*
|
||||
* @return context Context
|
||||
*/
|
||||
public function get_context() {
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for this attribute.
|
||||
*
|
||||
* @return object The assign plugin object
|
||||
*/
|
||||
public function get_pluginobject() {
|
||||
return $this->pluginobject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for this attribute.
|
||||
*
|
||||
* @return array The location (path) that this data is being writter to.
|
||||
*/
|
||||
public function get_subcontext() {
|
||||
return $this->subcontext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for this attribute.
|
||||
*
|
||||
* @return object The user id. If set then only information directly related to this user ID will be returned.
|
||||
*/
|
||||
public function get_user() {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for this attribute.
|
||||
*
|
||||
* @return assign The assign object.
|
||||
*/
|
||||
public function get_assign() {
|
||||
return $this->assign;
|
||||
}
|
||||
}
|
87
mod/assign/classes/privacy/assignfeedback_provider.php
Normal file
87
mod/assign/classes/privacy/assignfeedback_provider.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This file contains the assignfeedback_provider interface.
|
||||
*
|
||||
* Assignment Sub plugins should implement this if they store personal information.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_assign\privacy;
|
||||
|
||||
use core_privacy\local\request\contextlist;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
interface assignfeedback_provider extends \core_privacy\local\request\plugin\subplugin_provider {
|
||||
|
||||
/**
|
||||
* Retrieves the contextids associated with the provided userid for this subplugin.
|
||||
* NOTE if your subplugin must have an entry in the assign_grade table to work, then this
|
||||
* method can be empty.
|
||||
*
|
||||
* @param int $userid The user ID to get context IDs for.
|
||||
* @param \core_privacy\local\request\contextlist $contextlist Use add_from_sql with this object to add your context IDs.
|
||||
*/
|
||||
public static function get_context_for_userid_within_feedback(int $userid, contextlist $contextlist);
|
||||
|
||||
/**
|
||||
* Returns student user ids related to the provided teacher ID. If an entry must be present in the assign_grade table for
|
||||
* your plugin to work then there is no need to fill in this method. If you filled in get_context_for_userid_within_feedback()
|
||||
* then you probably have to fill this in as well.
|
||||
*
|
||||
* @param useridlist $useridlist A list of user IDs of students graded by this user.
|
||||
*/
|
||||
public static function get_student_user_ids(useridlist $useridlist);
|
||||
|
||||
/**
|
||||
* Export feedback data with the available grade and userid information provided.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - current path (subcontext)
|
||||
* - user object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Contains data to help export the user information.
|
||||
*/
|
||||
public static function export_feedback_user_data(assign_plugin_request_data $exportdata);
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function delete_feedback_for_context(assign_plugin_request_data $requestdata);
|
||||
|
||||
/**
|
||||
* Calling this function should delete all user data associated with this grade.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - user object
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data.
|
||||
*/
|
||||
public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata);
|
||||
}
|
88
mod/assign/classes/privacy/assignsubmission_provider.php
Normal file
88
mod/assign/classes/privacy/assignsubmission_provider.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This file contains the assignsubmission_provider interface.
|
||||
*
|
||||
* Assignment Sub plugins should implement this if they store personal information.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_assign\privacy;
|
||||
|
||||
use core_privacy\local\request\contextlist;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
interface assignsubmission_provider extends \core_privacy\local\request\plugin\subplugin_provider {
|
||||
|
||||
/**
|
||||
* Retrieves the contextids associated with the provided userid for this subplugin.
|
||||
* NOTE if your subplugin must have an entry in the assign_submission table to work, then this
|
||||
* method can be empty.
|
||||
*
|
||||
* @param int $userid The user ID to get context IDs for.
|
||||
* @param \core_privacy\local\request\contextlist $contextlist Use add_from_sql with this object to add your context IDs.
|
||||
*/
|
||||
public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist);
|
||||
|
||||
/**
|
||||
* Returns student user ids related to the provided teacher ID. If it is possible that a student ID will not be returned by
|
||||
* the sql query in \mod_assign\privacy\provider::find_grader_info() Then you need to provide some sql to retrive those
|
||||
* student IDs. This is highly likely if you had to fill in get_context_for_userid_within_submission above.
|
||||
*
|
||||
* @param useridlist $useridlist A user ID list object that you can append your user IDs to.
|
||||
*/
|
||||
public static function get_student_user_ids(useridlist $useridlist);
|
||||
|
||||
/**
|
||||
* This method is used to export any user data this sub-plugin has using the assign_plugin_request_data object to get the
|
||||
* context and userid.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - submission object
|
||||
* - current path (subcontext)
|
||||
* - user object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Information to use to export user data for this sub-plugin.
|
||||
*/
|
||||
public static function export_submission_user_data(assign_plugin_request_data $exportdata);
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Information to use to delete user data for this submission.
|
||||
*/
|
||||
public static function delete_submission_for_context(assign_plugin_request_data $requestdata);
|
||||
|
||||
/**
|
||||
* A call to this method should delete user data (where practicle) from the userid and context.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - submission object
|
||||
* - user object
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Details about the user and context to focus the deletion.
|
||||
*/
|
||||
public static function delete_submission_for_userid(assign_plugin_request_data $exportdata);
|
||||
}
|
100
mod/assign/classes/privacy/feedback_legacy_polyfill.php
Normal file
100
mod/assign/classes/privacy/feedback_legacy_polyfill.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This file contains the polyfill to allow a plugin to operate with Moodle 3.3 up.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_assign\privacy;
|
||||
|
||||
use core_privacy\local\request\contextlist;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The trait used to provide backwards compatability for third-party plugins.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
trait feedback_legacy_polyfill {
|
||||
|
||||
/**
|
||||
* Retrieves the contextids associated with the provided userid for this subplugin.
|
||||
* NOTE if your subplugin must have an entry in the assign_grade table to work, then this
|
||||
* method can be empty.
|
||||
*
|
||||
* @param int $userid The user ID to get context IDs for.
|
||||
* @param \core_privacy\local\request\contextlist $contextlist Use add_from_sql with this object to add your context IDs.
|
||||
*/
|
||||
public static function get_context_for_userid_within_feedback(int $userid, contextlist $contextlist) {
|
||||
return static::_get_context_for_userid_within_feedback($userid, $contextlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns student user ids related to the provided teacher ID. If an entry must be present in the assign_grade table for
|
||||
* your plugin to work then there is no need to fill in this method. If you filled in get_context_for_userid_within_feedback()
|
||||
* then you probably have to fill this in as well.
|
||||
*
|
||||
* @param useridlist $useridlist A list of user IDs of students graded by this user.
|
||||
*/
|
||||
public static function get_student_user_ids(useridlist $useridlist) {
|
||||
return static::_get_student_user_ids($useridlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export feedback data with the available grade and userid information provided.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - current path (subcontext)
|
||||
* - user object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Contains data to help export the user information.
|
||||
*/
|
||||
public static function export_feedback_user_data(assign_plugin_request_data $exportdata) {
|
||||
return static::_export_feedback_user_data($exportdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function delete_feedback_for_context(assign_plugin_request_data $requestdata) {
|
||||
return static::_delete_feedback_for_context($requestdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this function should delete all user data associated with this grade.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - user object
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data.
|
||||
*/
|
||||
public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata) {
|
||||
return static::_delete_feedback_for_grade($requestdata);
|
||||
}
|
||||
}
|
496
mod/assign/classes/privacy/provider.php
Normal file
496
mod/assign/classes/privacy/provider.php
Normal file
@ -0,0 +1,496 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_assign\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\metadata\provider as metadataprovider;
|
||||
use \core_privacy\local\request\contextlist;
|
||||
use \core_privacy\local\request\plugin\provider as pluginprovider;
|
||||
use \core_privacy\local\request\user_preference_provider as preference_provider;
|
||||
use \core_privacy\local\request\writer;
|
||||
use \core_privacy\local\request\approved_contextlist;
|
||||
use \core_privacy\local\request\transform;
|
||||
use \core_privacy\local\request\helper;
|
||||
use \core_privacy\manager;
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements metadataprovider, pluginprovider, preference_provider {
|
||||
|
||||
/** Interface for all assign submission sub-plugins. */
|
||||
const ASSIGNSUBMISSION_INTERFACE = 'mod_assign\privacy\assignsubmission_provider';
|
||||
|
||||
/** Interface for all assign feedback sub-plugins. */
|
||||
const ASSIGNFEEDBACK_INTERFACE = 'mod_assign\privacy\assignfeedback_provider';
|
||||
|
||||
/**
|
||||
* Provides meta data that is stored about a user with mod_assign
|
||||
*
|
||||
* @param collection $collection A collection of meta data items to be added to.
|
||||
* @return collection Returns the collection of metadata.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$assigngrades = [
|
||||
'userid' => 'privacy:metadata:userid',
|
||||
'timecreated' => 'privacy:metadata:timecreated',
|
||||
'timemodified' => 'timemodified',
|
||||
'grader' => 'privacy:metadata:grader',
|
||||
'grade' => 'privacy:metadata:grade',
|
||||
'attemptnumber' => 'attemptnumber'
|
||||
];
|
||||
$assignoverrides = [
|
||||
'groupid' => 'privacy:metadata:groupid',
|
||||
'userid' => 'privacy:metadata:userid',
|
||||
'allowsubmissionsfromdate' => 'allowsubmissionsfromdate',
|
||||
'duedate' => 'duedate',
|
||||
'cutoffdate' => 'cutoffdate'
|
||||
];
|
||||
$assignsubmission = [
|
||||
'userid' => 'privacy:metadata:userid',
|
||||
'timecreated' => 'privacy:metadata:timecreated',
|
||||
'timemodified' => 'timemodified',
|
||||
'status' => 'gradingstatus',
|
||||
'groupid' => 'privacy:metadata:groupid',
|
||||
'attemptnumber' => 'attemptnumber',
|
||||
'latest' => 'privacy:metadata:latest'
|
||||
];
|
||||
$assignuserflags = [
|
||||
'userid' => 'privacy:metadata:userid',
|
||||
'assignment' => 'privacy:metadata:assignmentid',
|
||||
'locked' => 'locksubmissions',
|
||||
'mailed' => 'privacy:metadata:mailed',
|
||||
'extensionduedate' => 'extensionduedate',
|
||||
'workflowstate' => 'markingworkflowstate',
|
||||
'allocatedmarker' => 'allocatedmarker'
|
||||
];
|
||||
$assignusermapping = [
|
||||
'assignment' => 'privacy:metadata:assignmentid',
|
||||
'userid' => 'privacy:metadata:userid'
|
||||
];
|
||||
$collection->add_database_table('assign_grades', $assigngrades, 'privacy:metadata:assigngrades');
|
||||
$collection->add_database_table('assign_overrides', $assignoverrides, 'privacy:metadata:assignoverrides');
|
||||
$collection->add_database_table('assign_submission', $assignsubmission, 'privacy:metadata:assignsubmissiondetail');
|
||||
$collection->add_database_table('assign_user_flags', $assignuserflags, 'privacy:metadata:assignuserflags');
|
||||
$collection->add_database_table('assign_user_mapping', $assignusermapping, 'privacy:metadata:assignusermapping');
|
||||
$collection->add_user_preference('assign_perpage', 'privacy:metadata:assignperpage');
|
||||
$collection->add_user_preference('assign_filter', 'privacy:metadata:assignfilter');
|
||||
$collection->add_user_preference('assign_markerfilter', 'privacy:metadata:assignmarkerfilter');
|
||||
$collection->add_user_preference('assign_workflowfilter', 'privacy:metadata:assignworkflowfilter');
|
||||
$collection->add_user_preference('assign_quickgrading', 'privacy:metadata:assignquickgrading');
|
||||
$collection->add_user_preference('assign_downloadasfolders', 'privacy:metadata:assigndownloadasfolders');
|
||||
|
||||
// Link to subplugins.
|
||||
$collection->add_plugintype_link('assignsubmission', [],'privacy:metadata:assignsubmissionpluginsummary');
|
||||
$collection->add_plugintype_link('assignfeedback', [], 'privacy:metadata:assignfeedbackpluginsummary');
|
||||
$collection->add_subsystem_link('core_message', [], 'privacy:metadata:assignmessageexplanation');
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the contexts that has information relating to the userid.
|
||||
*
|
||||
* @param int $userid The user ID.
|
||||
* @return contextlist an object with the contexts related to a userid.
|
||||
*/
|
||||
public static function get_contexts_for_userid(int $userid) : contextlist {
|
||||
$params = ['modulename' => 'assign',
|
||||
'contextlevel' => CONTEXT_MODULE,
|
||||
'userid' => $userid,
|
||||
'graderid' => $userid,
|
||||
'aouserid' => $userid,
|
||||
'asnuserid' => $userid,
|
||||
'aufuserid' => $userid,
|
||||
'aumuserid' => $userid];
|
||||
|
||||
$sql = "SELECT ctx.id
|
||||
FROM {course_modules} cm
|
||||
JOIN {modules} m ON cm.module = m.id AND m.name = :modulename
|
||||
JOIN {assign} a ON cm.instance = a.id
|
||||
JOIN {context} ctx ON cm.id = ctx.instanceid AND ctx.contextlevel = :contextlevel
|
||||
LEFT JOIN {assign_grades} ag ON a.id = ag.assignment
|
||||
LEFT JOIN {assign_overrides} ao ON a.id = ao.assignid
|
||||
LEFT JOIN {assign_submission} asn ON a.id = asn.assignment
|
||||
LEFT JOIN {assign_user_flags} auf ON a.id = auf.assignment
|
||||
LEFT JOIN {assign_user_mapping} aum ON a.id = aum.assignment
|
||||
WHERE ag.userid = :userid OR ag.grader = :graderid OR ao.userid = :aouserid
|
||||
OR asn.userid = :asnuserid OR auf.userid = :aufuserid OR aum.userid = :aumuserid";
|
||||
$contextlist = new contextlist();
|
||||
$contextlist->add_from_sql($sql, $params);
|
||||
manager::plugintype_class_callback('assignfeedback', self::ASSIGNFEEDBACK_INTERFACE,
|
||||
'get_context_for_userid_within_feedback', [$userid, $contextlist]);
|
||||
manager::plugintype_class_callback('assignsubmission', self::ASSIGNSUBMISSION_INTERFACE,
|
||||
'get_context_for_userid_within_submission', [$userid, $contextlist]);
|
||||
|
||||
return $contextlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out the user data filtered by contexts.
|
||||
*
|
||||
* @param approved_contextlist $contextlist contexts that we are writing data out from.
|
||||
*/
|
||||
public static function export_user_data(approved_contextlist $contextlist) {
|
||||
foreach ($contextlist->get_contexts() as $context) {
|
||||
// Check that the context is a module context.
|
||||
if ($context->contextlevel != CONTEXT_MODULE) {
|
||||
continue;
|
||||
}
|
||||
$user = $contextlist->get_user();
|
||||
$assigndata = helper::get_context_data($context, $user);
|
||||
helper::export_context_files($context, $user);
|
||||
|
||||
writer::with_context($context)->export_data([], $assigndata);
|
||||
$assign = new \assign($context, null, null);
|
||||
|
||||
// I need to find out if I'm a student or a teacher.
|
||||
if ($userids = self::get_graded_users($user->id, $assign)) {
|
||||
// Return teacher info.
|
||||
$currentpath = [get_string('privacy:studentpath', 'mod_assign')];
|
||||
foreach ($userids as $studentuserid) {
|
||||
$studentpath = array_merge($currentpath, [$studentuserid->id]);
|
||||
static::export_submission($assign, $studentuserid, $context, $studentpath, true);
|
||||
}
|
||||
}
|
||||
|
||||
static::export_overrides($context, $assign, $user);
|
||||
static::export_submission($assign, $user, $context, []);
|
||||
// Meta data.
|
||||
self::store_assign_user_flags($context, $assign, $user->id);
|
||||
if ($assign->is_blind_marking()) {
|
||||
$uniqueid = $assign->get_uniqueid_for_user_static($assign->get_instance()->id, $contextlist->get_user()->id);
|
||||
if ($uniqueid) {
|
||||
writer::with_context($context)
|
||||
->export_metadata([get_string('blindmarking', 'mod_assign')], 'blindmarkingid', $uniqueid,
|
||||
get_string('privacy:blindmarkingidentifier', 'mod_assign'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all use data which matches the specified context.
|
||||
*
|
||||
* @param context $context The module context.
|
||||
*/
|
||||
public static function delete_data_for_all_users_in_context(\context $context) {
|
||||
global $DB;
|
||||
|
||||
if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
// Apparently we can't trust anything that comes via the context.
|
||||
// Go go mega query to find out it we have an assign context that matches an existing assignment.
|
||||
$sql = "SELECT a.id
|
||||
FROM {assign} a
|
||||
JOIN {course_modules} cm ON a.id = cm.instance
|
||||
JOIN {modules} m ON m.id = cm.module AND m.name = :modulename
|
||||
JOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextmodule
|
||||
WHERE ctx.id = :contextid";
|
||||
$params = ['modulename' => 'assign', 'contextmodule' => CONTEXT_MODULE, 'contextid' => $context->id];
|
||||
$count = $DB->get_field_sql($sql, $params);
|
||||
// If we have a count over zero then we can proceed.
|
||||
if ($count > 0) {
|
||||
// Get the assignment related to this context.
|
||||
$assign = new \assign($context, null, null);
|
||||
// What to do first... Get sub plugins to delete their stuff.
|
||||
$requestdata = new assign_plugin_request_data($context, $assign);
|
||||
manager::plugintype_class_callback('assignsubmission', self::ASSIGNSUBMISSION_INTERFACE,
|
||||
'delete_submission_for_context', [$requestdata]);
|
||||
$requestdata = new assign_plugin_request_data($context, $assign);
|
||||
manager::plugintype_class_callback('assignfeedback', self::ASSIGNFEEDBACK_INTERFACE,
|
||||
'delete_feedback_for_context', [$requestdata]);
|
||||
$DB->delete_records('assign_grades', ['assignment' => $assign->get_instance()->id]);
|
||||
|
||||
// Time to roll my own method for deleting overrides.
|
||||
static::delete_user_overrides($assign);
|
||||
$DB->delete_records('assign_submission', ['assignment' => $assign->get_instance()->id]);
|
||||
$DB->delete_records('assign_user_flags', ['assignment' => $assign->get_instance()->id]);
|
||||
$DB->delete_records('assign_user_mapping', ['assignment' => $assign->get_instance()->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all user data for the specified user, in the specified contexts.
|
||||
*
|
||||
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
|
||||
*/
|
||||
public static function delete_data_for_user(approved_contextlist $contextlist) {
|
||||
global $DB;
|
||||
|
||||
$user = $contextlist->get_user();
|
||||
|
||||
foreach ($contextlist as $context) {
|
||||
if ($context->contextlevel != CONTEXT_MODULE) {
|
||||
continue;
|
||||
}
|
||||
// Get the assign object.
|
||||
$assign = new \assign($context, null, null);
|
||||
$assignid = $assign->get_instance()->id;
|
||||
|
||||
$submissions = $DB->get_records('assign_submission', ['assignment' => $assignid, 'userid' => $user->id]);
|
||||
foreach ($submissions as $submission) {
|
||||
$requestdata = new assign_plugin_request_data($context, $assign, $submission, [], $user);
|
||||
manager::plugintype_class_callback('assignsubmission', self::ASSIGNSUBMISSION_INTERFACE,
|
||||
'delete_submission_for_userid', [$requestdata]);
|
||||
}
|
||||
|
||||
$grades = $DB->get_records('assign_grades', ['assignment' => $assignid, 'userid' => $user->id]);
|
||||
foreach ($grades as $grade) {
|
||||
$requestdata = new assign_plugin_request_data($context, $assign, $grade, [], $user);
|
||||
manager::plugintype_class_callback('assignfeedback', self::ASSIGNFEEDBACK_INTERFACE,
|
||||
'delete_feedback_for_grade', [$requestdata]);
|
||||
}
|
||||
|
||||
static::delete_user_overrides($assign, $user);
|
||||
$DB->delete_records('assign_user_flags', ['assignment' => $assignid, 'userid' => $user->id]);
|
||||
$DB->delete_records('assign_user_mapping', ['assignment' => $assignid, 'userid' => $user->id]);
|
||||
$DB->delete_records('assign_grades', ['assignment' => $assignid, 'userid' => $user->id]);
|
||||
$DB->delete_records('assign_submission', ['assignment' => $assignid, 'userid' => $user->id]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes assignment overrides.
|
||||
*
|
||||
* @param \assign $assign The assignment object
|
||||
* @param \stdClass $user The user object if we are deleting only the overrides for one user.
|
||||
*/
|
||||
protected static function delete_user_overrides(\assign $assign, \stdClass $user = null) {
|
||||
global $DB;
|
||||
|
||||
$assignid = $assign->get_instance()->id;
|
||||
$params = (isset($user)) ? ['assignid' => $assignid, 'userid' => $user->id] : ['assignid' => $assignid];
|
||||
|
||||
$overrides = $DB->get_records('assign_overrides', $params);
|
||||
if (!empty($overrides)) {
|
||||
foreach ($overrides as $override) {
|
||||
|
||||
// First delete calendar events associated with this override.
|
||||
$conditions = ['modulename' => 'assign', 'instance' => $assignid];
|
||||
if (isset($user)) {
|
||||
$conditions['userid'] = $user->id;
|
||||
}
|
||||
$DB->delete_records('event', $conditions);
|
||||
|
||||
// Next delete the overrides.
|
||||
$DB->delete_records('assign_overrides', ['id' => $override->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find out if this user has graded any users.
|
||||
*
|
||||
* @param int $userid The user ID (potential teacher).
|
||||
* @param assign $assign The assignment object.
|
||||
* @return array If successful an array of objects with userids that this user graded, otherwise false.
|
||||
*/
|
||||
protected static function get_graded_users(int $userid, \assign $assign) {
|
||||
$params = ['grader' => $userid, 'assignid' => $assign->get_instance()->id];
|
||||
|
||||
$sql = "SELECT DISTINCT userid AS id
|
||||
FROM {assign_grades}
|
||||
WHERE grader = :grader AND assignment = :assignid";
|
||||
|
||||
$useridlist = new useridlist($userid, $assign->get_instance()->id);
|
||||
$useridlist->add_from_sql($sql, $params);
|
||||
|
||||
// Call sub-plugins to see if they have information not already collected.
|
||||
manager::plugintype_class_callback('assignsubmission', self::ASSIGNSUBMISSION_INTERFACE, 'get_student_user_ids',
|
||||
[$useridlist]);
|
||||
manager::plugintype_class_callback('assignfeedback', self::ASSIGNFEEDBACK_INTERFACE, 'get_student_user_ids', [$useridlist]);
|
||||
|
||||
$userids = $useridlist->get_userids();
|
||||
return ($userids) ? $userids : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out various user meta data about the assignment.
|
||||
*
|
||||
* @param \context $context The context of this assignment.
|
||||
* @param \assign $assign The assignment object.
|
||||
* @param int $userid The user ID
|
||||
*/
|
||||
protected static function store_assign_user_flags(\context $context, \assign $assign, int $userid) {
|
||||
$datatypes = ['locked' => get_string('locksubmissions', 'mod_assign'),
|
||||
'mailed' => get_string('privacy:metadata:mailed', 'mod_assign'),
|
||||
'extensionduedate' => get_string('extensionduedate', 'mod_assign'),
|
||||
'workflowstate' => get_string('markingworkflowstate', 'mod_assign'),
|
||||
'allocatedmarker' => get_string('allocatedmarker_help', 'mod_assign')];
|
||||
$userflags = (array)$assign->get_user_flags($userid, false);
|
||||
|
||||
foreach ($datatypes as $key => $description) {
|
||||
if (isset($userflags[$key]) && !empty($userflags[$key])) {
|
||||
$value = $userflags[$key];
|
||||
if ($key == 'locked' || $key == 'mailed') {
|
||||
$value = transform::yesno($value);
|
||||
} else if ($key == 'extensionduedate') {
|
||||
$value = transform::datetime($value);
|
||||
}
|
||||
writer::with_context($context)->export_metadata([], $key, $value, $description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and then exports the user's grade data.
|
||||
*
|
||||
* @param \stdClass $grade The assign grade object
|
||||
* @param \context $context The context object
|
||||
* @param array $currentpath Current directory path that we are exporting to.
|
||||
*/
|
||||
protected static function export_grade_data(\stdClass $grade, \context $context, array $currentpath) {
|
||||
$gradedata = (object)[
|
||||
'timecreated' => transform::datetime($grade->timecreated),
|
||||
'timemodified' => transform::datetime($grade->timemodified),
|
||||
'grader' => transform::user($grade->grader),
|
||||
'grade' => $grade->grade,
|
||||
'attemptnumber' => $grade->attemptnumber
|
||||
];
|
||||
writer::with_context($context)
|
||||
->export_data(array_merge($currentpath, [get_string('privacy:gradepath', 'mod_assign')]), $gradedata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats and then exports the user's submission data.
|
||||
*
|
||||
* @param \stdClass $submission The assign submission object
|
||||
* @param \context $context The context object
|
||||
* @param array $currentpath Current directory path that we are exporting to.
|
||||
*/
|
||||
protected static function export_submission_data(\stdClass $submission, \context $context, array $currentpath) {
|
||||
$submissiondata = (object)[
|
||||
'timecreated' => transform::datetime($submission->timecreated),
|
||||
'timemodified' => transform::datetime($submission->timemodified),
|
||||
'status' => get_string('submissionstatus_' . $submission->status, 'mod_assign'),
|
||||
'groupid' => $submission->groupid,
|
||||
'attemptnumber' => $submission->attemptnumber,
|
||||
'latest' => transform::yesno($submission->latest)
|
||||
];
|
||||
writer::with_context($context)
|
||||
->export_data(array_merge($currentpath, [get_string('privacy:submissionpath', 'mod_assign')]), $submissiondata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the user preferences related to mod_assign.
|
||||
*
|
||||
* @param int $userid The user ID that we want the preferences for.
|
||||
*/
|
||||
public static function export_user_preferences(int $userid) {
|
||||
$context = \context_system::instance();
|
||||
$assignpreferences = [
|
||||
'assign_perpage' => ['string' => get_string('privacy:metadata:assignperpage', 'mod_assign'), 'bool' => false],
|
||||
'assign_filter' => ['string' => get_string('privacy:metadata:assignfilter', 'mod_assign'), 'bool' => false],
|
||||
'assign_markerfilter' => ['string' => get_string('privacy:metadata:assignmarkerfilter', 'mod_assign'), 'bool' => true],
|
||||
'assign_workflowfilter' => ['string' => get_string('privacy:metadata:assignworkflowfilter', 'mod_assign'),
|
||||
'bool' => true],
|
||||
'assign_quickgrading' => ['string' => get_string('privacy:metadata:assignquickgrading', 'mod_assign'), 'bool' => true],
|
||||
'assign_downloadasfolders' => ['string' => get_string('privacy:metadata:assigndownloadasfolders', 'mod_assign'),
|
||||
'bool' => true]
|
||||
];
|
||||
foreach ($assignpreferences as $key => $preference) {
|
||||
$value = get_user_preferences($key, null, $userid);
|
||||
if ($preference['bool']) {
|
||||
$value = transform::yesno($value);
|
||||
}
|
||||
if (isset($value)) {
|
||||
writer::with_context($context)->export_user_preference('mod_assign', $key, $value, $preference['string']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export overrides for this assignment.
|
||||
*
|
||||
* @param \context $context Context
|
||||
* @param \assign $assign The assign object.
|
||||
* @param \stdClass $user The user object.
|
||||
*/
|
||||
public static function export_overrides(\context $context, \assign $assign, \stdClass $user) {
|
||||
|
||||
$overrides = $assign->override_exists($user->id);
|
||||
// Overrides returns an array with data in it, but an override with actual data will have the assign ID set.
|
||||
if (isset($overrides->assignid)) {
|
||||
$data = new \stdClass();
|
||||
if (!empty($overrides->duedate)) {
|
||||
$data->duedate = transform::datetime($overrides->duedate);
|
||||
}
|
||||
if (!empty($overrides->cutoffdate)) {
|
||||
$overrides->cutoffdate = transform::datetime($overrides->cutoffdate);
|
||||
}
|
||||
if (!empty($overrides->allowsubmissionsfromdate)) {
|
||||
$overrides->allowsubmissionsfromdate = transform::datetime($overrides->allowsubmissionsfromdate);
|
||||
}
|
||||
if (!empty($data)) {
|
||||
writer::with_context($context)->export_data([get_string('overrides', 'mod_assign')], $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports assignment submission data for a user.
|
||||
*
|
||||
* @param \assign $assign The assignment object
|
||||
* @param \stdClass $user The user object
|
||||
* @param \context_module $context The context
|
||||
* @param array $path The path for exporting data
|
||||
* @param bool|boolean $exportforteacher A flag for if this is exporting data as a teacher.
|
||||
*/
|
||||
protected static function export_submission(\assign $assign, \stdClass $user, \context_module $context, array $path,
|
||||
bool $exportforteacher = false) {
|
||||
$submissions = $assign->get_all_submissions($user->id);
|
||||
$teacher = ($exportforteacher) ? $user : null;
|
||||
foreach ($submissions as $submission) {
|
||||
// Attempt numbers start at zero, which is fine for programming, but doesn't make as much sense
|
||||
// for users.
|
||||
$submissionpath = array_merge($path,
|
||||
[get_string('privacy:attemptpath', 'mod_assign', ($submission->attemptnumber + 1))]);
|
||||
|
||||
$params = new assign_plugin_request_data($context, $assign, $submission, $submissionpath ,$teacher);
|
||||
manager::plugintype_class_callback('assignsubmission', self::ASSIGNSUBMISSION_INTERFACE,
|
||||
'export_submission_user_data', [$params]);
|
||||
if (!isset($teacher)) {
|
||||
self::export_submission_data($submission, $context, $submissionpath);
|
||||
}
|
||||
$grade = $assign->get_user_grade($user->id, false, $submission->attemptnumber);
|
||||
if ($grade) {
|
||||
$params = new assign_plugin_request_data($context, $assign, $grade, $submissionpath, $teacher);
|
||||
manager::plugintype_class_callback('assignfeedback', self::ASSIGNFEEDBACK_INTERFACE, 'export_feedback_user_data',
|
||||
[$params]);
|
||||
|
||||
self::export_grade_data($grade, $context, $submissionpath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
101
mod/assign/classes/privacy/submission_legacy_polyfill.php
Normal file
101
mod/assign/classes/privacy/submission_legacy_polyfill.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This file contains the polyfill to allow a plugin to operate with Moodle 3.3 up.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_assign\privacy;
|
||||
|
||||
use core_privacy\local\request\contextlist;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The trait used to provide backwards compatability for third-party plugins.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
trait submission_legacy_polyfill {
|
||||
|
||||
/**
|
||||
* Retrieves the contextids associated with the provided userid for this subplugin.
|
||||
* NOTE if your subplugin must have an entry in the assign_submission table to work, then this
|
||||
* method can be empty.
|
||||
*
|
||||
* @param int $userid The user ID to get context IDs for.
|
||||
* @param \core_privacy\local\request\contextlist $contextlist Use add_from_sql with this object to add your context IDs.
|
||||
*/
|
||||
public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) {
|
||||
return static::_get_context_for_userid_within_submission($userid, $contextlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns student user ids related to the provided teacher ID. If it is possible that a student ID will not be returned by
|
||||
* the sql query in \mod_assign\privacy\provider::find_grader_info() Then you need to provide some sql to retrive those
|
||||
* student IDs. This is highly likely if you had to fill in get_context_for_userid_within_submission above.
|
||||
*
|
||||
* @param useridlist $useridlist A user ID list object that you can append your user IDs to.
|
||||
*/
|
||||
public static function get_student_user_ids(useridlist $useridlist) {
|
||||
return static::_get_student_user_ids($useridlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to export any user data this sub-plugin has using the assign_plugin_request_data object to get the
|
||||
* context and userid.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - submission object
|
||||
* - current path (subcontext)
|
||||
* - user object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Information to use to export user data for this sub-plugin.
|
||||
*/
|
||||
public static function export_submission_user_data(assign_plugin_request_data $exportdata) {
|
||||
return static::_export_submission_user_data($exportdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Information to use to delete user data for this submission.
|
||||
*/
|
||||
public static function delete_submission_for_context(assign_plugin_request_data $requestdata) {
|
||||
return static::_delete_submission_for_context($requestdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method should delete user data (where practicle) from the userid and context.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - submission object
|
||||
* - user object
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Details about the user and context to focus the deletion.
|
||||
*/
|
||||
public static function delete_submission_for_userid(assign_plugin_request_data $exportdata) {
|
||||
return static::_delete_submission_for_userid($exportdata);
|
||||
}
|
||||
}
|
99
mod/assign/classes/privacy/useridlist.php
Normal file
99
mod/assign/classes/privacy/useridlist.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This file contains the mod_assign useridlist
|
||||
*
|
||||
* This is for collecting a list of user IDs
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
*
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace mod_assign\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* An object for collecting user IDs related to a teacher.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class useridlist {
|
||||
|
||||
/** @var int The ID of the teacher. */
|
||||
protected $teacherid;
|
||||
|
||||
/** @var int The ID of the assignment object. */
|
||||
protected $assignid;
|
||||
|
||||
/** @var array A collection of user IDs (students). */
|
||||
protected $userids = [];
|
||||
|
||||
/**
|
||||
* Create this object.
|
||||
*
|
||||
* @param int $teacherid The teacher ID.
|
||||
* @param int $assignid The assignment ID.
|
||||
*/
|
||||
public function __construct($teacherid, $assignid) {
|
||||
$this->teacherid = $teacherid;
|
||||
$this->assignid = $assignid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the teacher ID.
|
||||
*
|
||||
* @return int The teacher ID.
|
||||
*/
|
||||
public function get_teacherid() {
|
||||
return $this->teacherid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the assign ID.
|
||||
*
|
||||
* @return int The assign ID.
|
||||
*/
|
||||
public function get_assignid() {
|
||||
return $this->assignid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user IDs.
|
||||
*
|
||||
* @return array User IDs.
|
||||
*/
|
||||
public function get_userids() {
|
||||
return $this->userids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add sql and params to return user IDs.
|
||||
*
|
||||
* @param string $sql The sql string to return user IDs.
|
||||
* @param array $params Parameters for the sql statement.
|
||||
*/
|
||||
public function add_from_sql($sql, $params) {
|
||||
global $DB;
|
||||
$userids = $DB->get_records_sql($sql, $params);
|
||||
if (!empty($userids)) {
|
||||
$this->userids = array_merge($this->userids, $userids);
|
||||
}
|
||||
}
|
||||
}
|
125
mod/assign/feedback/comments/classes/privacy/provider.php
Normal file
125
mod/assign/feedback/comments/classes/privacy/provider.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_comments
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace assignfeedback_comments\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\metadata\provider as metadataprovider;
|
||||
use \mod_assign\privacy\assignfeedback_provider;
|
||||
use \core_privacy\local\request\writer;
|
||||
use \core_privacy\local\request\contextlist;
|
||||
use \mod_assign\privacy\assign_plugin_request_data;
|
||||
use \mod_assign\privacy\useridlist;
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_comments
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements metadataprovider, assignfeedback_provider {
|
||||
|
||||
/**
|
||||
* Return meta data about this plugin.
|
||||
*
|
||||
* @param collection $collection A list of information to add to.
|
||||
* @return collection Return the collection after adding to it.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$data = [
|
||||
'assignment' => 'privacy:metadata:assignmentid',
|
||||
'grade' => 'privacy:metadata:gradepurpose',
|
||||
'commenttext' => 'privacy:metadata:commentpurpose'
|
||||
];
|
||||
$collection->add_database_table('assignfeedback_comments', $data, 'privacy:metadata:tablesummary');
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* No need to fill in this method as all information can be acquired from the assign_grades table in the mod assign
|
||||
* provider.
|
||||
*
|
||||
* @param int $userid The user ID.
|
||||
* @param contextlist $contextlist The context list.
|
||||
*/
|
||||
public static function get_context_for_userid_within_feedback(int $userid, contextlist $contextlist) {
|
||||
// This uses the assign_grades table.
|
||||
}
|
||||
|
||||
/**
|
||||
* This also does not need to be filled in as this is already collected in the mod assign provider.
|
||||
*
|
||||
* @param useridlist $useridlist A list of user IDs
|
||||
*/
|
||||
public static function get_student_user_ids(useridlist $useridlist) {
|
||||
// Not required.
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for this plugin.
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful
|
||||
* information to help with exporting.
|
||||
*/
|
||||
public static function export_feedback_user_data(assign_plugin_request_data $exportdata) {
|
||||
// Get that comment information and jam it into that exporter.
|
||||
$assign = $exportdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'comments');
|
||||
$comments = $plugin->get_feedback_comments($exportdata->get_pluginobject()->id);
|
||||
if ($comments && !empty($comments->commenttext)) {
|
||||
$data = (object)['commenttext' => format_text($comments->commenttext, $comments->commentformat,
|
||||
['context' => $exportdata->get_context()])];
|
||||
writer::with_context($exportdata->get_context())
|
||||
->export_data(array_merge($exportdata->get_subcontext(),
|
||||
[get_string('privacy:commentpath', 'assignfeedback_comments')]), $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function delete_feedback_for_context(assign_plugin_request_data $requestdata) {
|
||||
$assign = $requestdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'comments');
|
||||
$plugin->delete_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this function should delete all user data associated with this grade entry.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data.
|
||||
*/
|
||||
public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata) {
|
||||
global $DB;
|
||||
$DB->delete_records('assignfeedback_comments', ['assignment' => $requestdata->get_assign()->get_instance()->id,
|
||||
'grade' => $requestdata->get_pluginobject()->id]);
|
||||
}
|
||||
}
|
@ -22,14 +22,17 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
$string['default'] = 'Enabled by default';
|
||||
$string['default_help'] = 'If set, this feedback method will be enabled by default for all new assignments.';
|
||||
$string['enabled'] = 'Feedback comments';
|
||||
$string['enabled_help'] = 'If enabled, the marker can leave feedback comments for each submission. ';
|
||||
$string['pluginname'] = 'Feedback comments';
|
||||
$string['privacy:commentpath'] = 'Feedback comments';
|
||||
$string['privacy:metadata:assignmentid'] = 'Assignment identifier';
|
||||
$string['privacy:metadata:commentpurpose'] = 'The comment text.';
|
||||
$string['privacy:metadata:gradepurpose'] = 'The grade ID associated with the comment.';
|
||||
$string['privacy:metadata:tablesummary'] = 'This stores comments made by the graders as feedback for the student on their submission.';
|
||||
$string['commentinline'] = 'Comment inline';
|
||||
$string['commentinline_help'] = 'If enabled, the submission text will be copied into the feedback comment field during grading, making it easier to comment inline (using a different colour, perhaps) or to edit the original text.';
|
||||
$string['commentinlinedefault'] = 'Comment inline by default';
|
||||
$string['commentinlinedefault_help'] = 'If set, this comment inline functionality will be enabled by default for all new assignments.';
|
||||
|
||||
|
203
mod/assign/feedback/comments/tests/privacy_test.php
Normal file
203
mod/assign/feedback/comments/tests/privacy_test.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for assignfeedback_comments.
|
||||
*
|
||||
* @package assignfeedback_comments
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
require_once($CFG->dirroot . '/mod/assign/tests/privacy_test.php');
|
||||
|
||||
/**
|
||||
* Unit tests for mod/assign/feedback/comments/classes/privacy/
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignfeedback_comments_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
|
||||
|
||||
/**
|
||||
* Convenience function for creating feedback data.
|
||||
*
|
||||
* @param object $assign assign object
|
||||
* @param stdClass $student user object
|
||||
* @param stdClass $teacher user object
|
||||
* @param string $submissiontext Submission text
|
||||
* @param string $feedbacktext Feedback text
|
||||
* @return array Feedback plugin object and the grade object.
|
||||
*/
|
||||
protected function create_feedback($assign, $student, $teacher, $submissiontext, $feedbacktext) {
|
||||
$submission = new \stdClass();
|
||||
$submission->assignment = $assign->get_instance()->id;
|
||||
$submission->userid = $student->id;
|
||||
$submission->timecreated = time();
|
||||
$submission->onlinetext_editor = ['text' => $submissiontext,
|
||||
'format' => FORMAT_MOODLE];
|
||||
|
||||
$this->setUser($student);
|
||||
$notices = [];
|
||||
$assign->save_submission($submission, $notices);
|
||||
|
||||
$grade = $assign->get_user_grade($student->id, true);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$plugin = $assign->get_feedback_plugin_by_type('comments');
|
||||
$feedbackdata = new \stdClass();
|
||||
$feedbackdata->assignfeedbackcomments_editor = [
|
||||
'text' => $feedbacktext,
|
||||
'format' => 1
|
||||
];
|
||||
|
||||
$plugin->save($grade, $feedbackdata);
|
||||
return [$plugin, $grade];
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick test to make sure that get_metadata returns something.
|
||||
*/
|
||||
public function test_get_metadata() {
|
||||
$collection = new \core_privacy\local\metadata\collection('assignfeedback_comments');
|
||||
$collection = \assignfeedback_comments\privacy\provider::get_metadata($collection);
|
||||
$this->assertNotEmpty($collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that feedback comments are exported for a user.
|
||||
*/
|
||||
public function test_export_feedback_user_data() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$feedbacktext = '<p>first comment for this test</p>';
|
||||
list($plugin, $grade) = $this->create_feedback($assign, $user1, $user2, 'Submission text', $feedbacktext);
|
||||
|
||||
$writer = \core_privacy\local\request\writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should be able to see the teachers feedback.
|
||||
$exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $grade, [], $user1);
|
||||
\assignfeedback_comments\privacy\provider::export_feedback_user_data($exportdata);
|
||||
$this->assertEquals($feedbacktext, $writer->get_data(['Feedback comments'])->commenttext);
|
||||
|
||||
// The teacher should also be able to see the feedback that they provided.
|
||||
$exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $grade, [], $user2);
|
||||
\assignfeedback_comments\privacy\provider::export_feedback_user_data($exportdata);
|
||||
$this->assertEquals($feedbacktext, $writer->get_data(['Feedback comments'])->commenttext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that all feedback is deleted for a context.
|
||||
*/
|
||||
public function test_delete_feedback_for_context() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$feedbacktext = '<p>first comment for this test</p>';
|
||||
list($plugin1, $grade1) = $this->create_feedback($assign, $user1, $user3, 'Submission text', $feedbacktext);
|
||||
$feedbacktext = '<p>Comment for second student.</p>';
|
||||
list($plugin2, $grade2) = $this->create_feedback($assign, $user2, $user3, 'Submission text', $feedbacktext);
|
||||
|
||||
// Check that we have data.
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade1->id);
|
||||
$this->assertNotEmpty($feedbackcomments);
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade2->id);
|
||||
$this->assertNotEmpty($feedbackcomments);
|
||||
|
||||
// Delete all comments for this context.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
|
||||
assignfeedback_comments\privacy\provider::delete_feedback_for_context($requestdata);
|
||||
|
||||
// Check that the data is now gone.
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade1->id);
|
||||
$this->assertEmpty($feedbackcomments);
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade2->id);
|
||||
$this->assertEmpty($feedbackcomments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a grade item is deleted for a user.
|
||||
*/
|
||||
public function test_delete_feedback_for_grade() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$feedbacktext = '<p>first comment for this test</p>';
|
||||
list($plugin1, $grade1) = $this->create_feedback($assign, $user1, $user3, 'Submission text', $feedbacktext);
|
||||
$feedbacktext = '<p>Comment for second student.</p>';
|
||||
list($plugin2, $grade2) = $this->create_feedback($assign, $user2, $user3, 'Submission text', $feedbacktext);
|
||||
|
||||
// Check that we have data.
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade1->id);
|
||||
$this->assertNotEmpty($feedbackcomments);
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade2->id);
|
||||
$this->assertNotEmpty($feedbackcomments);
|
||||
|
||||
// Delete all comments for this grade object.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $grade1, [], $user1);
|
||||
assignfeedback_comments\privacy\provider::delete_feedback_for_grade($requestdata);
|
||||
|
||||
// These comments should be empty.
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade1->id);
|
||||
$this->assertEmpty($feedbackcomments);
|
||||
|
||||
// These comments should not.
|
||||
$feedbackcomments = $plugin1->get_feedback_comments($grade2->id);
|
||||
$this->assertNotEmpty($feedbackcomments);
|
||||
}
|
||||
}
|
147
mod/assign/feedback/editpdf/classes/privacy/provider.php
Normal file
147
mod/assign/feedback/editpdf/classes/privacy/provider.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_editpdf
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace assignfeedback_editpdf\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\metadata\provider as metadataprovider;
|
||||
use \mod_assign\privacy\assignfeedback_provider;
|
||||
use \core_privacy\local\request\writer;
|
||||
use \core_privacy\local\request\contextlist;
|
||||
use \mod_assign\privacy\assign_plugin_request_data;
|
||||
use \mod_assign\privacy\useridlist;
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_editpdf
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements metadataprovider, assignfeedback_provider {
|
||||
|
||||
/**
|
||||
* Return meta data about this plugin.
|
||||
*
|
||||
* @param collection $collection A list of information to add to.
|
||||
* @return collection Return the collection after adding to it.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$quickdata = [
|
||||
'userid' => 'privacy:metadata:userid',
|
||||
'rawtext' => 'privacy:metadata:rawtextpurpose',
|
||||
'colour' => 'privacy:metadata:colourpurpose'
|
||||
];
|
||||
$collection->add_database_table('assignfeedback_editpdf_quick', $quickdata, 'privacy:metadata:tablepurpose');
|
||||
$collection->add_subsystem_link('core_files', [], 'privacy:metadata:filepurpose');
|
||||
$collection->add_subsystem_link('core_fileconverted', [], 'privacy:metadata:conversionpurpose');
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* No need to fill in this method as all information can be acquired from the assign_grades table in the mod assign
|
||||
* provider.
|
||||
*
|
||||
* @param int $userid The user ID.
|
||||
* @param contextlist $contextlist The context list.
|
||||
*/
|
||||
public static function get_context_for_userid_within_feedback(int $userid, contextlist $contextlist) {
|
||||
// This uses the assign_grade table.
|
||||
}
|
||||
|
||||
/**
|
||||
* This also does not need to be filled in as this is already collected in the mod assign provider.
|
||||
*
|
||||
* @param useridlist $useridlist A list of user IDs
|
||||
*/
|
||||
public static function get_student_user_ids(useridlist $useridlist) {
|
||||
// Not required.
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for this plugin.
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful
|
||||
* information to help with exporting.
|
||||
*/
|
||||
public static function export_feedback_user_data(assign_plugin_request_data $exportdata) {
|
||||
$currentpath = $exportdata->get_subcontext();
|
||||
$currentpath[] = get_string('privacy:path', 'assignfeedback_editpdf');
|
||||
$assign = $exportdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'editpdf');
|
||||
$fileareas = $plugin->get_file_areas();
|
||||
$grade = $exportdata->get_pluginobject();
|
||||
foreach ($fileareas as $filearea => $notused) {
|
||||
writer::with_context($exportdata->get_context())
|
||||
->export_area_files($currentpath, 'assignfeedback_editpdf', $filearea, $grade->id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function delete_feedback_for_context(assign_plugin_request_data $requestdata) {
|
||||
|
||||
$assign = $requestdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'editpdf');
|
||||
$fileareas = $plugin->get_file_areas();
|
||||
$fs = get_file_storage();
|
||||
foreach ($fileareas as $filearea => $notused) {
|
||||
// Delete pdf files.
|
||||
$fs->delete_area_files($requestdata->get_context()->id, 'assignfeedback_editpdf', $filearea);
|
||||
}
|
||||
// Delete entries from the tables.
|
||||
$plugin->delete_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this function should delete all user data associated with this grade.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data.
|
||||
*/
|
||||
public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata) {
|
||||
global $DB;
|
||||
|
||||
$assign = $requestdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'editpdf');
|
||||
$fileareas = $plugin->get_file_areas();
|
||||
$fs = get_file_storage();
|
||||
foreach ($fileareas as $filearea => $notused) {
|
||||
// Delete pdf files.
|
||||
$fs->delete_area_files($requestdata->get_context()->id, 'assignfeedback_editpdf',
|
||||
$filearea, $requestdata->get_pluginobject()->id);
|
||||
}
|
||||
|
||||
// Remove table entries.
|
||||
$DB->delete_records('assignfeedback_editpdf_annot', ['gradeid' => $requestdata->get_pluginobject()->id]);
|
||||
$DB->delete_records('assignfeedback_editpdf_cmnt', ['gradeid' => $requestdata->get_pluginobject()->id]);
|
||||
// Submission records in assignfeedback_editpdf_queue will be cleaned up in a scheduled task
|
||||
}
|
||||
}
|
@ -73,6 +73,13 @@ $string['pagenumber'] = 'Page {$a}';
|
||||
$string['pagexofy'] = 'Page {$a->page} of {$a->total}';
|
||||
$string['pen'] = 'Pen';
|
||||
$string['pluginname'] = 'Annotate PDF';
|
||||
$string['privacy:metadata:colourpurpose'] = 'Colour of the comment or annotation';
|
||||
$string['privacy:metadata:conversionpurpose'] = 'Files are converted to PDFs to allow for annotations.';
|
||||
$string['privacy:metadata:filepurpose'] = 'Stores an annotated PDF with feedback for the user.';
|
||||
$string['privacy:metadata:rawtextpurpose'] = 'Stores raw text for the quick data.';
|
||||
$string['privacy:metadata:tablepurpose'] = 'Stores teacher specified quicklist comments';
|
||||
$string['privacy:metadata:userid'] = 'An identifier for the user.';
|
||||
$string['privacy:path'] = 'PDF Feedback';
|
||||
$string['generatingpdf'] = 'Generating the PDF...';
|
||||
$string['rectangle'] = 'Rectangle';
|
||||
$string['red'] = 'Red';
|
||||
|
244
mod/assign/feedback/editpdf/tests/privacy_test.php
Normal file
244
mod/assign/feedback/editpdf/tests/privacy_test.php
Normal file
@ -0,0 +1,244 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for assignfeedback_editpdf.
|
||||
*
|
||||
* @package assignfeedback_editpdf
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
require_once($CFG->dirroot . '/mod/assign/tests/privacy_test.php');
|
||||
|
||||
use \assignfeedback_editpdf\page_editor;
|
||||
use \mod_assign\privacy\assign_plugin_request_data;
|
||||
|
||||
/**
|
||||
* Unit tests for mod/assign/feedback/editpdf/classes/privacy/
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignfeedback_editpdf_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
|
||||
|
||||
public function setUp() {
|
||||
// Skip this test if ghostscript is not supported.
|
||||
$result = \assignfeedback_editpdf\pdf::test_gs_path(false);
|
||||
if ($result->status !== \assignfeedback_editpdf\pdf::GSPATH_OK) {
|
||||
$this->markTestSkipped('Ghostscript not setup');
|
||||
return;
|
||||
}
|
||||
parent::setUp();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function for creating feedback data.
|
||||
*
|
||||
* @param object $assign assign object
|
||||
* @param stdClass $student user object
|
||||
* @param stdClass $teacher user object
|
||||
* @return array Feedback plugin object and the grade object.
|
||||
*/
|
||||
protected function create_feedback($assign, $student, $teacher) {
|
||||
global $CFG;
|
||||
|
||||
// Create a file submission with the test pdf.
|
||||
$submission = $assign->get_user_submission($student->id, true);
|
||||
|
||||
$this->setUser($student->id);
|
||||
|
||||
$fs = get_file_storage();
|
||||
$pdfsubmission = (object) array(
|
||||
'contextid' => $assign->get_context()->id,
|
||||
'component' => 'assignsubmission_file',
|
||||
'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
|
||||
'itemid' => $submission->id,
|
||||
'filepath' => '/',
|
||||
'filename' => 'submission.pdf'
|
||||
);
|
||||
$sourcefile = $CFG->dirroot.'/mod/assign/feedback/editpdf/tests/fixtures/submission.pdf';
|
||||
$fi = $fs->create_file_from_pathname($pdfsubmission, $sourcefile);
|
||||
|
||||
$data = new \stdClass();
|
||||
$plugin = $assign->get_submission_plugin_by_type('file');
|
||||
$plugin->save($submission, $data);
|
||||
|
||||
$this->setUser($teacher->id);
|
||||
|
||||
$plugin = $assign->get_feedback_plugin_by_type('editpdf');
|
||||
|
||||
$grade = $assign->get_user_grade($student->id, true);
|
||||
|
||||
$comment = new \assignfeedback_editpdf\comment();
|
||||
|
||||
$comment->rawtext = 'Comment text';
|
||||
$comment->width = 100;
|
||||
$comment->x = 100;
|
||||
$comment->y = 100;
|
||||
$comment->colour = 'red';
|
||||
page_editor::set_comments($grade->id, 0, [$comment]);
|
||||
|
||||
$annotation = new \assignfeedback_editpdf\annotation();
|
||||
|
||||
$annotation->path = '';
|
||||
$annotation->x = 100;
|
||||
$annotation->y = 100;
|
||||
$annotation->endx = 200;
|
||||
$annotation->endy = 200;
|
||||
$annotation->type = 'line';
|
||||
$annotation->colour = 'red';
|
||||
|
||||
page_editor::set_annotations($grade->id, 0, [$annotation]);
|
||||
|
||||
$comments = page_editor::get_comments($grade->id, 0, true);
|
||||
$annotations = page_editor::get_annotations($grade->id, 0, false);
|
||||
page_editor::release_drafts($grade->id);
|
||||
$storedfile = \assignfeedback_editpdf\document_services::generate_feedback_document($assign->get_instance()->id, $student->id,
|
||||
$grade->attemptnumber);
|
||||
|
||||
return [$plugin, $grade, $storedfile];
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick test to make sure that get_metadata returns something.
|
||||
*/
|
||||
public function test_get_metadata() {
|
||||
$collection = new \core_privacy\local\metadata\collection('assignfeedback_editpdf');
|
||||
$collection = \assignfeedback_editpdf\privacy\provider::get_metadata($collection);
|
||||
$this->assertNotEmpty($collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that feedback comments are exported for a user.
|
||||
*/
|
||||
public function test_export_feedback_user_data() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course,
|
||||
'assignsubmission_file_enabled' => 1,
|
||||
'assignsubmission_file_maxfiles' => 1,
|
||||
'assignfeedback_editpdf_enabled' => 1,
|
||||
'assignsubmission_file_maxsizebytes' => 1000000]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
list($plugin, $grade, $storedfile) = $this->create_feedback($assign, $user1, $user2);
|
||||
|
||||
// Check that we have data.
|
||||
$this->assertFalse($plugin->is_empty($grade));
|
||||
|
||||
$writer = \core_privacy\local\request\writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should be able to see the teachers feedback.
|
||||
$exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $grade, [], $user1);
|
||||
\assignfeedback_editpdf\privacy\provider::export_feedback_user_data($exportdata);
|
||||
// print_object($writer->get_files([get_string('privacy:path', 'assignfeedback_editpdf')]));
|
||||
// print_object($writer->get_files(['PDF feedback', $storedfile->get_filename()]));
|
||||
$pdffile = $writer->get_files([get_string('privacy:path', 'assignfeedback_editpdf')])[$storedfile->get_filename()];
|
||||
// The writer should have returned a stored file.
|
||||
$this->assertInstanceOf('stored_file', $pdffile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that all feedback is deleted for a context.
|
||||
*/
|
||||
public function test_delete_feedback_for_context() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Students.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course,
|
||||
'assignsubmission_file_enabled' => 1,
|
||||
'assignsubmission_file_maxfiles' => 1,
|
||||
'assignfeedback_editpdf_enabled' => 1,
|
||||
'assignsubmission_file_maxsizebytes' => 1000000]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
list($plugin1, $grade1, $storedfile1) = $this->create_feedback($assign, $user1, $user3);
|
||||
list($plugin2, $grade2, $storedfile2) = $this->create_feedback($assign, $user2, $user3);
|
||||
|
||||
// Check that we have data.
|
||||
$this->assertFalse($plugin1->is_empty($grade1));
|
||||
$this->assertFalse($plugin2->is_empty($grade2));
|
||||
|
||||
$requestdata = new assign_plugin_request_data($context, $assign);
|
||||
\assignfeedback_editpdf\privacy\provider::delete_feedback_for_context($requestdata);
|
||||
|
||||
// Check that we now have no data.
|
||||
$this->assertTrue($plugin1->is_empty($grade1));
|
||||
$this->assertTrue($plugin2->is_empty($grade2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a grade item is deleted for a user.
|
||||
*/
|
||||
public function test_delete_feedback_for_grade() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Students.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course,
|
||||
'assignsubmission_file_enabled' => 1,
|
||||
'assignsubmission_file_maxfiles' => 1,
|
||||
'assignfeedback_editpdf_enabled' => 1,
|
||||
'assignsubmission_file_maxsizebytes' => 1000000]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
list($plugin1, $grade1, $storedfile1) = $this->create_feedback($assign, $user1, $user3);
|
||||
list($plugin2, $grade2, $storedfile2) = $this->create_feedback($assign, $user2, $user3);
|
||||
|
||||
// Check that we have data.
|
||||
$this->assertFalse($plugin1->is_empty($grade1));
|
||||
$this->assertFalse($plugin2->is_empty($grade2));
|
||||
|
||||
$requestdata = new assign_plugin_request_data($context, $assign, $grade1, [], $user1);
|
||||
\assignfeedback_editpdf\privacy\provider::delete_feedback_for_grade($requestdata);
|
||||
|
||||
// Check that we now have no data for user 1.
|
||||
$this->assertTrue($plugin1->is_empty($grade1));
|
||||
// Check that user 2 data is still there.
|
||||
$this->assertFalse($plugin2->is_empty($grade2));
|
||||
}
|
||||
}
|
140
mod/assign/feedback/file/classes/privacy/provider.php
Normal file
140
mod/assign/feedback/file/classes/privacy/provider.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_file
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace assignfeedback_file\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\metadata\provider as metadataprovider;
|
||||
use core_privacy\local\request\contextlist;
|
||||
use \mod_assign\privacy\assignfeedback_provider;
|
||||
use \mod_assign\privacy\assign_plugin_request_data;
|
||||
use mod_assign\privacy\useridlist;
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_file
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements metadataprovider, assignfeedback_provider {
|
||||
|
||||
/**
|
||||
* Return meta data about this plugin.
|
||||
*
|
||||
* @param collection $collection A list of information to add to.
|
||||
* @return collection Return the collection after adding to it.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$collection->link_subsystem('core_files', 'privacy:metadata:filepurpose');
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* No need to fill in this method as all information can be acquired from the assign_grades table in the mod assign
|
||||
* provider.
|
||||
*
|
||||
* @param int $userid The user ID.
|
||||
* @param contextlist $contextlist The context list.
|
||||
*/
|
||||
public static function get_context_for_userid_within_feedback(int $userid, contextlist $contextlist) {
|
||||
// This uses the assign_grade table.
|
||||
}
|
||||
|
||||
/**
|
||||
* This also does not need to be filled in as this is already collected in the mod assign provider.
|
||||
*
|
||||
* @param useridlist $useridlist A list of user IDs
|
||||
*/
|
||||
public static function get_student_user_ids(useridlist $useridlist) {
|
||||
// Not required.
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for this plugin.
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful
|
||||
* information to help with exporting.
|
||||
*/
|
||||
public static function export_feedback_user_data(assign_plugin_request_data $exportdata) {
|
||||
$currentpath = $exportdata->get_subcontext();
|
||||
$currentpath[] = get_string('privacy:path', 'assignfeedback_file');
|
||||
$assign = $exportdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'file');
|
||||
$gradeid = $exportdata->get_pluginobject()->id;
|
||||
$filefeedback = $plugin->get_file_feedback($gradeid);
|
||||
if ($filefeedback) {
|
||||
$fileareas = $plugin->get_file_areas();
|
||||
foreach ($fileareas as $filearea => $notused) {
|
||||
\core_privacy\local\request\writer::with_context($exportdata->get_context())
|
||||
->export_area_files($currentpath, 'assignfeedback_file', $filearea, $gradeid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function delete_feedback_for_context(assign_plugin_request_data $requestdata) {
|
||||
|
||||
$assign = $requestdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'file');
|
||||
$fileareas = $plugin->get_file_areas();
|
||||
$fs = get_file_storage();
|
||||
foreach ($fileareas as $filearea => $notused) {
|
||||
// Delete feedback files.
|
||||
$fs->delete_area_files($requestdata->get_context()->id, 'assignfeedback_file', $filearea);
|
||||
}
|
||||
$plugin->delete_instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this function should delete all user data associated with this grade.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data.
|
||||
*/
|
||||
public static function delete_feedback_for_grade(assign_plugin_request_data $requestdata) {
|
||||
global $DB;
|
||||
|
||||
$assign = $requestdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignfeedback', 'file');
|
||||
$fileareas = $plugin->get_file_areas();
|
||||
$fs = get_file_storage();
|
||||
foreach ($fileareas as $filearea => $notused) {
|
||||
// Delete feedback files.
|
||||
$fs->delete_area_files($requestdata->get_context()->id, 'assignfeedback_file', $filearea,
|
||||
$requestdata->get_pluginobject()->id);
|
||||
}
|
||||
|
||||
// Delete table entries.
|
||||
$DB->delete_records('assignfeedback_file', ['assignment' => $requestdata->get_assign()->get_instance()->id,
|
||||
'grade' => $requestdata->get_pluginobject()->id]);
|
||||
}
|
||||
}
|
@ -37,6 +37,8 @@ $string['feedbackfileadded'] = 'New feedback file "{$a->filename}" for student "
|
||||
$string['feedbackfileupdated'] = 'Modified feedback file "{$a->filename}" for student "{$a->student}"';
|
||||
$string['feedbackzip_help'] = 'A zip file containing a list of feedback files for one or more students. Feedback files will be assigned to students based on the participant id which should be the second part of each filename immediately after the users full name. This naming convention is used when downloading submissions so you can download all submissions, add comments to a few files and then rezip and upload all of the files. Files with no changes will be ignored.';
|
||||
$string['file'] = 'Feedback files';
|
||||
$string['privacy:metadata:filepurpose'] = 'Feedback files from the teacher for the student.';
|
||||
$string['privacy:path'] = 'Feedback files';
|
||||
$string['filesupdated'] = 'Feedback files updated: {$a}';
|
||||
$string['filesadded'] = 'Feedback files added: {$a}';
|
||||
$string['importfeedbackfiles'] = 'Import feedback file(s)';
|
||||
|
209
mod/assign/feedback/file/tests/privacy_test.php
Normal file
209
mod/assign/feedback/file/tests/privacy_test.php
Normal file
@ -0,0 +1,209 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for assignfeedback_file.
|
||||
*
|
||||
* @package assignfeedback_file
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
require_once($CFG->dirroot . '/mod/assign/tests/privacy_test.php');
|
||||
|
||||
use mod_assign\privacy\assign_plugin_request_data;
|
||||
|
||||
/**
|
||||
* Unit tests for mod/assign/feedback/file/classes/privacy/
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignfeedback_file_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
|
||||
|
||||
/**
|
||||
* Convenience function for creating feedback data.
|
||||
*
|
||||
* @param object $assign assign object
|
||||
* @param stdClass $student user object
|
||||
* @param stdClass $teacher user object
|
||||
* @param string $submissiontext Submission text
|
||||
* @param string $feedbacktext Feedback text
|
||||
* @return array Feedback plugin object and the grade object.
|
||||
*/
|
||||
protected function create_feedback($assign, $student, $teacher, $submissiontext, $feedbacktext) {
|
||||
|
||||
$submission = new \stdClass();
|
||||
$submission->assignment = $assign->get_instance()->id;
|
||||
$submission->userid = $student->id;
|
||||
$submission->timecreated = time();
|
||||
$submission->onlinetext_editor = ['text' => $submissiontext,
|
||||
'format' => FORMAT_MOODLE];
|
||||
|
||||
$this->setUser($student);
|
||||
$notices = [];
|
||||
$assign->save_submission($submission, $notices);
|
||||
|
||||
$grade = $assign->get_user_grade($student->id, true);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$context = context_user::instance($teacher->id);
|
||||
|
||||
$draftitemid = file_get_unused_draft_itemid();
|
||||
file_prepare_draft_area($draftitemid, $context->id, 'assignfeedback_file', 'feedback_files', 1);
|
||||
|
||||
$dummy = array(
|
||||
'contextid' => $context->id,
|
||||
'component' => 'user',
|
||||
'filearea' => 'draft',
|
||||
'itemid' => $draftitemid,
|
||||
'filepath' => '/',
|
||||
'filename' => 'feedback1.txt'
|
||||
);
|
||||
|
||||
$fs = get_file_storage();
|
||||
$file = $fs->create_file_from_string($dummy, $feedbacktext);
|
||||
|
||||
// Create formdata.
|
||||
$data = new stdClass();
|
||||
$data->{'files_' . $teacher->id . '_filemanager'} = $draftitemid;
|
||||
|
||||
$plugin = $assign->get_feedback_plugin_by_type('file');
|
||||
// Save the feedback.
|
||||
$plugin->save($grade, $data);
|
||||
|
||||
return [$plugin, $grade];
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick test to make sure that get_metadata returns something.
|
||||
*/
|
||||
public function test_get_metadata() {
|
||||
$collection = new \core_privacy\local\metadata\collection('assignfeedback_file');
|
||||
$collection = \assignfeedback_file\privacy\provider::get_metadata($collection);
|
||||
$this->assertNotEmpty($collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that feedback comments are exported for a user.
|
||||
*/
|
||||
public function test_export_feedback_user_data() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$feedbacktext = '<p>first comment for this test</p>';
|
||||
list($plugin, $grade) = $this->create_feedback($assign, $user1, $user2, 'Submission text', $feedbacktext);
|
||||
|
||||
$writer = \core_privacy\local\request\writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should be able to see the teachers feedback.
|
||||
$exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $grade, [], $user1);
|
||||
\assignfeedback_file\privacy\provider::export_feedback_user_data($exportdata);
|
||||
$feedbackfile = $writer->get_files([get_string('privacy:path', 'assignfeedback_file')])['feedback1.txt'];
|
||||
// Check that we got a stored file.
|
||||
$this->assertInstanceOf('stored_file', $feedbackfile);
|
||||
$this->assertEquals('feedback1.txt', $feedbackfile->get_filename());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that all feedback is deleted for a context.
|
||||
*/
|
||||
public function test_delete_feedback_for_context() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Students.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$feedbacktext = '<p>first comment for this test</p>';
|
||||
list($plugin1, $grade1) = $this->create_feedback($assign, $user1, $user3, 'Submission text', $feedbacktext);
|
||||
$feedbacktext = '<p>Comment for second submission.</p>';
|
||||
list($plugin2, $grade2) = $this->create_feedback($assign, $user2, $user3, 'Submission text', $feedbacktext);
|
||||
|
||||
// Check that we have data.
|
||||
$this->assertFalse($plugin1->is_empty($grade1));
|
||||
$this->assertFalse($plugin2->is_empty($grade2));
|
||||
|
||||
$requestdata = new assign_plugin_request_data($context, $assign);
|
||||
\assignfeedback_file\privacy\provider::delete_feedback_for_context($requestdata);
|
||||
|
||||
// Check that we now have no data.
|
||||
$this->assertTrue($plugin1->is_empty($grade1));
|
||||
$this->assertTrue($plugin2->is_empty($grade2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a grade item is deleted for a user.
|
||||
*/
|
||||
public function test_delete_feedback_for_grade() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Students.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$feedbacktext = '<p>first comment for this test</p>';
|
||||
list($plugin1, $grade1) = $this->create_feedback($assign, $user1, $user3, 'Submission text', $feedbacktext);
|
||||
$feedbacktext = '<p>Comment for second submission.</p>';
|
||||
list($plugin2, $grade2) = $this->create_feedback($assign, $user2, $user3, 'Submission text', $feedbacktext);
|
||||
|
||||
// Check that we have data.
|
||||
$this->assertFalse($plugin1->is_empty($grade1));
|
||||
$this->assertFalse($plugin2->is_empty($grade2));
|
||||
|
||||
$requestdata = new assign_plugin_request_data($context, $assign, $grade1, [], $user1);
|
||||
\assignfeedback_file\privacy\provider::delete_feedback_for_grade($requestdata);
|
||||
|
||||
// Check that we now have no data.
|
||||
$this->assertTrue($plugin1->is_empty($grade1));
|
||||
// User 2's data should still be intact.
|
||||
$this->assertFalse($plugin2->is_empty($grade2));
|
||||
}
|
||||
}
|
47
mod/assign/feedback/offline/classes/privacy/provider.php
Normal file
47
mod/assign/feedback/offline/classes/privacy/provider.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_offline
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace assignfeedback_offline\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignfeedback_offline
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements \core_privacy\local\metadata\null_provider {
|
||||
|
||||
/**
|
||||
* Get the language string identifier with the component's language
|
||||
* file to explain why this plugin stores no data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_reason() : string {
|
||||
return 'privacy:nullproviderreason';
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ $string['importgrades'] = 'Confirm changes in grading worksheet';
|
||||
$string['invalidgradeimport'] = 'Moodle could not read the uploaded worksheet. Make sure it is saved in comma separated value format (.csv) and try again.';
|
||||
$string['gradesfile'] = 'Grading worksheet (csv format)';
|
||||
$string['gradesfile_help'] = 'Grading worksheet with modified grades. This file must be a csv file that has been downloaded from this assignment and must contain columns for the student grade, and identifier. The encoding for the file must be "UTF-8"';
|
||||
$string['privacy:nullproviderreason'] = 'This plugin has no database to store user information. It only uses APIs in mod_assign to help with displaying the grading interface.';
|
||||
$string['nochanges'] = 'No modified grades found in uploaded worksheet';
|
||||
$string['offlinegradingworksheet'] = 'Grades';
|
||||
$string['pluginname'] = 'Offline grading worksheet';
|
||||
|
@ -79,8 +79,8 @@ $string['assignmentsperpage'] = 'Assignments per page';
|
||||
$string['assignsubmission'] = 'Submission plugin';
|
||||
$string['assignsubmissionpluginname'] = 'Submission plugin';
|
||||
$string['attemptheading'] = 'Attempt {$a->attemptnumber}: {$a->submissionsummary}';
|
||||
$string['attemptnumber'] = 'Attempt number';
|
||||
$string['attempthistory'] = 'Previous attempts';
|
||||
$string['attemptnumber'] = 'Attempt number';
|
||||
$string['attemptsettings'] = 'Attempt settings';
|
||||
$string['attemptreopenmethod'] = 'Attempts reopened';
|
||||
$string['attemptreopenmethod_help'] = 'Determines how student submission attempts are reopened. The available options are: <ul><li>Never - The student submission cannot be reopened.</li><li>Manually - The student submission can be reopened by a teacher.</li><li>Automatically until pass - The student submission is automatically reopened until the student achieves the grade to pass value set in the Gradebook (Gradebook setup section) for this assignment.</li></ul>';
|
||||
@ -245,8 +245,8 @@ $string['filternone'] = 'No filter';
|
||||
$string['filternotsubmitted'] = 'Not submitted';
|
||||
$string['filterrequiregrading'] = 'Requires grading';
|
||||
$string['filtersubmitted'] = 'Submitted';
|
||||
$string['gradedby'] = 'Graded by';
|
||||
$string['graded'] = 'Graded';
|
||||
$string['gradedby'] = 'Graded by';
|
||||
$string['gradedon'] = 'Graded on';
|
||||
$string['gradebelowzero'] = 'Grade must be greater than or equal to zero.';
|
||||
$string['gradeabovemaximum'] = 'Grade must be less than or equal to {$a}.';
|
||||
@ -387,6 +387,32 @@ $string['preventsubmissionnotingroup_help'] = 'If enabled, users who are not mem
|
||||
$string['preventsubmissions'] = 'Prevent the user from making any more submissions to this assignment.';
|
||||
$string['preventsubmissionsshort'] = 'Prevent submission changes';
|
||||
$string['previous'] = 'Previous';
|
||||
$string['privacy:attemptpath'] = 'attempt {$a}';
|
||||
$string['privacy:blindmarkingidentifier'] = 'The identifier used for blind marking.';
|
||||
$string['privacy:gradepath'] = 'grade';
|
||||
$string['privacy:metadata:assigndownloadasfolders'] = 'A user preference for whether multiple file submissions should be downloaded into folders';
|
||||
$string['privacy:metadata:assignfeedbackpluginsummary'] = 'Feedback data for the assignment.';
|
||||
$string['privacy:metadata:assignfilter'] = 'Filter options such as \'Submitted\', \'Not submitted\', \'Requires grading\', and \'Granted extension\'';
|
||||
$string['privacy:metadata:assigngrades'] = 'Stores user grades for the assignment';
|
||||
$string['privacy:metadata:assignmarkerfilter'] = 'Filter the assign summary by the assigned marker.';
|
||||
$string['privacy:metadata:assignmentid'] = 'Assignment identifier.';
|
||||
$string['privacy:metadata:assignmessageexplanation'] = 'Messages are sent to students through the messaging system.';
|
||||
$string['privacy:metadata:assignoverrides'] = 'Stores override information for the assignment';
|
||||
$string['privacy:metadata:assignperpage'] = 'Number of assignments shown per page.';
|
||||
$string['privacy:metadata:assignquickgrading'] = 'A preference as to whether quick grading is used or not.';
|
||||
$string['privacy:metadata:assignsubmissiondetail'] = 'Stores user submission information';
|
||||
$string['privacy:metadata:assignsubmissionpluginsummary'] = 'Submission data for the assignment.';
|
||||
$string['privacy:metadata:assignuserflags'] = 'Stores user meta data such as extension dates';
|
||||
$string['privacy:metadata:assignusermapping'] = 'The mapping for blind marking';
|
||||
$string['privacy:metadata:assignworkflowfilter'] = 'Filter by the different workflow stages.';
|
||||
$string['privacy:metadata:grade'] = 'The numerical grade for this assignment submission. Can be determined by scales/advancedgradingforms etc but will always be converted back to a floating point number.';
|
||||
$string['privacy:metadata:grader'] = 'The user ID of the person grading.';
|
||||
$string['privacy:metadata:groupid'] = 'Group ID that the user is a member of.';
|
||||
$string['privacy:metadata:latest'] = 'Greatly simplifies queries wanting to know information about only the latest attempt.';
|
||||
$string['privacy:metadata:mailed'] = 'Has this user been mailed yet?';
|
||||
$string['privacy:metadata:timecreated'] = 'Time created';
|
||||
$string['privacy:metadata:userid'] = 'Identifier for the user.';
|
||||
$string['privacy:studentpath'] = 'studentsubmissions';
|
||||
$string['quickgrading'] = 'Quick grading';
|
||||
$string['quickgradingresult'] = 'Quick grading';
|
||||
$string['quickgradingchangessaved'] = 'The grade changes were saved';
|
||||
@ -454,6 +480,7 @@ $string['submissionlog'] = 'Student: {$a->fullname}, Status: {$a->status}';
|
||||
$string['submissionnotcopiedinvalidstatus'] = 'The submission was not copied because it has been edited since it was reopened.';
|
||||
$string['submissionnoteditable'] = 'Student cannot edit this submission';
|
||||
$string['submissionnotready'] = 'This assignment is not ready to submit:';
|
||||
$string['privacy:submissionpath'] = 'submission';
|
||||
$string['submissionplugins'] = 'Submission plugins';
|
||||
$string['submissionreceipts'] = 'Send submission receipts';
|
||||
$string['submissionreceiptothertext'] = 'Your assignment submission for
|
||||
|
@ -5287,7 +5287,7 @@ class assign {
|
||||
* @param int $userid If not set, $USER->id will be used.
|
||||
* @return array $submissions All submission records for this user (or group).
|
||||
*/
|
||||
protected function get_all_submissions($userid) {
|
||||
public function get_all_submissions($userid) {
|
||||
global $DB, $USER;
|
||||
|
||||
// If the userid is not null then use userid.
|
||||
|
131
mod/assign/submission/comments/classes/privacy/provider.php
Normal file
131
mod/assign/submission/comments/classes/privacy/provider.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignsubmission_comments
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace assignsubmission_comments\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\metadata\provider as metadataprovider;
|
||||
use \core_comment\privacy\provider as comments_provider;
|
||||
use \core_privacy\local\request\contextlist;
|
||||
use \mod_assign\privacy\assign_plugin_request_data;
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignsubmission_comments
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements metadataprovider, \mod_assign\privacy\assignsubmission_provider {
|
||||
|
||||
/**
|
||||
* Return meta data about this plugin.
|
||||
*
|
||||
* @param collection $collection A list of information to add to.
|
||||
* @return collection Return the collection after adding to it.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$collection->link_subsystem('core_comment', 'privacy:metadata:commentpurpose');
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* It is possible to make a comment as a teacher without creating an entry in the submission table, so this is required
|
||||
* to find those entries.
|
||||
*
|
||||
* @param int $userid The user ID that we are finding contexts for.
|
||||
* @param contextlist $contextlist A context list to add sql and params to for contexts.
|
||||
*/
|
||||
public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) {
|
||||
$sql = "SELECT contextid
|
||||
FROM {comments}
|
||||
WHERE component = :component
|
||||
AND commentarea = :commentarea
|
||||
AND userid = :userid";
|
||||
$params = ['userid' => $userid, 'component' => 'assignsubmission_comments', 'commentarea' => 'submission_comments'];
|
||||
$contextlist->add_from_sql($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to the fact that we can't rely on the queries in the mod_assign provider we have to add some additional sql.
|
||||
*
|
||||
* @param \mod_assign\privacy\useridlist $useridlist An object for obtaining user IDs of students.
|
||||
*/
|
||||
public static function get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) {
|
||||
$params = ['assignid' => $useridlist->get_assignid(), 'commentuserid' => $useridlist->get_teacherid(),
|
||||
'commentuserid2' => $useridlist->get_teacherid()];
|
||||
$sql = "SELECT DISTINCT c.userid AS id
|
||||
FROM {comments} c
|
||||
JOIN (SELECT c.itemid
|
||||
FROM {comments} c
|
||||
JOIN {assign_submission} s ON s.id = c.itemid AND s.assignment = :assignid
|
||||
WHERE c.userid = :commentuserid) aa ON aa.itemid = c.itemid
|
||||
WHERE c.userid NOT IN (:commentuserid2)";
|
||||
$useridlist->add_from_sql($sql, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for this plugin.
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful
|
||||
* information to help with exporting.
|
||||
*/
|
||||
public static function export_submission_user_data(assign_plugin_request_data $exportdata) {
|
||||
$component = 'assignsubmission_comments';
|
||||
$commentarea = 'submission_comments';
|
||||
|
||||
$userid = ($exportdata->get_user() != null);
|
||||
$submission = $exportdata->get_pluginobject();
|
||||
|
||||
// For the moment we are only showing the comments made by this user.
|
||||
comments_provider::export_comments($exportdata->get_context(), $component, $commentarea, $submission->id,
|
||||
$exportdata->get_subcontext(), $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all the comments made for this context.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data to fulfill the deletion request.
|
||||
*/
|
||||
public static function delete_submission_for_context(assign_plugin_request_data $requestdata) {
|
||||
comments_provider::delete_comments_for_all_users($requestdata->get_context(), 'assignsubmission_comments',
|
||||
'submission_comments');
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method should delete user data (where practical) using the userid and submission.
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Details about the user and context to focus the deletion.
|
||||
*/
|
||||
public static function delete_submission_for_userid(assign_plugin_request_data $exportdata) {
|
||||
// Create an approved context list to delete the comments.
|
||||
$contextlist = new \core_privacy\local\request\approved_contextlist($exportdata->get_user(), 'assignsubmission_comments',
|
||||
[$exportdata->get_context()->id]);
|
||||
comments_provider::delete_comments_for_user($contextlist, 'assignsubmission_comments', 'submission_comments');
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
|
||||
$string['blindmarkingname'] = 'Participant {$a}';
|
||||
$string['blindmarkingviewfullname'] = 'Participant {$a->participantnumber} ({$a->participantfullname})';
|
||||
$string['privacy:metadata:commentpurpose'] = 'Comments between the student and teacher about a submission.';
|
||||
$string['default'] = 'Enabled by default';
|
||||
$string['default_help'] = 'If set, this submission method will be enabled by default for all new assignments.';
|
||||
$string['enabled'] = 'Submission comments';
|
||||
|
253
mod/assign/submission/comments/tests/privacy_test.php
Normal file
253
mod/assign/submission/comments/tests/privacy_test.php
Normal file
@ -0,0 +1,253 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for assignsubmission_comments.
|
||||
*
|
||||
* @package assignsubmission_comments
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/tests/privacy_test.php');
|
||||
|
||||
/**
|
||||
* Unit tests for mod/assign/submission/comments/classes/privacy/
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignsubmission_comments_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
|
||||
|
||||
/**
|
||||
* Convenience function for creating feedback data.
|
||||
*
|
||||
* @param object $assign assign object
|
||||
* @param stdClass $student user object
|
||||
* @param string $submissiontext Submission text
|
||||
* @return array Submission plugin object and the submission object and the comment object.
|
||||
*/
|
||||
protected function create_comment_submission($assign, $student, $submissiontext) {
|
||||
|
||||
$submission = $assign->get_user_submission($student->id, true);
|
||||
|
||||
$plugin = $assign->get_submission_plugin_by_type('comments');
|
||||
|
||||
$context = $assign->get_context();
|
||||
$options = new stdClass();
|
||||
$options->area = 'submission_comments';
|
||||
$options->course = $assign->get_course();
|
||||
$options->context = $context;
|
||||
$options->itemid = $submission->id;
|
||||
$options->component = 'assignsubmission_comments';
|
||||
$options->showcount = true;
|
||||
$options->displaycancel = true;
|
||||
|
||||
$comment = new comment($options);
|
||||
$comment->set_post_permission(true);
|
||||
|
||||
$this->setUser($student);
|
||||
|
||||
$comment->add($submissiontext);
|
||||
|
||||
return [$plugin, $submission, $comment];
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick test to make sure that get_metadata returns something.
|
||||
*/
|
||||
public function test_get_metadata() {
|
||||
$collection = new \core_privacy\local\metadata\collection('assignsubmission_comments');
|
||||
$collection = \assignsubmission_comments\privacy\provider::get_metadata($collection);
|
||||
$this->assertNotEmpty($collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test returning the context for a user who has made a comment in an assignment.
|
||||
*/
|
||||
public function test_get_context_for_userid_within_submission() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentcomment = 'Comment from user 1';
|
||||
list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment);
|
||||
$teachercomment = 'From the teacher';
|
||||
$this->setUser($user2);
|
||||
$comment->add($teachercomment);
|
||||
|
||||
$contextlist = new \core_privacy\local\request\contextlist();
|
||||
\assignsubmission_comments\privacy\provider::get_context_for_userid_within_submission($user2->id, $contextlist);
|
||||
$this->assertEquals($context->id, $contextlist->get_contextids()[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test returning student ids given a user ID.
|
||||
*/
|
||||
public function test_get_student_user_ids() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentcomment = 'Comment from user 1';
|
||||
list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment);
|
||||
$teachercomment = 'From the teacher';
|
||||
$this->setUser($user2);
|
||||
$comment->add($teachercomment);
|
||||
|
||||
$useridlist = new mod_assign\privacy\useridlist($user2->id, $assign->get_instance()->id);
|
||||
\assignsubmission_comments\privacy\provider::get_student_user_ids($useridlist);
|
||||
$this->assertEquals($user1->id, $useridlist->get_userids()[0]->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that comments are exported for a user.
|
||||
*/
|
||||
public function test_export_submission_user_data() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentcomment = 'Comment from user 1';
|
||||
list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment);
|
||||
$teachercomment = 'From the teacher';
|
||||
$this->setUser($user2);
|
||||
$comment->add($teachercomment);
|
||||
|
||||
$writer = \core_privacy\local\request\writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should be able to see the teachers feedback.
|
||||
$exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission);
|
||||
\assignsubmission_comments\privacy\provider::export_submission_user_data($exportdata);
|
||||
$exportedcomments = $writer->get_data(['Comments']);
|
||||
$this->assertCount(2, $exportedcomments->comments);
|
||||
$this->assertContains($studentcomment, $exportedcomments->comments[0]->content);
|
||||
$this->assertContains($teachercomment, $exportedcomments->comments[1]->content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that all comments are deleted for this context.
|
||||
*/
|
||||
public function test_delete_submission_for_context() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentcomment = 'Comment from user 1';
|
||||
list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment);
|
||||
$studentcomment = 'Comment from user 2';
|
||||
list($plugin2, $submission2, $comment2) = $this->create_comment_submission($assign, $user2, $studentcomment);
|
||||
$teachercomment1 = 'From the teacher';
|
||||
$teachercomment2 = 'From the teacher for second student.';
|
||||
$this->setUser($user3);
|
||||
$comment->add($teachercomment1);
|
||||
$comment2->add($teachercomment2);
|
||||
|
||||
// Only need the context in this plugin for this operation.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
|
||||
\assignsubmission_comments\privacy\provider::delete_submission_for_context($requestdata);
|
||||
|
||||
$results = $DB->get_records('comments', ['contextid' => $context->id]);
|
||||
$this->assertEmpty($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the comments for a user are deleted.
|
||||
*/
|
||||
public function test_delete_submission_for_userid() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user3 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentcomment = 'Comment from user 1';
|
||||
list($plugin, $submission, $comment) = $this->create_comment_submission($assign, $user1, $studentcomment);
|
||||
$studentcomment = 'Comment from user 2';
|
||||
list($plugin2, $submission2, $comment2) = $this->create_comment_submission($assign, $user2, $studentcomment);
|
||||
$teachercomment1 = 'From the teacher';
|
||||
$teachercomment2 = 'From the teacher for second student.';
|
||||
$this->setUser($user3);
|
||||
$comment->add($teachercomment1);
|
||||
$comment2->add($teachercomment2);
|
||||
|
||||
// Provide full details to delete the comments.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, null, [], $user1);
|
||||
\assignsubmission_comments\privacy\provider::delete_submission_for_userid($requestdata);
|
||||
|
||||
$results = $DB->get_records('comments', ['contextid' => $context->id]);
|
||||
// We are only deleting the comments for user1 (one comment) so we should have three left.
|
||||
$this->assertCount(3, $results);
|
||||
foreach ($results as $result) {
|
||||
// Check that none of the comments are from user1.
|
||||
$this->assertNotEquals($user1->id, $result->userid);
|
||||
}
|
||||
}
|
||||
}
|
143
mod/assign/submission/file/classes/privacy/provider.php
Normal file
143
mod/assign/submission/file/classes/privacy/provider.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignsubmission_file
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace assignsubmission_file\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\metadata\provider as metadataprovider;
|
||||
use \core_privacy\local\request\writer;
|
||||
use \core_privacy\local\request\contextlist;
|
||||
use \mod_assign\privacy\assign_plugin_request_data;
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignsubmission_file
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements metadataprovider, \mod_assign\privacy\assignsubmission_provider {
|
||||
|
||||
/**
|
||||
* Return meta data about this plugin.
|
||||
*
|
||||
* @param collection $collection A list of information to add to.
|
||||
* @return collection Return the collection after adding to it.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$collection->link_subsystem('core_files', 'privacy:metadata:filepurpose');
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is covered by mod_assign provider and the query on assign_submissions.
|
||||
*
|
||||
* @param int $userid The user ID that we are finding contexts for.
|
||||
* @param contextlist $contextlist A context list to add sql and params to for contexts.
|
||||
*/
|
||||
public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) {
|
||||
// This is already fetched from mod_assign.
|
||||
}
|
||||
|
||||
/**
|
||||
* This is also covered by the mod_assign provider and it's queries.
|
||||
*
|
||||
* @param \mod_assign\privacy\useridlist $useridlist An object for obtaining user IDs of students.
|
||||
*/
|
||||
public static function get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) {
|
||||
// No need.
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for this plugin.
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful
|
||||
* information to help with exporting.
|
||||
*/
|
||||
public static function export_submission_user_data(assign_plugin_request_data $exportdata) {
|
||||
// We currently don't show submissions to teachers when exporting their data.
|
||||
$context = $exportdata->get_context();
|
||||
if ($exportdata->get_user() != null) {
|
||||
return null;
|
||||
}
|
||||
$user = new \stdClass();
|
||||
$assign = $exportdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignsubmission', 'file');
|
||||
$files = $plugin->get_files($exportdata->get_pluginobject(), $user);
|
||||
foreach ($files as $file) {
|
||||
$userid = $exportdata->get_pluginobject()->userid;
|
||||
writer::with_context($exportdata->get_context())->export_file($exportdata->get_subcontext(), $file);
|
||||
|
||||
// Plagiarism data.
|
||||
$coursecontext = $context->get_course_context();
|
||||
\core_plagiarism\privacy\provider::export_plagiarism_user_data($userid, $context, $exportdata->get_subcontext(), [
|
||||
'cmid' => $context->instanceid,
|
||||
'course' => $coursecontext->instanceid,
|
||||
'userid' => $userid,
|
||||
'file' => $file
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Information useful for deleting user data.
|
||||
*/
|
||||
public static function delete_submission_for_context(assign_plugin_request_data $requestdata) {
|
||||
global $DB;
|
||||
|
||||
\core_plagiarism\privacy\provider::delete_plagiarism_for_context($requestdata->get_context());
|
||||
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($requestdata->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA);
|
||||
|
||||
// Delete records from assignsubmission_file table.
|
||||
$DB->delete_records('assignsubmission_file', ['assignment' => $requestdata->get_assign()->get_instance()->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method should delete user data (where practicle) using the userid and submission.
|
||||
*
|
||||
* @param assign_plugin_request_data $deletedata Details about the user and context to focus the deletion.
|
||||
*/
|
||||
public static function delete_submission_for_userid(assign_plugin_request_data $deletedata) {
|
||||
global $DB;
|
||||
|
||||
\core_plagiarism\privacy\provider::delete_plagiarism_for_user($deletedata->get_user()->id, $deletedata->get_context());
|
||||
|
||||
$submissionid = $deletedata->get_pluginobject()->id;
|
||||
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($deletedata->get_context()->id, 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA,
|
||||
$submissionid);
|
||||
|
||||
$DB->delete_records('assignsubmission_file', ['assignment' => $deletedata->get_assign()->get_instance()->id,
|
||||
'submission' => $submissionid]);
|
||||
}
|
||||
}
|
@ -43,6 +43,7 @@ $string['maximumsubmissionsize'] = 'Maximum submission size';
|
||||
$string['maximumsubmissionsize_help'] = 'Files uploaded by students may be up to this size.';
|
||||
$string['numfilesforlog'] = 'The number of file(s) : {$a} file(s).';
|
||||
$string['pluginname'] = 'File submissions';
|
||||
$string['privacy:metadata:filepurpose'] = 'The files loaded for this assignment submission';
|
||||
$string['siteuploadlimit'] = 'Site upload limit';
|
||||
$string['submissionfilearea'] = 'Uploaded submission files';
|
||||
// Deprecated since Moodle 3.4.
|
||||
|
175
mod/assign/submission/file/tests/privacy_test.php
Normal file
175
mod/assign/submission/file/tests/privacy_test.php
Normal file
@ -0,0 +1,175 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for assignsubmission_file.
|
||||
*
|
||||
* @package assignsubmission_file
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/tests/privacy_test.php');
|
||||
|
||||
/**
|
||||
* Unit tests for mod/assign/submission/file/classes/privacy/
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignsubmission_file_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
|
||||
|
||||
/**
|
||||
* Convenience function for creating feedback data.
|
||||
*
|
||||
* @param object $assign assign object
|
||||
* @param stdClass $student user object
|
||||
* @param string $filename filename for the file submission
|
||||
* @return array Submission plugin object and the submission object.
|
||||
*/
|
||||
protected function create_file_submission($assign, $student, $filename) {
|
||||
global $CFG;
|
||||
// Create a file submission with the test pdf.
|
||||
$submission = $assign->get_user_submission($student->id, true);
|
||||
|
||||
$this->setUser($student->id);
|
||||
|
||||
$fs = get_file_storage();
|
||||
$pdfsubmission = (object) array(
|
||||
'contextid' => $assign->get_context()->id,
|
||||
'component' => 'assignsubmission_file',
|
||||
'filearea' => ASSIGNSUBMISSION_FILE_FILEAREA,
|
||||
'itemid' => $submission->id,
|
||||
'filepath' => '/',
|
||||
'filename' => $filename
|
||||
);
|
||||
$sourcefile = $CFG->dirroot.'/mod/assign/feedback/editpdf/tests/fixtures/submission.pdf';
|
||||
$fi = $fs->create_file_from_pathname($pdfsubmission, $sourcefile);
|
||||
|
||||
$data = new \stdClass();
|
||||
$plugin = $assign->get_submission_plugin_by_type('file');
|
||||
$plugin->save($submission, $data);
|
||||
|
||||
return [$plugin, $submission];
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick test to make sure that get_metadata returns something.
|
||||
*/
|
||||
public function test_get_metadata() {
|
||||
$collection = new \core_privacy\local\metadata\collection('assignsubmission_file');
|
||||
$collection = \assignsubmission_file\privacy\provider::get_metadata($collection);
|
||||
$this->assertNotEmpty($collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that submission files are exported for a user.
|
||||
*/
|
||||
public function test_export_submission_user_data() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
// Teacher.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentfilename = 'user1file.pdf';
|
||||
list($plugin, $submission) = $this->create_file_submission($assign, $user1, $studentfilename);
|
||||
|
||||
$writer = \core_privacy\local\request\writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should have a file submission.
|
||||
$exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, ['Attempt 1']);
|
||||
\assignsubmission_file\privacy\provider::export_submission_user_data($exportdata);
|
||||
// print_object($writer);
|
||||
$storedfile = $writer->get_files(['Attempt 1'])['user1file.pdf'];
|
||||
$this->assertInstanceOf('stored_file', $storedfile);
|
||||
$this->assertEquals($studentfilename, $storedfile->get_filename());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that all submission files are deleted for this context.
|
||||
*/
|
||||
public function test_delete_submission_for_context() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentfilename = 'user1file.pdf';
|
||||
list($plugin, $submission) = $this->create_file_submission($assign, $user1, $studentfilename);
|
||||
$student2filename = 'user2file.pdf';
|
||||
list($plugin2, $submission2) = $this->create_file_submission($assign, $user2, $studentfilename);
|
||||
|
||||
// Only need the context and assign object in this plugin for this operation.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
|
||||
\assignsubmission_file\privacy\provider::delete_submission_for_context($requestdata);
|
||||
// This checks that there are no files in this submission.
|
||||
$this->assertTrue($plugin->is_empty($submission));
|
||||
$this->assertTrue($plugin2->is_empty($submission2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the comments for a user are deleted.
|
||||
*/
|
||||
public function test_delete_submission_for_userid() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studentfilename = 'user1file.pdf';
|
||||
list($plugin, $submission) = $this->create_file_submission($assign, $user1, $studentfilename);
|
||||
$student2filename = 'user2file.pdf';
|
||||
list($plugin2, $submission2) = $this->create_file_submission($assign, $user2, $studentfilename);
|
||||
|
||||
// Only need the context and assign object in this plugin for this operation.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, [], $user1);
|
||||
\assignsubmission_file\privacy\provider::delete_submission_for_userid($requestdata);
|
||||
// This checks that there are no files in this submission.
|
||||
$this->assertTrue($plugin->is_empty($submission));
|
||||
// There should be files here.
|
||||
$this->assertFalse($plugin2->is_empty($submission2));
|
||||
}
|
||||
}
|
162
mod/assign/submission/onlinetext/classes/privacy/provider.php
Normal file
162
mod/assign/submission/onlinetext/classes/privacy/provider.php
Normal file
@ -0,0 +1,162 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignsubmission_onlinetext
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace assignsubmission_onlinetext\privacy;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\local\metadata\collection;
|
||||
use \core_privacy\local\metadata\provider as metadataprovider;
|
||||
use \core_privacy\local\request\writer;
|
||||
use \core_privacy\local\request\contextlist;
|
||||
use \mod_assign\privacy\assign_plugin_request_data;
|
||||
|
||||
/**
|
||||
* Privacy class for requesting user data.
|
||||
*
|
||||
* @package assignsubmission_onlinetext
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class provider implements metadataprovider, \mod_assign\privacy\assignsubmission_provider {
|
||||
|
||||
/**
|
||||
* Return meta data about this plugin.
|
||||
*
|
||||
* @param collection $collection A list of information to add to.
|
||||
* @return collection Return the collection after adding to it.
|
||||
*/
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$detail = [
|
||||
'assignment' => 'privacy:metadata:assignmentid',
|
||||
'submission' => 'privacy:metadata:submissionpurpose',
|
||||
'onlinetext' => 'privacy:metadata:textpurpose'
|
||||
];
|
||||
$collection->add_database_table('assignsubmission_onlinetext', $detail, 'privacy:metadata:tablepurpose');
|
||||
$collection->link_subsystem('core_files', 'privacy:metadata:filepurpose');
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is covered by mod_assign provider and the query on assign_submissions.
|
||||
*
|
||||
* @param int $userid The user ID that we are finding contexts for.
|
||||
* @param contextlist $contextlist A context list to add sql and params to for contexts.
|
||||
*/
|
||||
public static function get_context_for_userid_within_submission(int $userid, contextlist $contextlist) {
|
||||
// This is already fetched from mod_assign.
|
||||
}
|
||||
|
||||
/**
|
||||
* This is also covered by the mod_assign provider and it's queries.
|
||||
*
|
||||
* @param \mod_assign\privacy\useridlist $useridlist An object for obtaining user IDs of students.
|
||||
*/
|
||||
public static function get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) {
|
||||
// No need.
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all user data for this plugin.
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Data used to determine which context and user to export and other useful
|
||||
* information to help with exporting.
|
||||
*/
|
||||
public static function export_submission_user_data(assign_plugin_request_data $exportdata) {
|
||||
// We currently don't show submissions to teachers when exporting their data.
|
||||
if ($exportdata->get_user() != null) {
|
||||
return null;
|
||||
}
|
||||
// Retrieve text for this submission.
|
||||
$assign = $exportdata->get_assign();
|
||||
$plugin = $assign->get_plugin_by_type('assignsubmission', 'onlinetext');
|
||||
$submission = $exportdata->get_pluginobject();
|
||||
$editortext = $plugin->get_editor_text('onlinetext', $submission->id);
|
||||
$context = $exportdata->get_context();
|
||||
if (!empty($editortext)) {
|
||||
$submissiontext = new \stdClass();
|
||||
$submissiontext->text = writer::with_context($context)->rewrite_pluginfile_urls([], '', '', '', $editortext);
|
||||
$currentpath = $exportdata->get_subcontext();
|
||||
$currentpath[] = get_string('privacy:path', 'assignsubmission_onlinetext');
|
||||
writer::with_context($context)
|
||||
->export_area_files($currentpath, 'assignsubmission_onlinetext', 'submissions_onlinetext', $submission->id)
|
||||
// Add the text to the exporter.
|
||||
->export_data($currentpath, $submissiontext);
|
||||
|
||||
// Handle plagiarism data.
|
||||
$coursecontext = $context->get_course_context();
|
||||
$userid = $submission->userid;
|
||||
\core_plagiarism\privacy\provider::export_plagiarism_user_data($userid, $context, $currentpath, [
|
||||
'cmid' => $context->instanceid,
|
||||
'course' => $coursecontext->instanceid,
|
||||
'userid' => $userid,
|
||||
'content' => $editortext,
|
||||
'assignment' => $submission->assignment
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function delete_submission_for_context(assign_plugin_request_data $requestdata) {
|
||||
global $DB;
|
||||
|
||||
\core_plagiarism\privacy\provider::delete_plagiarism_for_context($requestdata->get_context());
|
||||
|
||||
// Delete related files.
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($requestdata->get_context()->id, 'assignsubmission_onlinetext',
|
||||
ASSIGNSUBMISSION_ONLINETEXT_FILEAREA);
|
||||
|
||||
// Delete the records in the table.
|
||||
$DB->delete_records('assignsubmission_onlinetext', ['assignment' => $requestdata->get_assign()->get_instance()->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method should delete user data (where practicle) from the userid and context.
|
||||
*
|
||||
* @param assign_plugin_request_data $deletedata Details about the user and context to focus the deletion.
|
||||
*/
|
||||
public static function delete_submission_for_userid(assign_plugin_request_data $deletedata) {
|
||||
global $DB;
|
||||
|
||||
\core_plagiarism\privacy\provider::delete_plagiarism_for_user($deletedata->get_user()->id, $deletedata->get_context());
|
||||
|
||||
$submissionid = $deletedata->get_pluginobject()->id;
|
||||
|
||||
// Delete related files.
|
||||
$fs = get_file_storage();
|
||||
$fs->delete_area_files($deletedata->get_context()->id, 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA,
|
||||
$submissionid);
|
||||
|
||||
// Delete the records in the table.
|
||||
$DB->delete_records('assignsubmission_onlinetext', ['assignment' => $deletedata->get_assign()->get_instance()->id,
|
||||
'submission' => $submissionid]);
|
||||
}
|
||||
}
|
@ -32,9 +32,15 @@ $string['nosubmission'] = 'Nothing has been submitted for this assignment';
|
||||
$string['onlinetext'] = 'Online text';
|
||||
$string['onlinetextfilename'] = 'onlinetext.html';
|
||||
$string['onlinetextsubmission'] = 'Allow online text submission';
|
||||
$string['pluginname'] = 'Online text submissions';
|
||||
$string['numwords'] = '({$a} words)';
|
||||
$string['numwordsforlog'] = 'Submission word count: {$a} words';
|
||||
$string['pluginname'] = 'Online text submissions';
|
||||
$string['privacy:metadata:assignmentid'] = 'Assignment identifier';
|
||||
$string['privacy:metadata:filepurpose'] = 'Files that are embedded in the text submission.';
|
||||
$string['privacy:metadata:submissionpurpose'] = 'The submission ID that links to submissions for the user.';
|
||||
$string['privacy:metadata:tablepurpose'] = 'Stores the text submission for each attempt.';
|
||||
$string['privacy:metadata:textpurpose'] = 'The actual text submitted for this attempt of the assignment.';
|
||||
$string['privacy:path'] = 'Submission Text';
|
||||
$string['wordlimit'] = 'Word limit';
|
||||
$string['wordlimit_help'] = 'If online text submissions are enabled, this is the maximum number ' .
|
||||
'of words that each student will be allowed to submit.';
|
||||
|
164
mod/assign/submission/onlinetext/tests/privacy_test.php
Normal file
164
mod/assign/submission/onlinetext/tests/privacy_test.php
Normal file
@ -0,0 +1,164 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for assignsubmission_onlinetext.
|
||||
*
|
||||
* @package assignsubmission_onlinetext
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/tests/privacy_test.php');
|
||||
|
||||
/**
|
||||
* Unit tests for mod/assign/submission/onlinetext/classes/privacy/
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class assignsubmission_online_privacy_testcase extends \mod_assign\tests\mod_assign_privacy_testcase {
|
||||
|
||||
/**
|
||||
* Convenience function for creating feedback data.
|
||||
*
|
||||
* @param object $assign assign object
|
||||
* @param stdClass $student user object
|
||||
* @param string $text Submission text.
|
||||
* @return array Submission plugin object and the submission object.
|
||||
*/
|
||||
protected function create_online_submission($assign, $student, $text) {
|
||||
global $CFG;
|
||||
|
||||
$this->setUser($student->id);
|
||||
$submission = $assign->get_user_submission($student->id, true);
|
||||
$data = new stdClass();
|
||||
$data->onlinetext_editor = array(
|
||||
'itemid' => file_get_unused_draft_itemid(),
|
||||
'text' => $text,
|
||||
'format' => FORMAT_PLAIN
|
||||
);
|
||||
|
||||
$submission = $assign->get_user_submission($student->id, true);
|
||||
|
||||
$plugin = $assign->get_submission_plugin_by_type('onlinetext');
|
||||
$plugin->save($submission, $data);
|
||||
|
||||
return [$plugin, $submission];
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick test to make sure that get_metadata returns something.
|
||||
*/
|
||||
public function test_get_metadata() {
|
||||
$collection = new \core_privacy\local\metadata\collection('assignsubmission_file');
|
||||
$collection = \assignsubmission_onlinetext\privacy\provider::get_metadata($collection);
|
||||
$this->assertNotEmpty($collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that submission files and text are exported for a user.
|
||||
*/
|
||||
public function test_export_submission_user_data() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$submissiontext = 'Just some text';
|
||||
list($plugin, $submission) = $this->create_online_submission($assign, $user1, $submissiontext);
|
||||
|
||||
$writer = \core_privacy\local\request\writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should have some text submitted.
|
||||
$exportdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, ['Attempt 1']);
|
||||
\assignsubmission_onlinetext\privacy\provider::export_submission_user_data($exportdata);
|
||||
$this->assertEquals($submissiontext, $writer->get_data(['Attempt 1',
|
||||
get_string('privacy:path', 'assignsubmission_onlinetext')])->text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that all submission files are deleted for this context.
|
||||
*/
|
||||
public function test_delete_submission_for_context() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studenttext = 'Student one\'s text.';
|
||||
list($plugin, $submission) = $this->create_online_submission($assign, $user1, $studenttext);
|
||||
$studenttext2 = 'Student two\'s text.';
|
||||
list($plugin2, $submission2) = $this->create_online_submission($assign, $user2, $studenttext2);
|
||||
|
||||
// Only need the context and assign object in this plugin for this operation.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
|
||||
\assignsubmission_onlinetext\privacy\provider::delete_submission_for_context($requestdata);
|
||||
// This checks that there is no content for these submissions.
|
||||
$this->assertTrue($plugin->is_empty($submission));
|
||||
$this->assertTrue($plugin2->is_empty($submission2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the comments for a user are deleted.
|
||||
*/
|
||||
public function test_delete_submission_for_userid() {
|
||||
$this->resetAfterTest();
|
||||
// Create course, assignment, submission, and then a feedback comment.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
// Student.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
$studenttext = 'Student one\'s text.';
|
||||
list($plugin, $submission) = $this->create_online_submission($assign, $user1, $studenttext);
|
||||
$studenttext2 = 'Student two\'s text.';
|
||||
list($plugin2, $submission2) = $this->create_online_submission($assign, $user2, $studenttext2);
|
||||
|
||||
// Need more data for this operation.
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign, $submission, [], $user1);
|
||||
\assignsubmission_onlinetext\privacy\provider::delete_submission_for_userid($requestdata);
|
||||
// This checks that there is no content for the first submission.
|
||||
$this->assertTrue($plugin->is_empty($submission));
|
||||
// But there is for the second submission.
|
||||
$this->assertFalse($plugin2->is_empty($submission2));
|
||||
}
|
||||
}
|
225
mod/assign/tests/privacy_feedback_legacy_polyfill_test.php
Normal file
225
mod/assign/tests/privacy_feedback_legacy_polyfill_test.php
Normal file
@ -0,0 +1,225 @@
|
||||
<?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/>.
|
||||
/**
|
||||
* Unit tests for the privacy legacy polyfill for mod_assign.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @category test
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/feedbackplugin.php');
|
||||
require_once($CFG->dirroot . '/mod/assign/feedback/comments/locallib.php');
|
||||
|
||||
/**
|
||||
* Unit tests for the assignment feedback subplugins API's privacy legacy_polyfill.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_assignfeedback_privacy_legacy_polyfill_test extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Convenience function to create an instance of an assignment.
|
||||
*
|
||||
* @param array $params Array of parameters to pass to the generator
|
||||
* @return assign The assign class.
|
||||
*/
|
||||
protected function create_instance($params = array()) {
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||||
$instance = $generator->create_instance($params);
|
||||
$cm = get_coursemodule_from_instance('assign', $instance->id);
|
||||
$context = \context_module::instance($cm->id);
|
||||
return new \assign($context, $cm, $params['course']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the get_context_for_userid_within_feedback shim.
|
||||
*/
|
||||
public function test_get_context_for_userid_within_feedback() {
|
||||
$userid = 21;
|
||||
$contextlist = new \core_privacy\local\request\contextlist();
|
||||
$mock = $this->createMock(test_assignfeedback_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_get_context_for_userid_within_feedback', [$userid, $contextlist]);
|
||||
test_legacy_polyfill_feedback_provider::$mock = $mock;
|
||||
test_legacy_polyfill_feedback_provider::get_context_for_userid_within_feedback($userid, $contextlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the get_student_user_ids shim.
|
||||
*/
|
||||
public function test_get_student_user_ids() {
|
||||
$teacherid = 107;
|
||||
$assignid = 15;
|
||||
$useridlist = new \mod_assign\privacy\useridlist($teacherid, $assignid);
|
||||
$mock = $this->createMock(test_assignfeedback_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_get_student_user_ids', [$useridlist]);
|
||||
test_legacy_polyfill_feedback_provider::$mock = $mock;
|
||||
test_legacy_polyfill_feedback_provider::get_student_user_ids($useridlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the export_feedback_user_data shim.
|
||||
*/
|
||||
public function test_export_feedback_user_data() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
$context = context_system::instance();
|
||||
$subplugin = new assign_feedback_comments($assign, 'comments');
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context,$assign);
|
||||
$mock = $this->createMock(test_assignfeedback_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_export_feedback_user_data', [$requestdata]);
|
||||
test_legacy_polyfill_feedback_provider::$mock = $mock;
|
||||
test_legacy_polyfill_feedback_provider::export_feedback_user_data($requestdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the delete_feedback_for_context shim.
|
||||
*/
|
||||
public function test_delete_feedback_for_context() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
$context = context_system::instance();
|
||||
$subplugin = new assign_feedback_comments($assign, 'comments');
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context,$assign);
|
||||
$mock = $this->createMock(test_assignfeedback_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_delete_feedback_for_context', [$requestdata]);
|
||||
test_legacy_polyfill_feedback_provider::$mock = $mock;
|
||||
test_legacy_polyfill_feedback_provider::delete_feedback_for_context($requestdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the delete feedback for grade shim.
|
||||
*/
|
||||
public function test_delete_feedback_for_grade() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
$context = context_system::instance();
|
||||
$subplugin = new assign_feedback_comments($assign, 'comments');
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context,$assign);
|
||||
$mock = $this->createMock(test_assignfeedback_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_delete_feedback_for_grade', [$requestdata]);
|
||||
test_legacy_polyfill_feedback_provider::$mock = $mock;
|
||||
test_legacy_polyfill_feedback_provider::delete_feedback_for_grade($requestdata);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Legacy polyfill test class for the assignfeedback_provider.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class test_legacy_polyfill_feedback_provider implements \mod_assign\privacy\assignfeedback_provider {
|
||||
use \mod_assign\privacy\feedback_legacy_polyfill;
|
||||
/**
|
||||
* @var test_legacy_polyfill_feedback_provider $mock.
|
||||
*/
|
||||
public static $mock = null;
|
||||
|
||||
/**
|
||||
* Retrieves the contextids associated with the provided userid for this subplugin.
|
||||
* NOTE if your subplugin must have an entry in the assign_grade table to work, then this
|
||||
* method can be empty.
|
||||
*
|
||||
* @param int $userid The user ID to get context IDs for.
|
||||
* @param contextlist $contextlist Use add_from_sql with this object to add your context IDs.
|
||||
*/
|
||||
public static function _get_context_for_userid_within_feedback(int $userid,
|
||||
\core_privacy\local\request\contextlist $contextlist) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns student user ids related to the provided teacher ID. If an entry must be present in the assign_grade table for
|
||||
* your plugin to work then there is no need to fill in this method. If you filled in get_context_for_userid_within_feedback()
|
||||
* then you probably have to fill this in as well.
|
||||
*
|
||||
* @param useridlist $useridlist A list of user IDs of students graded by this user.
|
||||
*/
|
||||
public static function _get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Export feedback data with the available grade and userid information provided.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - current path (subcontext)
|
||||
* - user object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Contains data to help export the user information.
|
||||
*/
|
||||
public static function _export_feedback_user_data(\mod_assign\privacy\assign_plugin_request_data $exportdata) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function _delete_feedback_for_context(\mod_assign\privacy\assign_plugin_request_data $requestdata) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling this function should delete all user data associated with this grade.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - user object
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data.
|
||||
*/
|
||||
public static function _delete_feedback_for_grade(\mod_assign\privacy\assign_plugin_request_data $requestdata) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Called inside the polyfill methods in the test polyfill provider, allowing us to ensure these are called with correct params.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class test_assignfeedback_legacy_polyfill_mock_wrapper {
|
||||
/**
|
||||
* Get the return value for the specified item.
|
||||
*/
|
||||
public function get_return_value() {
|
||||
}
|
||||
}
|
226
mod/assign/tests/privacy_submission_legacy_polyfill_test.php
Normal file
226
mod/assign/tests/privacy_submission_legacy_polyfill_test.php
Normal file
@ -0,0 +1,226 @@
|
||||
<?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/>.
|
||||
/**
|
||||
* Unit tests for the privacy legacy polyfill for mod_assign.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @category test
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/submissionplugin.php');
|
||||
require_once($CFG->dirroot . '/mod/assign/submission/comments/locallib.php');
|
||||
|
||||
/**
|
||||
* Unit tests for the assignment submission subplugins API's privacy legacy_polyfill.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_assignsubmission_privacy_legacy_polyfill_test extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Convenience function to create an instance of an assignment.
|
||||
*
|
||||
* @param array $params Array of parameters to pass to the generator
|
||||
* @return assign The assign class.
|
||||
*/
|
||||
protected function create_instance($params = array()) {
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||||
$instance = $generator->create_instance($params);
|
||||
$cm = get_coursemodule_from_instance('assign', $instance->id);
|
||||
$context = \context_module::instance($cm->id);
|
||||
return new \assign($context, $cm, $params['course']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the get_context_for_userid_within_submission shim.
|
||||
*/
|
||||
public function test_get_context_for_userid_within_submission() {
|
||||
|
||||
$userid = 21;
|
||||
$contextlist = new \core_privacy\local\request\contextlist();
|
||||
$mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_get_context_for_userid_within_submission', [$userid, $contextlist]);
|
||||
test_legacy_polyfill_submission_provider::$mock = $mock;
|
||||
test_legacy_polyfill_submission_provider::get_context_for_userid_within_submission($userid, $contextlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the get_student_user_ids shim.
|
||||
*/
|
||||
public function test_get_student_user_ids() {
|
||||
$teacherid = 107;
|
||||
$assignid = 15;
|
||||
$useridlist = new \mod_assign\privacy\useridlist($teacherid, $assignid);
|
||||
$mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_get_student_user_ids', [$useridlist]);
|
||||
test_legacy_polyfill_submission_provider::$mock = $mock;
|
||||
test_legacy_polyfill_submission_provider::get_student_user_ids($useridlist);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the export_submission_user_data shim.
|
||||
*/
|
||||
public function test_export_submission_user_data() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
$context = context_system::instance();
|
||||
$subplugin = new assign_submission_comments($assign, 'comment');
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
|
||||
$mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_export_submission_user_data', [$requestdata]);
|
||||
test_legacy_polyfill_submission_provider::$mock = $mock;
|
||||
test_legacy_polyfill_submission_provider::export_submission_user_data($requestdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the delete_submission_for_context shim.
|
||||
*/
|
||||
public function test_delete_submission_for_context() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
$context = context_system::instance();
|
||||
$subplugin = new assign_submission_comments($assign, 'comment');
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
|
||||
$mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_delete_submission_for_context', [$requestdata]);
|
||||
test_legacy_polyfill_submission_provider::$mock = $mock;
|
||||
test_legacy_polyfill_submission_provider::delete_submission_for_context($requestdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the delete submission for grade shim.
|
||||
*/
|
||||
public function test_delete_submission_for_userid() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$assign = $this->create_instance(['course' => $course]);
|
||||
$context = context_system::instance();
|
||||
$subplugin = new assign_submission_comments($assign, 'comment');
|
||||
$requestdata = new \mod_assign\privacy\assign_plugin_request_data($context, $assign);
|
||||
$mock = $this->createMock(test_assignsubmission_legacy_polyfill_mock_wrapper::class);
|
||||
$mock->expects($this->once())
|
||||
->method('get_return_value')
|
||||
->with('_delete_submission_for_userid', [$requestdata]);
|
||||
test_legacy_polyfill_submission_provider::$mock = $mock;
|
||||
test_legacy_polyfill_submission_provider::delete_submission_for_userid($requestdata);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Legacy polyfill test class for the assignsubmission_provider.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class test_legacy_polyfill_submission_provider implements \mod_assign\privacy\assignsubmission_provider {
|
||||
use \mod_assign\privacy\submission_legacy_polyfill;
|
||||
/**
|
||||
* @var test_legacy_polyfill_submission_provider $mock.
|
||||
*/
|
||||
public static $mock = null;
|
||||
|
||||
/**
|
||||
* Retrieves the contextids associated with the provided userid for this subplugin.
|
||||
* NOTE if your subplugin must have an entry in the assign_grade table to work, then this
|
||||
* method can be empty.
|
||||
*
|
||||
* @param int $userid The user ID to get context IDs for.
|
||||
* @param contextlist $contextlist Use add_from_sql with this object to add your context IDs.
|
||||
*/
|
||||
public static function _get_context_for_userid_within_submission(int $userid,
|
||||
\core_privacy\local\request\contextlist $contextlist) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns student user ids related to the provided teacher ID. If it is possible that a student ID will not be returned by
|
||||
* the sql query in \mod_assign\privacy\provider::find_grader_info() Then you need to provide some sql to retrive those
|
||||
* student IDs. This is highly likely if you had to fill in get_context_for_userid_within_submission above.
|
||||
*
|
||||
* @param useridlist $useridlist A list of user IDs of students graded by this user.
|
||||
*/
|
||||
public static function _get_student_user_ids(\mod_assign\privacy\useridlist $useridlist) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to export any user data this sub-plugin has using the assign_plugin_request_data object to get the
|
||||
* context and userid.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - current path (subcontext)
|
||||
* - user object
|
||||
*
|
||||
* @param assign_plugin_request_data $exportdata Contains data to help export the user information.
|
||||
*/
|
||||
public static function _export_submission_user_data(\mod_assign\privacy\assign_plugin_request_data $exportdata) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* Any call to this method should delete all user data for the context defined in the deletion_criteria.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data from this sub-plugin.
|
||||
*/
|
||||
public static function _delete_submission_for_context(\mod_assign\privacy\assign_plugin_request_data $requestdata) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to this method should delete user data (where practicle) from the userid and context.
|
||||
* assign_plugin_request_data contains:
|
||||
* - context
|
||||
* - grade object
|
||||
* - user object
|
||||
* - assign object
|
||||
*
|
||||
* @param assign_plugin_request_data $requestdata Data useful for deleting user data.
|
||||
*/
|
||||
public static function _delete_submission_for_userid(\mod_assign\privacy\assign_plugin_request_data $requestdata) {
|
||||
static::$mock->get_return_value(__FUNCTION__, func_get_args());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Called inside the polyfill methods in the test polyfill provider, allowing us to ensure these are called with correct params.
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adriangreeve.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class test_assignsubmission_legacy_polyfill_mock_wrapper {
|
||||
/**
|
||||
* Get the return value for the specified item.
|
||||
*/
|
||||
public function get_return_value() {
|
||||
}
|
||||
}
|
562
mod/assign/tests/privacy_test.php
Normal file
562
mod/assign/tests/privacy_test.php
Normal file
@ -0,0 +1,562 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Base class for unit tests for mod_assign.
|
||||
*
|
||||
* @package mod_assign
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace mod_assign\tests;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/mod/assign/locallib.php');
|
||||
|
||||
use \core_privacy\tests\provider_testcase;
|
||||
use \core_privacy\local\request\writer;
|
||||
use \core_privacy\local\request\approved_contextlist;
|
||||
use \mod_assign\privacy\provider;
|
||||
|
||||
/**
|
||||
* Unit tests for mod/assign/classes/privacy/
|
||||
*
|
||||
* @copyright 2018 Adrian Greeve <adrian@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mod_assign_privacy_testcase extends provider_testcase {
|
||||
|
||||
/**
|
||||
* Convenience method for creating a submission.
|
||||
*
|
||||
* @param assign $assign The assign object
|
||||
* @param stdClass $user The user object
|
||||
* @param string $submissiontext Submission text
|
||||
* @param integer $attemptnumber The attempt number
|
||||
* @return object A submission object.
|
||||
*/
|
||||
protected function create_submission($assign, $user, $submissiontext, $attemptnumber = 0) {
|
||||
$submission = $assign->get_user_submission($user->id, true, $attemptnumber);
|
||||
$submission->onlinetext_editor = ['text' => $submissiontext,
|
||||
'format' => FORMAT_MOODLE];
|
||||
|
||||
$this->setUser($user);
|
||||
$notices = [];
|
||||
$assign->save_submission($submission, $notices);
|
||||
return $submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to create an instance of an assignment.
|
||||
*
|
||||
* @param array $params Array of parameters to pass to the generator
|
||||
* @return assign The assign class.
|
||||
*/
|
||||
protected function create_instance($params = array()) {
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||||
$instance = $generator->create_instance($params);
|
||||
$cm = get_coursemodule_from_instance('assign', $instance->id);
|
||||
$context = \context_module::instance($cm->id);
|
||||
return new \assign($context, $cm, $params['course']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that getting the contexts for a user works.
|
||||
*/
|
||||
public function test_get_contexts_for_userid() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course1 = $this->getDataGenerator()->create_course();
|
||||
$course2 = $this->getDataGenerator()->create_course();
|
||||
$course3 = $this->getDataGenerator()->create_course();
|
||||
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course1->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course3->id, 'student');
|
||||
// Need a second user to create content in other assignments.
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course2->id, 'student');
|
||||
|
||||
// Create multiple assignments.
|
||||
// Assignment with a text submission.
|
||||
$assign1 = $this->create_instance(['course' => $course1]);
|
||||
// Assignment two in a different course that the user is not enrolled in.
|
||||
$assign2 = $this->create_instance(['course' => $course2]);
|
||||
// Assignment three has an entry in the override table.
|
||||
$assign3 = $this->create_instance(['course' => $course3, 'cutoffdate' => time()]);
|
||||
// Assignment four - blind marking.
|
||||
$assign4 = $this->create_instance(['course' => $course1, 'blindmarking' => 1]);
|
||||
// Assignment five - user flags.
|
||||
$assign5 = $this->create_instance(['course' => $course3]);
|
||||
|
||||
// Override has to be manually inserted into the DB.
|
||||
$overridedata = new \stdClass();
|
||||
$overridedata->assignid = $assign3->get_instance()->id;
|
||||
$overridedata->userid = $user1->id;
|
||||
$overridedata->duedate = time();
|
||||
$DB->insert_record('assign_overrides', $overridedata);
|
||||
// Assign unique id for blind marking in assignment four for user 1.
|
||||
\assign::get_uniqueid_for_user_static($assign4->get_instance()->id, $user1->id);
|
||||
// Create an entry in the user flags table.
|
||||
$assign5->get_user_flags($user1->id, true);
|
||||
|
||||
// The user will be in these contexts.
|
||||
$usercontextids = [
|
||||
$assign1->get_context()->id,
|
||||
$assign3->get_context()->id,
|
||||
$assign4->get_context()->id,
|
||||
$assign5->get_context()->id,
|
||||
];
|
||||
|
||||
$submission = new \stdClass();
|
||||
$submission->assignment = $assign1->get_instance()->id;
|
||||
$submission->userid = $user1->id;
|
||||
$submission->timecreated = time();
|
||||
$submission->onlinetext_editor = ['text' => 'Submission text',
|
||||
'format' => FORMAT_MOODLE];
|
||||
|
||||
$this->setUser($user1);
|
||||
$notices = [];
|
||||
$assign1->save_submission($submission, $notices);
|
||||
|
||||
// Create a submission for the second assignment.
|
||||
$submission->assignment = $assign2->get_instance()->id;
|
||||
$submission->userid = $user2->id;
|
||||
$this->setUser($user2);
|
||||
$assign2->save_submission($submission, $notices);
|
||||
|
||||
$contextlist = provider::get_contexts_for_userid($user1->id);
|
||||
$this->assertEquals(count($usercontextids), count($contextlist->get_contextids()));
|
||||
// There should be no difference between the contexts.
|
||||
$this->assertEmpty(array_diff($usercontextids, $contextlist->get_contextids()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a student with multiple submissions and grades is returned with the correct data.
|
||||
*/
|
||||
public function test_export_user_data_student() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$teacher = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance([
|
||||
'course' => $course,
|
||||
'name' => 'Assign 1',
|
||||
'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
|
||||
'maxattempts' => 3,
|
||||
'assignsubmission_onlinetext_enabled' => true,
|
||||
'assignfeedback_comments_enabled' => true
|
||||
]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
// Create some submissions (multiple attempts) for a student.
|
||||
$submissiontext = 'My first submission';
|
||||
$submission = $this->create_submission($assign, $user, $submissiontext);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade1 = '67.00';
|
||||
$teachercommenttext = 'Please try again.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 0;
|
||||
$data->grade = $grade1;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user->id, $data);
|
||||
|
||||
$submissiontext2 = 'My second submission';
|
||||
$submission = $this->create_submission($assign, $user, $submissiontext2, 1);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade2 = '72.00';
|
||||
$teachercommenttext2 = 'This is better. Thanks.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 1;
|
||||
$data->grade = $grade2;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user->id, $data);
|
||||
|
||||
$writer = writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should have some text submitted.
|
||||
// Add the course context as well to make sure there is no error.
|
||||
$approvedlist = new approved_contextlist($user, 'mod_assign', [$context->id, $coursecontext->id]);
|
||||
provider::export_user_data($approvedlist);
|
||||
|
||||
// Check that we have general details about the assignment.
|
||||
$this->assertEquals('Assign 1', $writer->get_data()->name);
|
||||
// Check Submissions.
|
||||
$this->assertEquals($submissiontext, $writer->get_data(['attempt 1', 'Submission Text'])->text);
|
||||
$this->assertEquals($submissiontext2, $writer->get_data(['attempt 2', 'Submission Text'])->text);
|
||||
$this->assertEquals(0, $writer->get_data(['attempt 1', 'submission'])->attemptnumber);
|
||||
$this->assertEquals(1, $writer->get_data(['attempt 2', 'submission'])->attemptnumber);
|
||||
// Check grades.
|
||||
$this->assertEquals($grade1, $writer->get_data(['attempt 1', 'grade'])->grade);
|
||||
$this->assertEquals($grade2, $writer->get_data(['attempt 2', 'grade'])->grade);
|
||||
// Check feedback.
|
||||
$this->assertContains($teachercommenttext, $writer->get_data(['attempt 1', 'Feedback comments'])->commenttext);
|
||||
$this->assertContains($teachercommenttext2, $writer->get_data(['attempt 2', 'Feedback comments'])->commenttext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the data returned for a teacher.
|
||||
*/
|
||||
public function test_export_user_data_teacher() {
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$teacher = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance([
|
||||
'course' => $course,
|
||||
'name' => 'Assign 1',
|
||||
'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
|
||||
'maxattempts' => 3,
|
||||
'assignsubmission_onlinetext_enabled' => true,
|
||||
'assignfeedback_comments_enabled' => true
|
||||
]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext = 'My first submission';
|
||||
$submission = $this->create_submission($assign, $user1, $submissiontext);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade1 = '54.00';
|
||||
$teachercommenttext = 'Comment on user 1 attempt 1.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 0;
|
||||
$data->grade = $grade1;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user1->id, $data);
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext2 = 'My first submission for user 2';
|
||||
$submission = $this->create_submission($assign, $user2, $submissiontext2);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade2 = '56.00';
|
||||
$teachercommenttext2 = 'Comment on user 2 first attempt.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 0;
|
||||
$data->grade = $grade2;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user2->id, $data);
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext3 = 'My second submission for user 2';
|
||||
$submission = $this->create_submission($assign, $user2, $submissiontext3, 1);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade3 = '83.00';
|
||||
$teachercommenttext3 = 'Comment on user 2 another attempt.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 1;
|
||||
$data->grade = $grade3;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext3, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user2->id, $data);
|
||||
|
||||
// Set up some flags.
|
||||
$duedate = time();
|
||||
$flagdata = $assign->get_user_flags($teacher->id, true);
|
||||
$flagdata->mailed = 1;
|
||||
$flagdata->extensionduedate = $duedate;
|
||||
$assign->update_user_flags($flagdata);
|
||||
|
||||
$writer = writer::with_context($context);
|
||||
$this->assertFalse($writer->has_any_data());
|
||||
|
||||
// The student should have some text submitted.
|
||||
$approvedlist = new approved_contextlist($teacher, 'mod_assign', [$context->id, $coursecontext->id]);
|
||||
provider::export_user_data($approvedlist);
|
||||
|
||||
// Check flag metadata.
|
||||
$metadata = $writer->get_all_metadata();
|
||||
$this->assertEquals(\core_privacy\local\request\transform::yesno(1), $metadata['mailed']->value);
|
||||
$this->assertEquals(\core_privacy\local\request\transform::datetime($duedate), $metadata['extensionduedate']->value);
|
||||
|
||||
// Check for student grades given.
|
||||
$student1grade = $writer->get_data(['studentsubmissions', $user1->id, 'attempt 1', 'grade']);
|
||||
$this->assertEquals($grade1, $student1grade->grade);
|
||||
$student2grade1 = $writer->get_data(['studentsubmissions', $user2->id, 'attempt 1', 'grade']);
|
||||
$this->assertEquals($grade2, $student2grade1->grade);
|
||||
$student2grade2 = $writer->get_data(['studentsubmissions', $user2->id, 'attempt 2', 'grade']);
|
||||
$this->assertEquals($grade3, $student2grade2->grade);
|
||||
// Check for feedback given to students.
|
||||
$this->assertContains($teachercommenttext, $writer->get_data(['studentsubmissions', $user1->id, 'attempt 1',
|
||||
'Feedback comments'])->commenttext);
|
||||
$this->assertContains($teachercommenttext2, $writer->get_data(['studentsubmissions', $user2->id, 'attempt 1',
|
||||
'Feedback comments'])->commenttext);
|
||||
$this->assertContains($teachercommenttext3, $writer->get_data(['studentsubmissions', $user2->id, 'attempt 2',
|
||||
'Feedback comments'])->commenttext);
|
||||
}
|
||||
|
||||
/**
|
||||
* A test for deleting all user data for a given context.
|
||||
*/
|
||||
public function test_delete_data_for_all_users_in_context() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$teacher = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance([
|
||||
'course' => $course,
|
||||
'name' => 'Assign 1',
|
||||
'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
|
||||
'maxattempts' => 3,
|
||||
'assignsubmission_onlinetext_enabled' => true,
|
||||
'assignfeedback_comments_enabled' => true
|
||||
]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext = 'My first submission';
|
||||
$submission = $this->create_submission($assign, $user1, $submissiontext);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
// Overrides for both students.
|
||||
$overridedata = new \stdClass();
|
||||
$overridedata->assignid = $assign->get_instance()->id;
|
||||
$overridedata->userid = $user1->id;
|
||||
$overridedata->duedate = time();
|
||||
$DB->insert_record('assign_overrides', $overridedata);
|
||||
$overridedata->userid = $user2->id;
|
||||
$DB->insert_record('assign_overrides', $overridedata);
|
||||
assign_update_events($assign);
|
||||
|
||||
$grade1 = '54.00';
|
||||
$teachercommenttext = 'Comment on user 1 attempt 1.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 0;
|
||||
$data->grade = $grade1;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user1->id, $data);
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext2 = 'My first submission for user 2';
|
||||
$submission = $this->create_submission($assign, $user2, $submissiontext2);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade2 = '56.00';
|
||||
$teachercommenttext2 = 'Comment on user 2 first attempt.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 0;
|
||||
$data->grade = $grade2;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user2->id, $data);
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext3 = 'My second submission for user 2';
|
||||
$submission = $this->create_submission($assign, $user2, $submissiontext3, 1);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade3 = '83.00';
|
||||
$teachercommenttext3 = 'Comment on user 2 another attempt.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 1;
|
||||
$data->grade = $grade3;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext3, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user2->id, $data);
|
||||
|
||||
// Delete all user data for this assignment.
|
||||
provider::delete_data_for_all_users_in_context($context);
|
||||
|
||||
// Check all relevant tables.
|
||||
$records = $DB->get_records('assign_submission');
|
||||
$this->assertEmpty($records);
|
||||
$records = $DB->get_records('assign_grades');
|
||||
$this->assertEmpty($records);
|
||||
$records = $DB->get_records('assignsubmission_onlinetext');
|
||||
$this->assertEmpty($records);
|
||||
$records = $DB->get_records('assignfeedback_comments');
|
||||
$this->assertEmpty($records);
|
||||
|
||||
// Check that overrides and the calendar events are deleted.
|
||||
$records = $DB->get_records('event');
|
||||
$this->assertEmpty($records);
|
||||
$records = $DB->get_records('assign_overrides');
|
||||
$this->assertEmpty($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* A test for deleting all user data for one user.
|
||||
*/
|
||||
public function test_delete_data_for_user() {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$coursecontext = \context_course::instance($course->id);
|
||||
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
$user2 = $this->getDataGenerator()->create_user();
|
||||
$teacher = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student');
|
||||
$this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
|
||||
$assign = $this->create_instance([
|
||||
'course' => $course,
|
||||
'name' => 'Assign 1',
|
||||
'attemptreopenmethod' => ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL,
|
||||
'maxattempts' => 3,
|
||||
'assignsubmission_onlinetext_enabled' => true,
|
||||
'assignfeedback_comments_enabled' => true
|
||||
]);
|
||||
|
||||
$context = $assign->get_context();
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext = 'My first submission';
|
||||
$submission1 = $this->create_submission($assign, $user1, $submissiontext);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
// Overrides for both students.
|
||||
$overridedata = new \stdClass();
|
||||
$overridedata->assignid = $assign->get_instance()->id;
|
||||
$overridedata->userid = $user1->id;
|
||||
$overridedata->duedate = time();
|
||||
$DB->insert_record('assign_overrides', $overridedata);
|
||||
$overridedata->userid = $user2->id;
|
||||
$DB->insert_record('assign_overrides', $overridedata);
|
||||
assign_update_events($assign);
|
||||
|
||||
$grade1 = '54.00';
|
||||
$teachercommenttext = 'Comment on user 1 attempt 1.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 0;
|
||||
$data->grade = $grade1;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user1->id, $data);
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext2 = 'My first submission for user 2';
|
||||
$submission2 = $this->create_submission($assign, $user2, $submissiontext2);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade2 = '56.00';
|
||||
$teachercommenttext2 = 'Comment on user 2 first attempt.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 0;
|
||||
$data->grade = $grade2;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext2, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user2->id, $data);
|
||||
|
||||
// Create and grade some submissions from the students.
|
||||
$submissiontext3 = 'My second submission for user 2';
|
||||
$submission3 = $this->create_submission($assign, $user2, $submissiontext3, 1);
|
||||
|
||||
$this->setUser($teacher);
|
||||
|
||||
$grade3 = '83.00';
|
||||
$teachercommenttext3 = 'Comment on user 2 another attempt.';
|
||||
$data = new \stdClass();
|
||||
$data->attemptnumber = 1;
|
||||
$data->grade = $grade3;
|
||||
$data->assignfeedbackcomments_editor = ['text' => $teachercommenttext3, 'format' => FORMAT_MOODLE];
|
||||
|
||||
// Give the submission a grade.
|
||||
$assign->save_grade($user2->id, $data);
|
||||
|
||||
// Delete user 2's data.
|
||||
$approvedlist = new approved_contextlist($user2, 'mod_assign', [$context->id, $coursecontext->id]);
|
||||
provider::delete_data_for_user($approvedlist);
|
||||
|
||||
// Check all relevant tables.
|
||||
$records = $DB->get_records('assign_submission');
|
||||
foreach ($records as $record) {
|
||||
$this->assertEquals($user1->id, $record->userid);
|
||||
$this->assertNotEquals($user2->id, $record->userid);
|
||||
}
|
||||
$records = $DB->get_records('assign_grades');
|
||||
foreach ($records as $record) {
|
||||
$this->assertEquals($user1->id, $record->userid);
|
||||
$this->assertNotEquals($user2->id, $record->userid);
|
||||
}
|
||||
$records = $DB->get_records('assignsubmission_onlinetext');
|
||||
$this->assertCount(1, $records);
|
||||
$record = array_shift($records);
|
||||
// The only submission is for user 1.
|
||||
$this->assertEquals($submission1->id, $record->submission);
|
||||
$records = $DB->get_records('assignfeedback_comments');
|
||||
$this->assertCount(1, $records);
|
||||
$record = array_shift($records);
|
||||
// The only record is the feedback comment for user 1.
|
||||
$this->assertEquals($teachercommenttext, $record->commenttext);
|
||||
|
||||
// Check calendar events as well as assign overrides.
|
||||
$records = $DB->get_records('event');
|
||||
$this->assertCount(1, $records);
|
||||
$record = array_shift($records);
|
||||
// The remaining event should be for user 1.
|
||||
$this->assertEquals($user1->id, $record->userid);
|
||||
// Now for assign_overrides
|
||||
$records = $DB->get_records('assign_overrides');
|
||||
$this->assertCount(1, $records);
|
||||
$record = array_shift($records);
|
||||
// The remaining event should be for user 1.
|
||||
$this->assertEquals($user1->id, $record->userid);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user