Merge branch 'wip-MDL-33550-master' of git://github.com/marinaglancy/moodle

This commit is contained in:
Dan Poltawski 2012-06-14 16:23:08 +08:00
commit 4585e6ac98
18 changed files with 366 additions and 323 deletions

View file

@ -1090,16 +1090,39 @@ abstract class repository {
}
/**
* Repository method to serve file
* Repository method to serve the referenced file
*
* @param stored_file $storedfile
* @see send_stored_file
*
* @param stored_file $storedfile the file that contains the reference
* @param int $lifetime Number of seconds before the file should expire from caches (default 24 hours)
* @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
* @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
* @param array $options additional options affecting the file serving
*/
public function send_file($storedfile, $lifetime=86400 , $filter=0, $forcedownload=false, array $options = null) {
throw new coding_exception("Repository plugin must implement send_file() method.");
if ($this->has_moodle_files()) {
$fs = get_file_storage();
$params = file_storage::unpack_reference($storedfile->get_reference(), true);
$srcfile = null;
if (is_array($params)) {
$srcfile = $fs->get_file($params['contextid'], $params['component'], $params['filearea'],
$params['itemid'], $params['filepath'], $params['filename']);
}
if (empty($options)) {
$options = array();
}
if (!isset($options['filename'])) {
$options['filename'] = $storedfile->get_filename();
}
if (!$srcfile) {
send_file_not_found();
} else {
send_stored_file($srcfile, $lifetime, $filter, $forcedownload, $options);
}
} else {
throw new coding_exception("Repository plugin must implement send_file() method.");
}
}
/**
@ -1128,10 +1151,35 @@ abstract class repository {
* {@link stored_file::get_reference()}
*
* @param string $reference
* @return string|null
* @param int $filestatus status of the file, 0 - ok, 666 - source missing
* @return string
*/
public function get_reference_details($reference) {
return null;
public function get_reference_details($reference, $filestatus = 0) {
if ($this->has_moodle_files()) {
$fileinfo = null;
$params = file_storage::unpack_reference($reference, true);
if (is_array($params)) {
$context = get_context_instance_by_id($params['contextid']);
if ($context) {
$browser = get_file_browser();
$fileinfo = $browser->get_file_info($context, $params['component'], $params['filearea'], $params['itemid'], $params['filepath'], $params['filename']);
}
}
if (empty($fileinfo)) {
if ($filestatus == 666) {
if (is_siteadmin() || ($context && has_capability('moodle/course:managefiles', $context))) {
return get_string('lostsource', 'repository',
$params['contextid']. '/'. $params['component']. '/'. $params['filearea']. '/'. $params['itemid']. $params['filepath']. $params['filename']);
} else {
return get_string('lostsource', 'repository', '');
}
}
return get_string('undisclosedsource', 'repository');
} else {
return $fileinfo->get_readable_fullname();
}
}
return '';
}
/**
@ -1148,14 +1196,33 @@ abstract class repository {
}
/**
* Get file from external repository by reference
* Returns information about file in this repository by reference
* {@link repository::get_file_reference()}
* {@link repository::get_file()}
*
* Returns null if file not found or is not readable
*
* @param stdClass $reference file reference db record
* @return stdClass|null|false
* @return stdClass|null contains one of the following:
* - 'contenthash' and 'filesize'
* - 'filepath'
* - 'handle'
* - 'content'
*/
public function get_file_by_reference($reference) {
if ($this->has_moodle_files() && isset($reference->reference)) {
$fs = get_file_storage();
$params = file_storage::unpack_reference($reference->reference, true);
if (!is_array($params) || !($storedfile = $fs->get_file($params['contextid'],
$params['component'], $params['filearea'], $params['itemid'], $params['filepath'],
$params['filename']))) {
return null;
}
return (object)array(
'contenthash' => $storedfile->get_contenthash(),
'filesize' => $storedfile->get_filesize()
);
}
return null;
}
@ -1433,6 +1500,13 @@ abstract class repository {
* @return string file referece
*/
public function get_file_reference($source) {
if ($this->has_moodle_files() && ($this->supported_returntypes() & FILE_REFERENCE)) {
$params = file_storage::unpack_reference($source);
if (!is_array($params)) {
throw new repository_exception('invalidparams', 'repository');
}
return file_storage::pack_reference($params);
}
return $source;
}
/**
@ -1484,16 +1558,22 @@ abstract class repository {
*
* @param string $url the url of file
* @param string $filename save location
* @return string the location of the file
* @return array with elements:
* path: internal location of the file
* url: URL to the source (from parameters)
*/
public function get_file($url, $filename = '') {
global $CFG;
$path = $this->prepare_file($filename);
$fp = fopen($path, 'w');
$c = new curl;
$c->download(array(array('url'=>$url, 'file'=>$fp)));
$result = $c->download(array(array('url'=>$url, 'file'=>$fp)));
// Close file handler.
fclose($fp);
if (empty($result)) {
unlink($path);
return null;
}
return array('path'=>$path, 'url'=>$url);
}
@ -2137,25 +2217,47 @@ abstract class repository {
}
}
/**
* Called from phpunit between tests, resets whatever was cached
*/
public static function reset_caches() {
self::sync_external_file(null, true);
}
/**
* Call to request proxy file sync with repository source.
*
* @param stored_file $file
* @param bool $resetsynchistory whether to reset all history of sync (used by phpunit)
* @return bool success
*/
public static function sync_external_file(stored_file $file) {
public static function sync_external_file($file, $resetsynchistory = false) {
global $DB;
// TODO MDL-25290 static should be replaced with MUC code.
static $synchronized = array();
if ($resetsynchistory) {
$synchronized = array();
}
$fs = get_file_storage();
if (!$file || !$file->get_referencefileid()) {
return false;
}
if (array_key_exists($file->get_id(), $synchronized)) {
return $synchronized[$file->get_id()];
}
// remember that we already cached in current request to prevent from querying again
$synchronized[$file->get_id()] = false;
if (!$reference = $DB->get_record('files_reference', array('id'=>$file->get_referencefileid()))) {
return false;
}
if (!empty($reference->lastsync) and ($reference->lastsync + $reference->lifetime > time())) {
return false;
$synchronized[$file->get_id()] = true;
return true;
}
if (!$repository = self::get_repository_by_id($reference->repositoryid, SYSCONTEXTID)) {
@ -2169,14 +2271,10 @@ abstract class repository {
$fileinfo = $repository->get_file_by_reference($reference);
if ($fileinfo === null) {
// does not exist any more - set status to missing
$sql = "UPDATE {files} SET status = :missing WHERE referencefileid = :referencefileid";
$params = array('referencefileid'=>$reference->id, 'missing'=>666);
$DB->execute($sql, $params);
$file->set_missingsource();
//TODO: purge content from pool if we set some other content hash and it is no used any more
$synchronized[$file->get_id()] = true;
return true;
} else if ($fileinfo === false) {
// error
return false;
}
$contenthash = null;
@ -2205,15 +2303,9 @@ abstract class repository {
return false;
}
$now = time();
// update files table
$sql = "UPDATE {files} SET contenthash = :contenthash, filesize = :filesize, referencelastsync = :now, referencelifetime = :lifetime, timemodified = :now2 WHERE referencefileid = :referencefileid AND contenthash <> :contenthash2";
$params = array('contenthash'=>$contenthash, 'filesize'=>$filesize, 'now'=>$now, 'lifetime'=>$reference->lifetime,
'now2'=>$now, 'referencefileid'=>$reference->id, 'contenthash2'=>$contenthash);
$DB->execute($sql, $params);
$DB->set_field('files_reference', 'lastsync', $now, array('id'=>$reference->id));
$file->set_synchronized($contenthash, $filesize);
$synchronized[$file->get_id()] = true;
return true;
}
}