MDL-36754 core_files: Add a token version of pluginfile

This commit is contained in:
Andrew Nicols 2018-06-03 21:06:45 +08:00
parent 6e445671c1
commit 4a74ab0200
5 changed files with 150 additions and 5 deletions

View file

@ -27,6 +27,8 @@ namespace core_files\privacy;
defined('MOODLE_INTERNAL') || die(); defined('MOODLE_INTERNAL') || die();
use core_privacy\local\metadata\collection; use core_privacy\local\metadata\collection;
use core_privacy\local\request\contextlist;
use core_privacy\local\request\approved_contextlist;
/** /**
* Data provider class. * Data provider class.
@ -41,7 +43,10 @@ use core_privacy\local\metadata\collection;
*/ */
class provider implements class provider implements
\core_privacy\local\metadata\provider, \core_privacy\local\metadata\provider,
\core_privacy\local\request\subsystem\plugin_provider { \core_privacy\local\request\subsystem\plugin_provider,
// We store a userkey for token-based file access.
\core_privacy\local\request\subsystem\provider {
/** /**
* Returns metadata. * Returns metadata.
@ -65,7 +70,95 @@ class provider implements
'timemodified' => 'privacy:metadata:files:timemodified', 'timemodified' => 'privacy:metadata:files:timemodified',
], 'privacy:metadata:files'); ], 'privacy:metadata:files');
$collection->add_subsystem_link('core_userkey', [], 'privacy:metadata:core_userkey');
return $collection; return $collection;
} }
/**
* Get the list of contexts that contain user information for the specified user.
*
* This is currently just the user context.
*
* @param int $userid The user to search.
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
*/
public static function get_contexts_for_userid(int $userid) : contextlist {
$sql = "SELECT ctx.id
FROM {user_private_key} k
JOIN {user} u ON k.userid = u.id
JOIN {context} ctx ON ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel
WHERE k.userid = :userid AND k.script = :script";
$params = [
'userid' => $userid,
'contextlevel' => CONTEXT_USER,
'script' => 'core_files',
];
$contextlist = new contextlist();
$contextlist->add_from_sql($sql, $params);
return $contextlist;
}
/**
* Export all user data for the specified user, in the specified contexts.
*
* @param approved_contextlist $contextlist The approved contexts to export information for.
*/
public static function export_user_data(approved_contextlist $contextlist) {
// If the user has data, then only the CONTEXT_USER should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
return;
}
// Sanity check that context is at the user context level, then get the userid.
$context = reset($contexts);
if ($context->contextlevel !== CONTEXT_USER) {
return;
}
// Export associated userkeys.
$subcontext = [
get_string('files'),
];
\core_userkey\privacy\provider::export_userkeys($context, $subcontext, 'core_files');
}
/**
* Delete all use data which matches the specified deletion_criteria.
*
* @param context $context A user context.
*/
public static function delete_data_for_all_users_in_context(\context $context) {
// Sanity check that context is at the user context level, then get the userid.
if ($context->contextlevel !== CONTEXT_USER) {
return;
}
// Delete all the userkeys.
\core_userkey\privacy\provider::delete_userkeys('core_files', $context->instanceid);
}
/**
* 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) {
// If the user has data, then only the user context should be present so get the first context.
$contexts = $contextlist->get_contexts();
if (count($contexts) == 0) {
return;
}
// Sanity check that context is at the user context level, then get the userid.
$context = reset($contexts);
if ($context->contextlevel !== CONTEXT_USER) {
return;
}
// Delete all the userkeys for core_files..
\core_userkey\privacy\provider::delete_userkeys('core_files', $context->instanceid);
}
} }

View file

@ -37,3 +37,4 @@ $string['privacy:metadata:files:source'] = 'The source of the file';
$string['privacy:metadata:files:timecreated'] = 'The time when the file was created'; $string['privacy:metadata:files:timecreated'] = 'The time when the file was created';
$string['privacy:metadata:files:timemodified'] = 'The time when the file was last modified'; $string['privacy:metadata:files:timemodified'] = 'The time when the file was last modified';
$string['privacy:metadata:files:userid'] = 'The user who created the file'; $string['privacy:metadata:files:userid'] = 'The user who created the file';
$string['privacy:metadata:core_userkey'] = 'A private token is generated and stored. This token can be used to access Moodle files without requiring you to log in.';

View file

@ -3112,9 +3112,10 @@ function validate_user_key($keyvalue, $script, $instance) {
* @uses PARAM_ALPHANUM * @uses PARAM_ALPHANUM
* @param string $script unique script identifier * @param string $script unique script identifier
* @param int $instance optional instance id * @param int $instance optional instance id
* @param string $keyvalue The key. If not supplied, this will be fetched from the current session.
* @return int Instance ID * @return int Instance ID
*/ */
function require_user_key_login($script, $instance=null) { function require_user_key_login($script, $instance = null, $keyvalue = null) {
global $DB; global $DB;
if (!NO_MOODLE_COOKIES) { if (!NO_MOODLE_COOKIES) {
@ -3124,7 +3125,9 @@ function require_user_key_login($script, $instance=null) {
// Extra safety. // Extra safety.
\core\session\manager::write_close(); \core\session\manager::write_close();
$keyvalue = required_param('key', PARAM_ALPHANUM); if (null === $keyvalue) {
$keyvalue = required_param('key', PARAM_ALPHANUM);
}
$key = validate_user_key($keyvalue, $script, $instance); $key = validate_user_key($keyvalue, $script, $instance);

View file

@ -25,12 +25,16 @@
*/ */
// Disable moodle specific debug messages and any errors in output. // Disable moodle specific debug messages and any errors in output.
define('NO_DEBUG_DISPLAY', true); if (!defined('NO_DEBUG_DISPLAY')) {
define('NO_DEBUG_DISPLAY', true);
}
require_once('config.php'); require_once('config.php');
require_once('lib/filelib.php'); require_once('lib/filelib.php');
$relativepath = get_file_argument(); if (empty($relativepath)) {
$relativepath = get_file_argument();
}
$forcedownload = optional_param('forcedownload', 0, PARAM_BOOL); $forcedownload = optional_param('forcedownload', 0, PARAM_BOOL);
$preview = optional_param('preview', null, PARAM_ALPHANUM); $preview = optional_param('preview', null, PARAM_ALPHANUM);
// Offline means download the file from the repository and serve it, even if it was an external link. // Offline means download the file from the repository and serve it, even if it was an external link.

44
tokenpluginfile.php Normal file
View file

@ -0,0 +1,44 @@
<?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/>.
/**
* Entry point for token-based access to pluginfile.php.
*
* @package core
* @copyright 2018 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
// Disable the use of sessions/cookies - we recreate $USER for every call.
define('NO_MOODLE_COOKIES', true);
// Disable debugging for this script.
// It is typically used to display images.
define('NO_DEBUG_DISPLAY', true);
require_once('config.php');
$relativepath = get_file_argument();
$token = optional_param('token', '', PARAM_ALPHANUM);
if (0 == strpos($relativepath, '/token/')) {
$relativepath = ltrim($relativepath, '/');
$pathparts = explode('/', $relativepath, 2);
$token = $pathparts[0];
$relativepath = "/{$pathparts[1]}";
}
require_user_key_login('core_files', null, $token);
require_once('pluginfile.php');