AutorÃa | Ultima modificación | Ver Log |
<?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 Subsystem implementation for mod_assignment.** @package mod_assignment* @copyright 2018 Zig Tan <zig@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/namespace mod_assignment\privacy;use core_privacy\local\metadata\collection;use core_privacy\local\request\approved_contextlist;use core_privacy\local\request\contextlist;use core_privacy\local\request\transform;use core_privacy\local\request\writer;use core_privacy\local\request\helper;use core_privacy\local\request\approved_userlist;use core_privacy\local\request\userlist;defined('MOODLE_INTERNAL') || die();global $CFG;require_once($CFG->dirroot . '/mod/assignment/lib.php');/*** Implementation of the privacy subsystem plugin provider for mod_assignment.** @copyright 2018 Zig Tan <zig@moodle.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later*/class provider implements\core_privacy\local\metadata\provider,\core_privacy\local\request\plugin\provider,\core_privacy\local\request\user_preference_provider,\core_privacy\local\request\core_userlist_provider {/*** Return the fields which contain personal data.** @param collection $collection a reference to the collection to use to store the metadata.* @return collection the updated collection of metadata items.*/public static function get_metadata(collection $collection) : collection {$collection->add_database_table('assignment_submissions',['userid' => 'privacy:metadata:assignment_submissions:userid','timecreated' => 'privacy:metadata:assignment_submissions:timecreated','timemodified' => 'privacy:metadata:assignment_submissions:timemodified','numfiles' => 'privacy:metadata:assignment_submissions:numfiles','data1' => 'privacy:metadata:assignment_submissions:data1','data2' => 'privacy:metadata:assignment_submissions:data2','grade' => 'privacy:metadata:assignment_submissions:grade','submissioncomment' => 'privacy:metadata:assignment_submissions:submissioncomment','teacher' => 'privacy:metadata:assignment_submissions:teacher','timemarked' => 'privacy:metadata:assignment_submissions:timemarked','mailed' => 'privacy:metadata:assignment_submissions:mailed'],'privacy:metadata:assignment_submissions');// Legacy mod_assignment preferences from Moodle 2.X.$collection->add_user_preference('assignment_filter', 'privacy:metadata:assignmentfilter');$collection->add_user_preference('assignment_mailinfo', 'privacy:metadata:assignmentmailinfo');$collection->add_user_preference('assignment_perpage', 'privacy:metadata:assignmentperpage');$collection->add_user_preference('assignment_quickgrade', 'privacy:metadata:assignmentquickgrade');return $collection;}/*** Get the list of contexts that contain user information for the specified user.** @param int $userid the userid.* @return contextlist the list of contexts containing user info for the user.*/public static function get_contexts_for_userid(int $userid) : contextlist {$contextlist = new contextlist();$sql = "SELECT DISTINCTctx.idFROM {context} ctxJOIN {course_modules} cm ON cm.id = ctx.instanceid AND ctx.contextlevel = :contextmoduleJOIN {modules} m ON cm.module = m.id AND m.name = :modulenameJOIN {assignment} a ON cm.instance = a.idJOIN {assignment_submissions} s ON s.assignment = a.idWHERE s.userid = :useridOR s.teacher = :teacher";$params = ['contextmodule' => CONTEXT_MODULE,'modulename' => 'assignment','userid' => $userid,'teacher' => $userid];$contextlist->add_from_sql($sql, $params);return $contextlist;}/*** Get the list of users who have data within a context.** @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.*/public static function get_users_in_context(userlist $userlist) {$context = $userlist->get_context();if ($context->contextlevel != CONTEXT_MODULE) {return;}$params = ['modulename' => 'assignment','contextlevel' => CONTEXT_MODULE,'contextid' => $context->id];$sql = "SELECT s.useridFROM {assignment_submissions} sJOIN {assignment} a ON s.assignment = a.idJOIN {modules} m ON m.name = :modulenameJOIN {course_modules} cm ON a.id = cm.instance AND cm.module = m.idJOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevelWHERE ctx.id = :contextid";$userlist->add_from_sql('userid', $sql, $params);$sql = "SELECT s.teacherFROM {assignment_submissions} sJOIN {assignment} a ON s.assignment = a.idJOIN {modules} m ON m.name = :modulenameJOIN {course_modules} cm ON a.id = cm.instance AND cm.module = m.idJOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextlevelWHERE ctx.id = :contextid";$userlist->add_from_sql('teacher', $sql, $params);}/*** Export personal data for the given approved_contextlist.* User and context information is contained within the contextlist.** @param approved_contextlist $contextlist a list of contexts approved for export.*/public static function export_user_data(approved_contextlist $contextlist) {if (empty($contextlist->count())) {return;}$user = $contextlist->get_user();foreach ($contextlist->get_contexts() as $context) {if ($context->contextlevel != CONTEXT_MODULE) {continue;}// Cannot make use of helper::export_context_files(), need to manually export assignment details.$assignmentdata = self::get_assignment_by_context($context);// Get assignment details object for output.$assignment = self::get_assignment_output($assignmentdata);writer::with_context($context)->export_data([], $assignment);// Check if the user has marked any assignment's submissions to determine assignment submissions to export.$teacher = (self::has_marked_assignment_submissions($assignmentdata->id, $user->id) == true) ? true : false;// Get the assignment submissions submitted by & marked by the user for an assignment.$submissionsdata = self::get_assignment_submissions_by_assignment($assignmentdata->id, $user->id, $teacher);foreach ($submissionsdata as $submissiondata) {// Default subcontext path to export assignment submissions submitted by the user.$subcontexts = [get_string('privacy:submissionpath', 'mod_assignment')];if ($teacher == true) {if ($submissiondata->teacher == $user->id) {// Export assignment submissions that have been marked by the user.$subcontexts = [get_string('privacy:markedsubmissionspath', 'mod_assignment'),transform::user($submissiondata->userid)];}}// Get assignment submission details object for output.$submission = self::get_assignment_submission_output($submissiondata);$itemid = $submissiondata->id;writer::with_context($context)->export_data($subcontexts, $submission)->export_area_files($subcontexts, 'mod_assignment', 'submission', $itemid);}}}/*** 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();$assignmentpreferences = ['assignment_filter' => ['string' => get_string('privacy:metadata:assignmentfilter', 'mod_assignment'),'bool' => false],'assignment_mailinfo' => ['string' => get_string('privacy:metadata:assignmentmailinfo', 'mod_assignment'),'bool' => false],'assignment_perpage' => ['string' => get_string('privacy:metadata:assignmentperpage', 'mod_assignment'),'bool' => false],'assignment_quickgrade' => ['string' => get_string('privacy:metadata:assignmentquickgrade', 'mod_assignment'),'bool' => false],];foreach ($assignmentpreferences 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_assignment', $key, $value, $preference['string']);}}}/*** Delete all data for all users in the specified context.** @param \context $context the context to delete in.*/public static function delete_data_for_all_users_in_context(\context $context) {global $DB;if ($context->contextlevel == CONTEXT_MODULE) {// Delete all assignment submissions for the assignment associated with the context module.$assignment = self::get_assignment_by_context($context);if ($assignment != null) {$DB->delete_records('assignment_submissions', ['assignment' => $assignment->id]);// Delete all file uploads associated with the assignment submission for the specified context.$fs = get_file_storage();$fs->delete_area_files($context->id, 'mod_assignment', 'submission');}}}/*** Delete all user data for the specified user, in the specified contexts.** @param approved_contextlist $contextlist a list of contexts approved for deletion.*/public static function delete_data_for_user(approved_contextlist $contextlist) {global $DB;if (empty($contextlist->count())) {return;}$userid = $contextlist->get_user()->id;// Only retrieve assignment submissions submitted by the user for deletion.$assignmentsubmissionids = array_keys(self::get_assignment_submissions_by_contextlist($contextlist, $userid));$DB->delete_records_list('assignment_submissions', 'id', $assignmentsubmissionids);// Delete all file uploads associated with the assignment submission for the user's specified list of contexts.$fs = get_file_storage();foreach ($contextlist->get_contextids() as $contextid) {foreach ($assignmentsubmissionids as $submissionid) {$fs->delete_area_files($contextid, 'mod_assignment', 'submission', $submissionid);}}}/*** Delete multiple users within a single context.** @param approved_userlist $userlist The approved context and user information to delete information for.*/public static function delete_data_for_users(approved_userlist $userlist) {global $DB;$context = $userlist->get_context();// If the context isn't for a module then return early.if ($context->contextlevel != CONTEXT_MODULE) {return;}// Fetch the assignment.$assignment = self::get_assignment_by_context($context);$userids = $userlist->get_userids();list($inorequalsql, $params) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);$params['assignmentid'] = $assignment->id;// Get submission ids.$sql = "SELECT s.idFROM {assignment_submissions} sJOIN {assignment} a ON s.assignment = a.idWHERE a.id = :assignmentidAND s.userid $inorequalsql";$submissionids = $DB->get_records_sql($sql, $params);list($submissionidsql, $submissionparams) = $DB->get_in_or_equal(array_keys($submissionids), SQL_PARAMS_NAMED);$fs = get_file_storage();$fs->delete_area_files_select($context->id, 'mod_assignment', 'submission', $submissionidsql, $submissionparams);// Delete related tables.$DB->delete_records_list('assignment_submissions', 'id', array_keys($submissionids));}// Start of helper functions./*** Helper function to check if a user has marked assignment submissions for a given assignment.** @param int $assignmentid The assignment ID to check if user has marked associated submissions.* @param int $userid The user ID to check if user has marked associated submissions.* @return bool If user has marked associated submissions returns true, otherwise false.* @throws \dml_exception*/protected static function has_marked_assignment_submissions($assignmentid, $userid) {global $DB;$params = ['assignment' => $assignmentid,'teacher' => $userid];$sql = "SELECT count(s.id) as nomarkedFROM {assignment_submissions} sWHERE s.assignment = :assignmentAND s.teacher = :teacher";$results = $DB->get_record_sql($sql, $params);return ($results->nomarked > 0) ? true : false;}/*** Helper function to return assignment for a context module.** @param object $context The context module object to return the assignment record by.* @return mixed The assignment details or null record associated with the context module.* @throws \dml_exception*/protected static function get_assignment_by_context($context) {global $DB;$params = ['modulename' => 'assignment','contextmodule' => CONTEXT_MODULE,'contextid' => $context->id];$sql = "SELECT a.id,a.name,a.intro,a.assignmenttype,a.grade,a.timedue,a.timeavailable,a.timemodifiedFROM {assignment} aJOIN {course_modules} cm ON a.id = cm.instanceJOIN {modules} m ON m.id = cm.module AND m.name = :modulenameJOIN {context} ctx ON ctx.instanceid = cm.id AND ctx.contextlevel = :contextmoduleWHERE ctx.id = :contextid";return $DB->get_record_sql($sql, $params);}/*** Helper function to return assignment submissions submitted by / marked by a user and their contextlist.** @param object $contextlist Object with the contexts related to a userid to retrieve assignment submissions by.* @param int $userid The user ID to find assignment submissions that were submitted by.* @param bool $teacher The teacher status to determine if marked assignment submissions should be returned.* @return array Array of assignment submission details.* @throws \coding_exception* @throws \dml_exception*/protected static function get_assignment_submissions_by_contextlist($contextlist, $userid, $teacher = false) {global $DB;list($contextsql, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);$params = ['contextmodule' => CONTEXT_MODULE,'modulename' => 'assignment','userid' => $userid];$sql = "SELECT s.id as id,s.assignment as assignment,s.numfiles as numfiles,s.data1 as data1,s.data2 as data2,s.grade as grade,s.submissioncomment as submissioncomment,s.teacher as teacher,s.timemarked as timemarked,s.timecreated as timecreated,s.timemodified as timemodifiedFROM {context} ctxJOIN {course_modules} cm ON cm.id = ctx.instanceid AND ctx.contextlevel = :contextmoduleJOIN {modules} m ON cm.module = m.id AND m.name = :modulenameJOIN {assignment} a ON cm.instance = a.idJOIN {assignment_submissions} s ON s.assignment = a.idWHERE (s.userid = :userid";if ($teacher == true) {$sql .= " OR s.teacher = :teacher";$params['teacher'] = $userid;}$sql .= ")";$sql .= " AND ctx.id {$contextsql}";$params += $contextparams;return $DB->get_records_sql($sql, $params);}/*** Helper function to retrieve assignment submissions submitted by / marked by a user for a specific assignment.** @param int $assignmentid The assignment ID to retrieve assignment submissions by.* @param int $userid The user ID to retrieve assignment submissions submitted / marked by.* @param bool $teacher The teacher status to determine if marked assignment submissions should be returned.* @return array Array of assignment submissions details.* @throws \dml_exception*/protected static function get_assignment_submissions_by_assignment($assignmentid, $userid, $teacher = false) {global $DB;$params = ['assignment' => $assignmentid,'userid' => $userid];$sql = "SELECT s.id as id,s.assignment as assignment,s.numfiles as numfiles,s.data1 as data1,s.data2 as data2,s.grade as grade,s.submissioncomment as submissioncomment,s.teacher as teacher,s.timemarked as timemarked,s.timecreated as timecreated,s.timemodified as timemodified,s.userid as useridFROM {assignment_submissions} sWHERE s.assignment = :assignmentAND (s.userid = :userid";if ($teacher == true) {$sql .= " OR s.teacher = :teacher";$params['teacher'] = $userid;}$sql .= ")";return $DB->get_records_sql($sql, $params);}/*** Helper function generate assignment output object for exporting.** @param object $assignmentdata Object containing assignment data.* @return object Formatted assignment output object for exporting.*/protected static function get_assignment_output($assignmentdata) {$assignment = (object) ['name' => $assignmentdata->name,'intro' => $assignmentdata->intro,'assignmenttype' => $assignmentdata->assignmenttype,'grade' => $assignmentdata->grade,'timemodified' => transform::datetime($assignmentdata->timemodified)];if ($assignmentdata->timeavailable != 0) {$assignment->timeavailable = transform::datetime($assignmentdata->timeavailable);}if ($assignmentdata->timedue != 0) {$assignment->timedue = transform::datetime($assignmentdata->timedue);}return $assignment;}/*** Helper function generate assignment submission output object for exporting.** @param object $submissiondata Object containing assignment submission data.* @return object Formatted assignment submission output for exporting.*/protected static function get_assignment_submission_output($submissiondata) {$submission = (object) ['assignment' => $submissiondata->assignment,'numfiles' => $submissiondata->numfiles,'data1' => $submissiondata->data1,'data2' => $submissiondata->data2,'grade' => $submissiondata->grade,'submissioncomment' => $submissiondata->submissioncomment,'teacher' => transform::user($submissiondata->teacher)];if ($submissiondata->timecreated != 0) {$submission->timecreated = transform::datetime($submissiondata->timecreated);}if ($submissiondata->timemarked != 0) {$submission->timemarked = transform::datetime($submissiondata->timemarked);}if ($submissiondata->timemodified != 0) {$submission->timemodified = transform::datetime($submissiondata->timemodified);}return $submission;}}