this introduces portfolio/file.php to serve portfolio related files - access check is delegated to the plugin.
and also two new classes in the portfolio plugin tree - push vs pull.
$string['addnewportfolio'] = 'Add a new portfolio';
$string['addtoportfolio'] = 'Add to portfolio';
-$string['alreadyexporting'] = 'You already have an active portfolio export in this session. Please complete that first';
+$string['alreadyexporting'] = 'You already have an active portfolio export in this session. Please complete that first, or <a href=\"$a\">click here</a> to cancel it.';
$string['availableformats'] = 'Available export formats';
$string['callercouldnotpackage'] = 'Failed to package up your data for export';
$string['cannotsetvisible'] = 'Cannot set this to visible - the plugin has been completely disabled because of a misconfiguration';
$string['exportqueued'] = 'Portfolio export has been successfully queued for transfer';
$string['exportedpreviously'] = 'Previous exports';
$string['failedtosendpackage'] = 'Failed to send your data to the selected portfolio system!';
+$string['filedenied'] = 'Access denied to this file';
+$string['filenotfound'] = 'File not found';
$string['format_file'] = 'File';
$string['format_mbkp'] = 'Moodle Backup';
$string['hidden'] = 'Hidden';
$string['instancenotsaved'] = 'Failed to save portfolio';
$string['instancenotdelete'] = 'Failed to delete portfolio';
$string['instancesaved'] = 'Portfolio saved successfully';
-$string['invalidtempid'] = 'Invalid temporary id';
+$string['invalidtempid'] = 'Invalid export id. maybe it has expired';
$string['invalidformat'] = 'Something is exporting an invalid format, $a';
$string['invalidinstance'] = 'Could not find that portfolio instance';
$string['manageportfolios'] = 'Manage portfolios';
}
if (isset($SESSION->portfolioexport)) {
- print_error('alreadyexporting', 'portfolio');
+ print_error('alreadyexporting', 'portfolio', null, $CFG->wwwroot . '/portfolio/add.php?cancel=1');
}
if (empty($callbackfile)) {
*/
public abstract function expected_time($callertime);
+ /**
+ * is this plugin push or pill.
+ * if push, cleanup will be called directly after send_package
+ * if not, cleanup will be called after portfolio/file.php is requested
+ *
+ * @return boolean
+ */
+ public abstract function is_push();
+
/**
* check sanity of plugin
* if this function returns something non empty, ALL instances of your plugin
}
}
+/**
+* class to inherit from for 'push' type plugins
+*/
+abstract class portfolio_plugin_push_base extends portfolio_plugin_base {
+
+ public function is_push() {
+ return true;
+ }
+}
+
+/**
+* class to inherit from for 'pull' type plugins
+*/
+abstract class portfolio_plugin_pull_base extends portfolio_plugin_base {
+
+ private $file;
+
+ public function is_push() {
+ return false;
+ }
+
+
+ /**
+ * before sending the file when the pull is requested, verify the request parameters
+ * these might include a token of some sort of whatever
+ *
+ * @param array request parameters (POST wins over GET)
+ */
+ public abstract function verify_file_request_params($params);
+
+}
+
/**
* this is the form that is actually used while exporting.
* plugins and callers don't get to define their own class
if (!$alreadystolen && $url = $this->instance->steal_control($stage)) {
$this->set('stage', $stage);
$this->save();
- //$SESSION->portfolio->stagepresteal = $stage;
redirect($url);
break;
}
*/
public function process_stage_config() {
- //global $SESSION;
-
$pluginobj = $callerobj = null;
if ($this->instance->has_export_config()) {
$pluginobj = $this->instance;
$mform = new portfolio_export_form('', $customdata);
if ($mform->is_cancelled()){
$this->cancel_request();
- /*
- unset($SESSION->portfolio);
- redirect($this->caller->get_return_url());
- exit;
- */
} else if ($fromform = $mform->get_data()){
if (!confirm_sesskey()) {
return $this->raise_error('confirmsesskeybad', '', $caller->get_return_url());
*
* @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
*/
- public function process_stage_cleanup() {
+ public function process_stage_cleanup($pullok=false) {
global $CFG, $DB, $SESSION;
+
+ if (!$pullok && !$this->get('instance')->is_push()) {
+ unset($SESSION->portfolioexport);
+ return true;
+ }
// @todo maybe add a hook in the plugin(s)
$DB->delete_records('portfolio_tempdata', array('id' => $this->id));
$fs = get_file_storage();
* @return boolean whether or not to process the next stage. this is important as the control function is called recursively.
*/
public function process_stage_finished($queued=false) {
- //global $SESSION;
$returnurl = $this->caller->get_return_url();
$continueurl = $this->instance->get_continue_url();
$extras = $this->instance->get_extra_finish_options();
}
}
print_footer();
- //unset($SESSION->portfolio);
return false;
}
* error handler - decides whether we're running interactively or not
* and behaves accordingly
*/
- public function raise_error($string, $module='moodle', $continue=null) {
+ public function raise_error($string, $module='moodle', $continue=null, $a=null) {
if (defined('FULLME') && FULLME == 'cron') {
debugging(get_string($string, $module));
return false;
}
if (isset($this)) {
- $this->process_stage_cleanup();
+ $this->process_stage_cleanup(true);
}
- //global $SESSION;
- //unset($SESSION->portfolio);
- print_error($string, $module, $continue);
+ print_error($string, $module, $continue, $a);
}
public function cancel_request() {
if (!isset($this)) {
return;
}
- $this->process_stage_cleanup();
+ $this->process_stage_cleanup(true);
redirect($this->caller->get_return_url());
exit;
}
public static function rewaken_object($id) {
global $DB, $CFG;
if (!$data = $DB->get_record('portfolio_tempdata', array('id' => $id))) {
- portfolio_exporer::raise_error('invalidtempid', 'portfolio');
+ portfolio_exporter::raise_error('invalidtempid', 'portfolio');
}
$exporter = unserialize(base64_decode($data->data));
if ($exporter->instancefile) {
if (empty($files)) {
return array();
}
- return $files;
+ $returnfiles = array();
+ foreach ($files as $f) {
+ $returnfiles[$f->get_filename()] = $f;
+ }
+ return $returnfiles;
}
/**
$exporter = portfolio_exporter::rewaken_object($dataid);
if ($cancel = optional_param('cancel', 0, PARAM_RAW)) {
$exporter->cancel_request();
- /*
- $returnurl = $exporter->get('caller')->get_return_url();
- unset($SESSION->portfolio);
- redirect($returnurl);
- */
}
if (!$exporter->get('instance')) {
if ($instance = optional_param('instance', '', PARAM_INT)) {
$mform = new portfolio_instance_select('', array('caller' => $exporter->get('caller')));
if ($mform->is_cancelled()) {
$exporter->cancel_request();
- /*
- $returnurl = $caller->get_return_url();
- unset($SESSION->portfolio);
- redirect($returnurl);
- exit;
- */
} else if ($fromform = $mform->get_data()){
redirect($CFG->wwwroot . '/portfolio/add.php?instance=' . $fromform->instance . '&id=' . $exporter->get('id'));
exit;
--- /dev/null
+<?php
+require_once(dirname(dirname(__FILE__)) . '/config.php');
+require_once($CFG->libdir . '/portfoliolib.php');
+require_once($CFG->libdir . '/file/stored_file.php');
+require_once($CFG->libdir . '/filelib.php');
+
+$id = required_param('id', PARAM_INT);
+
+$exporter = portfolio_exporter::rewaken_object($id);
+
+if ($exporter->get('instance')->is_push()) {
+ $exporter->raise_error('filedenied', 'portfolio');
+}
+
+if (!$exporter->get('instance')->verify_file_request_params(array_merge($_GET, $_POST))) {
+ $exporter->raise_error('filedenied', 'portfolio');
+}
+
+$file = $exporter->get('instance')->get('file');
+if (!($file instanceof stored_file)) {
+ $exporter->raise_error('filenotfound', 'portfolio');
+}
+
+send_stored_file($file, 0, 0, true, null, true);
+$exporter->process_stage_cleanup(true);
+
+?>
require_once($CFG->libdir.'/filelib.php');
require_once($CFG->dirroot.'/repository/boxnet/boxlibphp5.php');
-class portfolio_plugin_boxnet extends portfolio_plugin_base {
+class portfolio_plugin_boxnet extends portfolio_plugin_push_base {
private $boxclient;
private $ticket;
<?php
require_once($CFG->libdir . '/portfoliolib.php');
+require_once($CFG->libdir . '/packer/zip_packer.php');
-class portfolio_plugin_download extends portfolio_plugin_base {
+class portfolio_plugin_download extends portfolio_plugin_pull_base {
- protected $zipfile;
+ protected $file;
protected $exportconfig;
public static function allows_multiple() {
}
public function prepare_package() {
- // just zip up whatever files the caller has created for us
- // and move them to the user's temporary area.
- $userdir = temp_portfolio_usertemp_directory($this->get('user')->id);
-
- $newfile = 'portfolio_export_' . time() . '.zip';
- $files = get_directory_list($tempdir);
- foreach ($files as $key => $file) {
- $files[$key] = $tempdir . '/' . $file;
- }
- zip_files($files, $userdir . '/' . $newfile);
- $this->set('zipfile', $newfile);
+ $files = $this->exporter->get_tempfiles();
+ $zipper = new zip_packer();
- return true;
+ $filename = 'portfolio-export.zip';
+ if ($newfile = $zipper->archive_to_storage($files, SYSCONTEXTID, 'portfolio_exporter', $this->exporter->get('id'), '/final/', $filename, $this->user->id)) {
+ $this->set('file', $newfile);
+ return true;
+ }
+ return false;
}
public function send_package() {
public function get_extra_finish_options() {
global $CFG;
- return array(
- // @todo this will go through files api later, this is a (nonworking) hack for now.
- $CFG->wwwroot . '/file.php?file=' . $this->zipfile => get_string('downloadfile', 'portfolio_download'),
- );
+ return array($CFG->wwwroot . '/portfolio/file.php?id=' . $this->exporter->get('id') => get_string('downloadfile', 'portfolio_download'));
}
- public function get_continue_url() {
- return false;
+ public function verify_file_request_params($params) {
+ // for download plugin the only thing we need to verify is that
+ // the logged in user is the same as the exporting user
+ global $USER;
+ if ($USER->id != $this->user->id) {
+ return false;
+ }
+ return true;
}
- public static function plugin_sanity_check() {
- return 'notupgradedtousefilesapi';
+ public function get_continue_url() {
+ return false;
}
}