| 1 | efrain | 1 | <?php
 | 
        
           |  |  | 2 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 3 | //
 | 
        
           |  |  | 4 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 5 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 6 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 7 | // (at your option) any later version.
 | 
        
           |  |  | 8 | //
 | 
        
           |  |  | 9 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 12 | // GNU General Public License for more details.
 | 
        
           |  |  | 13 | //
 | 
        
           |  |  | 14 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 15 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 16 |   | 
        
           |  |  | 17 | /**
 | 
        
           |  |  | 18 |  * This plugin is used to access Google Drive.
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * @since Moodle 2.0
 | 
        
           |  |  | 21 |  * @package    repository_googledocs
 | 
        
           |  |  | 22 |  * @copyright  2009 Dan Poltawski <talktodan@gmail.com>
 | 
        
           |  |  | 23 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 24 |  */
 | 
        
           |  |  | 25 |   | 
        
           |  |  | 26 | defined('MOODLE_INTERNAL') || die();
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 | require_once($CFG->dirroot . '/repository/lib.php');
 | 
        
           |  |  | 29 | require_once($CFG->libdir . '/filebrowser/file_browser.php');
 | 
        
           |  |  | 30 |   | 
        
           |  |  | 31 | use repository_googledocs\helper;
 | 
        
           |  |  | 32 | use repository_googledocs\googledocs_content_search;
 | 
        
           |  |  | 33 |   | 
        
           |  |  | 34 | /**
 | 
        
           |  |  | 35 |  * Google Docs Plugin
 | 
        
           |  |  | 36 |  *
 | 
        
           |  |  | 37 |  * @since Moodle 2.0
 | 
        
           |  |  | 38 |  * @package    repository_googledocs
 | 
        
           |  |  | 39 |  * @copyright  2009 Dan Poltawski <talktodan@gmail.com>
 | 
        
           |  |  | 40 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 41 |  */
 | 
        
           |  |  | 42 | class repository_googledocs extends repository {
 | 
        
           |  |  | 43 |   | 
        
           |  |  | 44 |     /**
 | 
        
           |  |  | 45 |      * OAuth 2 client
 | 
        
           |  |  | 46 |      * @var \core\oauth2\client
 | 
        
           |  |  | 47 |      */
 | 
        
           |  |  | 48 |     private $client = null;
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 |     /**
 | 
        
           |  |  | 51 |      * OAuth 2 Issuer
 | 
        
           |  |  | 52 |      * @var \core\oauth2\issuer
 | 
        
           |  |  | 53 |      */
 | 
        
           |  |  | 54 |     private $issuer = null;
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 |     /**
 | 
        
           |  |  | 57 |      * Additional scopes required for drive.
 | 
        
           |  |  | 58 |      */
 | 
        
           |  |  | 59 |     const SCOPES = 'https://www.googleapis.com/auth/drive';
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 |     /** @var string Defines the path node identifier for the repository root. */
 | 
        
           |  |  | 62 |     const REPOSITORY_ROOT_ID = 'repository_root';
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 |     /** @var string Defines the path node identifier for the my drive root. */
 | 
        
           |  |  | 65 |     const MY_DRIVE_ROOT_ID = 'root';
 | 
        
           |  |  | 66 |   | 
        
           |  |  | 67 |     /** @var string Defines the path node identifier for the shared drives root. */
 | 
        
           |  |  | 68 |     const SHARED_DRIVES_ROOT_ID = 'shared_drives_root';
 | 
        
           |  |  | 69 |   | 
        
           |  |  | 70 |     /** @var string Defines the path node identifier for the content search root. */
 | 
        
           |  |  | 71 |     const SEARCH_ROOT_ID = 'search';
 | 
        
           |  |  | 72 |   | 
        
           |  |  | 73 |     /**
 | 
        
           |  |  | 74 |      * Constructor.
 | 
        
           |  |  | 75 |      *
 | 
        
           |  |  | 76 |      * @param int $repositoryid repository instance id.
 | 
        
           |  |  | 77 |      * @param int|stdClass $context a context id or context object.
 | 
        
           |  |  | 78 |      * @param array $options repository options.
 | 
        
           |  |  | 79 |      * @param int $readonly indicate this repo is readonly or not.
 | 
        
           |  |  | 80 |      * @return void
 | 
        
           |  |  | 81 |      */
 | 
        
           |  |  | 82 |     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array(), $readonly = 0) {
 | 
        
           |  |  | 83 |         parent::__construct($repositoryid, $context, $options, $readonly = 0);
 | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 |         try {
 | 
        
           |  |  | 86 |             $this->issuer = \core\oauth2\api::get_issuer(get_config('googledocs', 'issuerid'));
 | 
        
           |  |  | 87 |         } catch (dml_missing_record_exception $e) {
 | 
        
           |  |  | 88 |             $this->disabled = true;
 | 
        
           |  |  | 89 |         }
 | 
        
           |  |  | 90 |   | 
        
           |  |  | 91 |         if ($this->issuer && !$this->issuer->get('enabled')) {
 | 
        
           |  |  | 92 |             $this->disabled = true;
 | 
        
           |  |  | 93 |         }
 | 
        
           |  |  | 94 |     }
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 |     /**
 | 
        
           |  |  | 97 |      * Get a cached user authenticated oauth client.
 | 
        
           |  |  | 98 |      *
 | 
        
           |  |  | 99 |      * @param moodle_url $overrideurl - Use this url instead of the repo callback.
 | 
        
           |  |  | 100 |      * @return \core\oauth2\client
 | 
        
           |  |  | 101 |      */
 | 
        
           |  |  | 102 |     protected function get_user_oauth_client($overrideurl = false) {
 | 
        
           |  |  | 103 |         if ($this->client) {
 | 
        
           |  |  | 104 |             return $this->client;
 | 
        
           |  |  | 105 |         }
 | 
        
           |  |  | 106 |         if ($overrideurl) {
 | 
        
           |  |  | 107 |             $returnurl = $overrideurl;
 | 
        
           |  |  | 108 |         } else {
 | 
        
           |  |  | 109 |             $returnurl = new moodle_url('/repository/repository_callback.php');
 | 
        
           |  |  | 110 |             $returnurl->param('callback', 'yes');
 | 
        
           |  |  | 111 |             $returnurl->param('repo_id', $this->id);
 | 
        
           |  |  | 112 |             $returnurl->param('sesskey', sesskey());
 | 
        
           |  |  | 113 |         }
 | 
        
           |  |  | 114 |   | 
        
           |  |  | 115 |         $this->client = \core\oauth2\api::get_user_oauth_client($this->issuer, $returnurl, self::SCOPES, true);
 | 
        
           |  |  | 116 |   | 
        
           |  |  | 117 |         return $this->client;
 | 
        
           |  |  | 118 |     }
 | 
        
           |  |  | 119 |   | 
        
           |  |  | 120 |     /**
 | 
        
           |  |  | 121 |      * Checks whether the user is authenticate or not.
 | 
        
           |  |  | 122 |      *
 | 
        
           |  |  | 123 |      * @return bool true when logged in.
 | 
        
           |  |  | 124 |      */
 | 
        
           |  |  | 125 |     public function check_login() {
 | 
        
           |  |  | 126 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 127 |         return $client->is_logged_in();
 | 
        
           |  |  | 128 |     }
 | 
        
           |  |  | 129 |   | 
        
           |  |  | 130 |     /**
 | 
        
           |  |  | 131 |      * Print or return the login form.
 | 
        
           |  |  | 132 |      *
 | 
        
           |  |  | 133 |      * @return void|array for ajax.
 | 
        
           |  |  | 134 |      */
 | 
        
           |  |  | 135 |     public function print_login() {
 | 
        
           |  |  | 136 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 137 |         $url = $client->get_login_url();
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 |         if ($this->options['ajax']) {
 | 
        
           |  |  | 140 |             $popup = new stdClass();
 | 
        
           |  |  | 141 |             $popup->type = 'popup';
 | 
        
           |  |  | 142 |             $popup->url = $url->out(false);
 | 
        
           |  |  | 143 |             return array('login' => array($popup));
 | 
        
           |  |  | 144 |         } else {
 | 
        
           |  |  | 145 |             echo '<a target="_blank" href="'.$url->out(false).'">'.get_string('login', 'repository').'</a>';
 | 
        
           |  |  | 146 |         }
 | 
        
           |  |  | 147 |     }
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 |     /**
 | 
        
           |  |  | 150 |      * Print the login in a popup.
 | 
        
           |  |  | 151 |      *
 | 
        
           |  |  | 152 |      * @param array|null $attr Custom attributes to be applied to popup div.
 | 
        
           |  |  | 153 |      */
 | 
        
           |  |  | 154 |     public function print_login_popup($attr = null) {
 | 
        
           |  |  | 155 |         global $OUTPUT, $PAGE;
 | 
        
           |  |  | 156 |   | 
        
           |  |  | 157 |         $client = $this->get_user_oauth_client(false);
 | 
        
           |  |  | 158 |         $url = new moodle_url($client->get_login_url());
 | 
        
           |  |  | 159 |         $state = $url->get_param('state') . '&reloadparent=true';
 | 
        
           |  |  | 160 |         $url->param('state', $state);
 | 
        
           |  |  | 161 |   | 
        
           |  |  | 162 |         $PAGE->set_pagelayout('embedded');
 | 
        
           |  |  | 163 |         echo $OUTPUT->header();
 | 
        
           |  |  | 164 |   | 
        
           |  |  | 165 |         $repositoryname = get_string('pluginname', 'repository_googledocs');
 | 
        
           |  |  | 166 |   | 
        
           |  |  | 167 |         $button = new single_button(
 | 
        
           |  |  | 168 |             $url,
 | 
        
           |  |  | 169 |             get_string('logintoaccount', 'repository', $repositoryname),
 | 
        
           |  |  | 170 |             'post',
 | 
        
           |  |  | 171 |             single_button::BUTTON_PRIMARY
 | 
        
           |  |  | 172 |         );
 | 
        
           |  |  | 173 |         $button->add_action(new popup_action('click', $url, 'Login'));
 | 
        
           |  |  | 174 |         $button->class = 'mdl-align';
 | 
        
           |  |  | 175 |         $button = $OUTPUT->render($button);
 | 
        
           |  |  | 176 |         echo html_writer::div($button, '', $attr);
 | 
        
           |  |  | 177 |   | 
        
           |  |  | 178 |         echo $OUTPUT->footer();
 | 
        
           |  |  | 179 |     }
 | 
        
           |  |  | 180 |   | 
        
           |  |  | 181 |     /**
 | 
        
           |  |  | 182 |      * Build the breadcrumb from a path.
 | 
        
           |  |  | 183 |      *
 | 
        
           |  |  | 184 |      * @deprecated since Moodle 3.11.
 | 
        
           |  |  | 185 |      * @param string $path to create a breadcrumb from.
 | 
        
           |  |  | 186 |      * @return array containing name and path of each crumb.
 | 
        
           |  |  | 187 |      */
 | 
        
           |  |  | 188 |     protected function build_breadcrumb($path) {
 | 
        
           |  |  | 189 |         debugging('The function build_breadcrumb() is deprecated, please use get_navigation() from the ' .
 | 
        
           |  |  | 190 |             'googledocs repository content classes instead.', DEBUG_DEVELOPER);
 | 
        
           |  |  | 191 |   | 
        
           |  |  | 192 |         $bread = explode('/', $path);
 | 
        
           |  |  | 193 |         $crumbtrail = '';
 | 
        
           |  |  | 194 |         foreach ($bread as $crumb) {
 | 
        
           |  |  | 195 |             list($id, $name) = $this->explode_node_path($crumb);
 | 
        
           |  |  | 196 |             $name = empty($name) ? $id : $name;
 | 
        
           |  |  | 197 |             $breadcrumb[] = array(
 | 
        
           |  |  | 198 |                 'name' => $name,
 | 
        
           |  |  | 199 |                 'path' => $this->build_node_path($id, $name, $crumbtrail)
 | 
        
           |  |  | 200 |             );
 | 
        
           |  |  | 201 |             $tmp = end($breadcrumb);
 | 
        
           |  |  | 202 |             $crumbtrail = $tmp['path'];
 | 
        
           |  |  | 203 |         }
 | 
        
           |  |  | 204 |         return $breadcrumb;
 | 
        
           |  |  | 205 |     }
 | 
        
           |  |  | 206 |   | 
        
           |  |  | 207 |     /**
 | 
        
           |  |  | 208 |      * Generates a safe path to a node.
 | 
        
           |  |  | 209 |      *
 | 
        
           |  |  | 210 |      * Typically, a node will be id|Name of the node.
 | 
        
           |  |  | 211 |      *
 | 
        
           |  |  | 212 |      * @deprecated since Moodle 3.11.
 | 
        
           |  |  | 213 |      * @param string $id of the node.
 | 
        
           |  |  | 214 |      * @param string $name of the node, will be URL encoded.
 | 
        
           |  |  | 215 |      * @param string $root to append the node on, must be a result of this function.
 | 
        
           |  |  | 216 |      * @return string path to the node.
 | 
        
           |  |  | 217 |      */
 | 
        
           |  |  | 218 |     protected function build_node_path($id, $name = '', $root = '') {
 | 
        
           |  |  | 219 |         debugging('The function build_node_path() is deprecated, please use ' .
 | 
        
           |  |  | 220 |             '\repository_googledocs\helper::build_node_path() instead.', DEBUG_DEVELOPER);
 | 
        
           |  |  | 221 |   | 
        
           |  |  | 222 |         $path = $id;
 | 
        
           |  |  | 223 |         if (!empty($name)) {
 | 
        
           |  |  | 224 |             $path .= '|' . urlencode($name);
 | 
        
           |  |  | 225 |         }
 | 
        
           |  |  | 226 |         if (!empty($root)) {
 | 
        
           |  |  | 227 |             $path = trim($root, '/') . '/' . $path;
 | 
        
           |  |  | 228 |         }
 | 
        
           |  |  | 229 |         return $path;
 | 
        
           |  |  | 230 |     }
 | 
        
           |  |  | 231 |   | 
        
           |  |  | 232 |     /**
 | 
        
           |  |  | 233 |      * Returns information about a node in a path.
 | 
        
           |  |  | 234 |      *
 | 
        
           |  |  | 235 |      * @deprecated since Moodle 3.11.
 | 
        
           |  |  | 236 |      * @see self::build_node_path()
 | 
        
           |  |  | 237 |      * @param string $node to extrat information from.
 | 
        
           |  |  | 238 |      * @return array about the node.
 | 
        
           |  |  | 239 |      */
 | 
        
           |  |  | 240 |     protected function explode_node_path($node) {
 | 
        
           |  |  | 241 |         debugging('The function explode_node_path() is deprecated, please use ' .
 | 
        
           |  |  | 242 |             '\repository_googledocs\helper::explode_node_path() instead.', DEBUG_DEVELOPER);
 | 
        
           |  |  | 243 |   | 
        
           |  |  | 244 |         if (strpos($node, '|') !== false) {
 | 
        
           |  |  | 245 |             list($id, $name) = explode('|', $node, 2);
 | 
        
           |  |  | 246 |             $name = urldecode($name);
 | 
        
           |  |  | 247 |         } else {
 | 
        
           |  |  | 248 |             $id = $node;
 | 
        
           |  |  | 249 |             $name = '';
 | 
        
           |  |  | 250 |         }
 | 
        
           |  |  | 251 |         $id = urldecode($id);
 | 
        
           |  |  | 252 |         return array(
 | 
        
           |  |  | 253 |   | 
        
           |  |  | 254 |             1 => $name,
 | 
        
           |  |  | 255 |             'id' => $id,
 | 
        
           |  |  | 256 |             'name' => $name
 | 
        
           |  |  | 257 |         );
 | 
        
           |  |  | 258 |     }
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 |     /**
 | 
        
           |  |  | 261 |      * List the files and folders.
 | 
        
           |  |  | 262 |      *
 | 
        
           |  |  | 263 |      * @param  string $path path to browse.
 | 
        
           |  |  | 264 |      * @param  string $page page to browse.
 | 
        
           |  |  | 265 |      * @return array of result.
 | 
        
           |  |  | 266 |      */
 | 
        
           |  |  | 267 |     public function get_listing($path='', $page = '') {
 | 
        
           |  |  | 268 |         if (empty($path)) {
 | 
        
           |  |  | 269 |             $pluginname = get_string('pluginname', 'repository_googledocs');
 | 
        
           |  |  | 270 |             $path = helper::build_node_path('repository_root', $pluginname);
 | 
        
           |  |  | 271 |         }
 | 
        
           |  |  | 272 |   | 
        
           |  |  | 273 |         if (!$this->issuer->get('enabled')) {
 | 
        
           |  |  | 274 |             // Empty list of files for disabled repository.
 | 
        
           |  |  | 275 |             return [
 | 
        
           |  |  | 276 |                 'dynload' => false,
 | 
        
           |  |  | 277 |                 'list' => [],
 | 
        
           |  |  | 278 |                 'nologin' => true,
 | 
        
           |  |  | 279 |             ];
 | 
        
           |  |  | 280 |         }
 | 
        
           |  |  | 281 |   | 
        
           |  |  | 282 |         // We analyse the path to extract what to browse.
 | 
        
           |  |  | 283 |         $trail = explode('/', $path);
 | 
        
           |  |  | 284 |         $uri = array_pop($trail);
 | 
        
           |  |  | 285 |         list($id, $name) = helper::explode_node_path($uri);
 | 
        
           |  |  | 286 |         $service = new repository_googledocs\rest($this->get_user_oauth_client());
 | 
        
           |  |  | 287 |   | 
        
           |  |  | 288 |         // Define the content class object and query which will be used to get the contents for this path.
 | 
        
           |  |  | 289 |         if ($id === self::SEARCH_ROOT_ID) {
 | 
        
           |  |  | 290 |             // The special keyword 'search' is the ID of the node. This is possible as we can set up a breadcrumb in
 | 
        
           |  |  | 291 |             // the search results. Therefore, we should use the content search object to get the results from the
 | 
        
           |  |  | 292 |             // previously performed search.
 | 
        
           |  |  | 293 |             $contentobj = new googledocs_content_search($service, $path);
 | 
        
           |  |  | 294 |             // We need to deconstruct the node name in order to obtain the search term and use it as a query.
 | 
        
           |  |  | 295 |             $query = str_replace(get_string('searchfor', 'repository_googledocs'), '', $name);
 | 
        
           |  |  | 296 |             $query = trim(str_replace("'", "", $query));
 | 
        
           |  |  | 297 |         } else {
 | 
        
           |  |  | 298 |             // Otherwise, return and use the appropriate (based on the path) content browser object.
 | 
        
           |  |  | 299 |             $contentobj = helper::get_browser($service, $path);
 | 
        
           |  |  | 300 |             // Use the node ID as a query.
 | 
        
           |  |  | 301 |             $query = $id;
 | 
        
           |  |  | 302 |         }
 | 
        
           |  |  | 303 |   | 
        
           |  |  | 304 |         return [
 | 
        
           |  |  | 305 |             'dynload' => true,
 | 
        
           |  |  | 306 |             'defaultreturntype' => $this->default_returntype(),
 | 
        
           |  |  | 307 |             'path' => $contentobj->get_navigation(),
 | 
        
           |  |  | 308 |             'list' => $contentobj->get_content_nodes($query, [$this, 'filter']),
 | 
        
           |  |  | 309 |             'manage' => 'https://drive.google.com/',
 | 
        
           |  |  | 310 |         ];
 | 
        
           |  |  | 311 |     }
 | 
        
           |  |  | 312 |   | 
        
           |  |  | 313 |     /**
 | 
        
           |  |  | 314 |      * Search throughout the Google Drive.
 | 
        
           |  |  | 315 |      *
 | 
        
           |  |  | 316 |      * @param string $searchtext text to search for.
 | 
        
           |  |  | 317 |      * @param int $page search page.
 | 
        
           |  |  | 318 |      * @return array of results.
 | 
        
           |  |  | 319 |      */
 | 
        
           |  |  | 320 |     public function search($searchtext, $page = 0) {
 | 
        
           |  |  | 321 |         // Construct the path to the repository root.
 | 
        
           |  |  | 322 |         $pluginname = get_string('pluginname', 'repository_googledocs');
 | 
        
           |  |  | 323 |         $rootpath = helper::build_node_path(self::REPOSITORY_ROOT_ID, $pluginname);
 | 
        
           |  |  | 324 |         // Construct the path to the search results node.
 | 
        
           |  |  | 325 |         // Currently, when constructing the search node name, the search term is concatenated to the lang string.
 | 
        
           |  |  | 326 |         // This was done deliberately so that we can easily and accurately obtain the search term from the search node
 | 
        
           |  |  | 327 |         // name later when navigating to the search results through the breadcrumb navigation.
 | 
        
           |  |  | 328 |         $name = get_string('searchfor', 'repository_googledocs') . " '{$searchtext}'";
 | 
        
           |  |  | 329 |         $path = helper::build_node_path(self::SEARCH_ROOT_ID, $name, $rootpath);
 | 
        
           |  |  | 330 |   | 
        
           |  |  | 331 |         $service = new repository_googledocs\rest($this->get_user_oauth_client());
 | 
        
           |  |  | 332 |         $searchobj = new googledocs_content_search($service, $path);
 | 
        
           |  |  | 333 |   | 
        
           |  |  | 334 |         return [
 | 
        
           |  |  | 335 |             'dynload' => true,
 | 
        
           |  |  | 336 |             'path' => $searchobj->get_navigation(),
 | 
        
           |  |  | 337 |             'list' => $searchobj->get_content_nodes($searchtext, [$this, 'filter']),
 | 
        
           |  |  | 338 |             'manage' => 'https://drive.google.com/',
 | 
        
           |  |  | 339 |         ];
 | 
        
           |  |  | 340 |     }
 | 
        
           |  |  | 341 |   | 
        
           |  |  | 342 |     /**
 | 
        
           |  |  | 343 |      * Query Google Drive for files and folders using a search query.
 | 
        
           |  |  | 344 |      *
 | 
        
           |  |  | 345 |      * Documentation about the query format can be found here:
 | 
        
           |  |  | 346 |      *   https://developers.google.com/drive/search-parameters
 | 
        
           |  |  | 347 |      *
 | 
        
           |  |  | 348 |      * This returns a list of files and folders with their details as they should be
 | 
        
           |  |  | 349 |      * formatted and returned by functions such as get_listing() or search().
 | 
        
           |  |  | 350 |      *
 | 
        
           |  |  | 351 |      * @deprecated since Moodle 3.11.
 | 
        
           |  |  | 352 |      * @param string $q search query as expected by the Google API.
 | 
        
           |  |  | 353 |      * @param string $path parent path of the current files, will not be used for the query.
 | 
        
           |  |  | 354 |      * @param int $page page.
 | 
        
           |  |  | 355 |      * @return array of files and folders.
 | 
        
           |  |  | 356 |      */
 | 
        
           |  |  | 357 |     protected function query($q, $path = null, $page = 0) {
 | 
        
           |  |  | 358 |         debugging('The function query() is deprecated, please use get_content_nodes() from the ' .
 | 
        
           |  |  | 359 |             'googledocs repository content classes instead.', DEBUG_DEVELOPER);
 | 
        
           |  |  | 360 |   | 
        
           |  |  | 361 |         global $OUTPUT;
 | 
        
           |  |  | 362 |   | 
        
           |  |  | 363 |         $files = array();
 | 
        
           |  |  | 364 |         $folders = array();
 | 
        
           |  |  | 365 |         $config = get_config('googledocs');
 | 
        
           |  |  | 366 |         $fields = "files(id,name,mimeType,webContentLink,webViewLink,fileExtension,modifiedTime,size,thumbnailLink,iconLink)";
 | 
        
           |  |  | 367 |         $params = array('q' => $q, 'fields' => $fields, 'spaces' => 'drive');
 | 
        
           |  |  | 368 |   | 
        
           |  |  | 369 |         try {
 | 
        
           |  |  | 370 |             // Retrieving files and folders.
 | 
        
           |  |  | 371 |             $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 372 |             $service = new repository_googledocs\rest($client);
 | 
        
           |  |  | 373 |   | 
        
           |  |  | 374 |             $response = $service->call('list', $params);
 | 
        
           |  |  | 375 |         } catch (Exception $e) {
 | 
        
           |  |  | 376 |             if ($e->getCode() == 403 && strpos($e->getMessage(), 'Access Not Configured') !== false) {
 | 
        
           |  |  | 377 |                 // This is raised when the service Drive API has not been enabled on Google APIs control panel.
 | 
        
           |  |  | 378 |                 throw new repository_exception('servicenotenabled', 'repository_googledocs');
 | 
        
           |  |  | 379 |             } else {
 | 
        
           |  |  | 380 |                 throw $e;
 | 
        
           |  |  | 381 |             }
 | 
        
           |  |  | 382 |         }
 | 
        
           |  |  | 383 |   | 
        
           |  |  | 384 |         $gfiles = isset($response->files) ? $response->files : array();
 | 
        
           |  |  | 385 |         foreach ($gfiles as $gfile) {
 | 
        
           |  |  | 386 |             if ($gfile->mimeType == 'application/vnd.google-apps.folder') {
 | 
        
           |  |  | 387 |                 // This is a folder.
 | 
        
           |  |  | 388 |                 $folders[$gfile->name . $gfile->id] = array(
 | 
        
           |  |  | 389 |                     'title' => $gfile->name,
 | 
        
           |  |  | 390 |                     'path' => $this->build_node_path($gfile->id, $gfile->name, $path),
 | 
        
           |  |  | 391 |                     'date' => strtotime($gfile->modifiedTime),
 | 
        
           |  |  | 392 |                     'thumbnail' => $OUTPUT->image_url(file_folder_icon())->out(false),
 | 
        
           |  |  | 393 |                     'thumbnail_height' => 64,
 | 
        
           |  |  | 394 |                     'thumbnail_width' => 64,
 | 
        
           |  |  | 395 |                     'children' => array()
 | 
        
           |  |  | 396 |                 );
 | 
        
           |  |  | 397 |             } else {
 | 
        
           |  |  | 398 |                 // This is a file.
 | 
        
           |  |  | 399 |                 $link = isset($gfile->webViewLink) ? $gfile->webViewLink : '';
 | 
        
           |  |  | 400 |                 if (empty($link)) {
 | 
        
           |  |  | 401 |                     $link = isset($gfile->webContentLink) ? $gfile->webContentLink : '';
 | 
        
           |  |  | 402 |                 }
 | 
        
           |  |  | 403 |                 if (isset($gfile->fileExtension)) {
 | 
        
           |  |  | 404 |                     // The file has an extension, therefore we can download it.
 | 
        
           |  |  | 405 |                     $source = json_encode([
 | 
        
           |  |  | 406 |                         'id' => $gfile->id,
 | 
        
           |  |  | 407 |                         'name' => $gfile->name,
 | 
        
           |  |  | 408 |                         'exportformat' => 'download',
 | 
        
           |  |  | 409 |                         'link' => $link
 | 
        
           |  |  | 410 |                     ]);
 | 
        
           |  |  | 411 |                     $title = $gfile->name;
 | 
        
           |  |  | 412 |                 } else {
 | 
        
           |  |  | 413 |                     // The file is probably a Google Doc file, we get the corresponding export link.
 | 
        
           |  |  | 414 |                     // This should be improved by allowing the user to select the type of export they'd like.
 | 
        
           |  |  | 415 |                     $type = str_replace('application/vnd.google-apps.', '', $gfile->mimeType);
 | 
        
           |  |  | 416 |                     $title = '';
 | 
        
           |  |  | 417 |                     $exporttype = '';
 | 
        
           |  |  | 418 |                     $types = get_mimetypes_array();
 | 
        
           |  |  | 419 |   | 
        
           |  |  | 420 |                     switch ($type){
 | 
        
           |  |  | 421 |                         case 'document':
 | 
        
           |  |  | 422 |                             $ext = $config->documentformat;
 | 
        
           |  |  | 423 |                             $title = $gfile->name . '.gdoc';
 | 
        
           |  |  | 424 |                             if ($ext === 'rtf') {
 | 
        
           |  |  | 425 |                                 // Moodle user 'text/rtf' as the MIME type for RTF files.
 | 
        
           |  |  | 426 |                                 // Google uses 'application/rtf' for the same type of file.
 | 
        
           |  |  | 427 |                                 // See https://developers.google.com/drive/v3/web/manage-downloads.
 | 
        
           |  |  | 428 |                                 $exporttype = 'application/rtf';
 | 
        
           |  |  | 429 |                             } else {
 | 
        
           |  |  | 430 |                                 $exporttype = $types[$ext]['type'];
 | 
        
           |  |  | 431 |                             }
 | 
        
           |  |  | 432 |                             break;
 | 
        
           |  |  | 433 |                         case 'presentation':
 | 
        
           |  |  | 434 |                             $ext = $config->presentationformat;
 | 
        
           |  |  | 435 |                             $title = $gfile->name . '.gslides';
 | 
        
           |  |  | 436 |                             $exporttype = $types[$ext]['type'];
 | 
        
           |  |  | 437 |                             break;
 | 
        
           |  |  | 438 |                         case 'spreadsheet':
 | 
        
           |  |  | 439 |                             $ext = $config->spreadsheetformat;
 | 
        
           |  |  | 440 |                             $title = $gfile->name . '.gsheet';
 | 
        
           |  |  | 441 |                             $exporttype = $types[$ext]['type'];
 | 
        
           |  |  | 442 |                             break;
 | 
        
           |  |  | 443 |                         case 'drawing':
 | 
        
           |  |  | 444 |                             $ext = $config->drawingformat;
 | 
        
           |  |  | 445 |                             $title = $gfile->name . '.'. $ext;
 | 
        
           |  |  | 446 |                             $exporttype = $types[$ext]['type'];
 | 
        
           |  |  | 447 |                             break;
 | 
        
           |  |  | 448 |                     }
 | 
        
           |  |  | 449 |                     // Skips invalid/unknown types.
 | 
        
           |  |  | 450 |                     if (empty($title)) {
 | 
        
           |  |  | 451 |                         continue;
 | 
        
           |  |  | 452 |                     }
 | 
        
           |  |  | 453 |                     $source = json_encode([
 | 
        
           |  |  | 454 |                         'id' => $gfile->id,
 | 
        
           |  |  | 455 |                         'exportformat' => $exporttype,
 | 
        
           |  |  | 456 |                         'link' => $link,
 | 
        
           |  |  | 457 |                         'name' => $gfile->name
 | 
        
           |  |  | 458 |                     ]);
 | 
        
           |  |  | 459 |                 }
 | 
        
           |  |  | 460 |                 // Adds the file to the file list. Using the itemId along with the name as key
 | 
        
           |  |  | 461 |                 // of the array because Google Drive allows files with identical names.
 | 
        
           |  |  | 462 |                 $thumb = '';
 | 
        
           |  |  | 463 |                 if (isset($gfile->thumbnailLink)) {
 | 
        
           |  |  | 464 |                     $thumb = $gfile->thumbnailLink;
 | 
        
           |  |  | 465 |                 } else if (isset($gfile->iconLink)) {
 | 
        
           |  |  | 466 |                     $thumb = $gfile->iconLink;
 | 
        
           |  |  | 467 |                 }
 | 
        
           |  |  | 468 |                 $files[$title . $gfile->id] = array(
 | 
        
           |  |  | 469 |                     'title' => $title,
 | 
        
           |  |  | 470 |                     'source' => $source,
 | 
        
           |  |  | 471 |                     'date' => strtotime($gfile->modifiedTime),
 | 
        
           |  |  | 472 |                     'size' => isset($gfile->size) ? $gfile->size : null,
 | 
        
           |  |  | 473 |                     'thumbnail' => $thumb,
 | 
        
           |  |  | 474 |                     'thumbnail_height' => 64,
 | 
        
           |  |  | 475 |                     'thumbnail_width' => 64,
 | 
        
           |  |  | 476 |                 );
 | 
        
           |  |  | 477 |             }
 | 
        
           |  |  | 478 |         }
 | 
        
           |  |  | 479 |   | 
        
           |  |  | 480 |         // Filter and order the results.
 | 
        
           |  |  | 481 |         $files = array_filter($files, array($this, 'filter'));
 | 
        
           |  |  | 482 |         core_collator::ksort($files, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 483 |         core_collator::ksort($folders, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 484 |         return array_merge(array_values($folders), array_values($files));
 | 
        
           |  |  | 485 |     }
 | 
        
           |  |  | 486 |   | 
        
           |  |  | 487 |     /**
 | 
        
           |  |  | 488 |      * Logout.
 | 
        
           |  |  | 489 |      *
 | 
        
           |  |  | 490 |      * @return string
 | 
        
           |  |  | 491 |      */
 | 
        
           |  |  | 492 |     public function logout() {
 | 
        
           |  |  | 493 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 494 |         $client->log_out();
 | 
        
           |  |  | 495 |         return parent::logout();
 | 
        
           |  |  | 496 |     }
 | 
        
           |  |  | 497 |   | 
        
           |  |  | 498 |     /**
 | 
        
           |  |  | 499 |      * Get a file.
 | 
        
           |  |  | 500 |      *
 | 
        
           |  |  | 501 |      * @param string $reference reference of the file.
 | 
        
           |  |  | 502 |      * @param string $file name to save the file to.
 | 
        
           |  |  | 503 |      * @return string JSON encoded array of information about the file.
 | 
        
           |  |  | 504 |      */
 | 
        
           |  |  | 505 |     public function get_file($reference, $filename = '') {
 | 
        
           |  |  | 506 |         global $CFG;
 | 
        
           |  |  | 507 |   | 
        
           |  |  | 508 |         if (!$this->issuer->get('enabled')) {
 | 
        
           |  |  | 509 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 510 |         }
 | 
        
           |  |  | 511 |   | 
        
           |  |  | 512 |         $source = json_decode($reference);
 | 
        
           |  |  | 513 |   | 
        
           |  |  | 514 |         $client = null;
 | 
        
           |  |  | 515 |         if (!empty($source->usesystem)) {
 | 
        
           |  |  | 516 |             $client = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 517 |         } else {
 | 
        
           |  |  | 518 |             $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 519 |         }
 | 
        
           |  |  | 520 |   | 
        
           |  |  | 521 |         $base = 'https://www.googleapis.com/drive/v3';
 | 
        
           |  |  | 522 |   | 
        
           |  |  | 523 |         $newfilename = false;
 | 
        
           |  |  | 524 |         if ($source->exportformat == 'download') {
 | 
        
           |  |  | 525 |             $params = ['alt' => 'media'];
 | 
        
           |  |  | 526 |             $sourceurl = new moodle_url($base . '/files/' . $source->id, $params);
 | 
        
           |  |  | 527 |             $source = $sourceurl->out(false);
 | 
        
           |  |  | 528 |         } else {
 | 
        
           |  |  | 529 |             $params = ['mimeType' => $source->exportformat];
 | 
        
           |  |  | 530 |             $sourceurl = new moodle_url($base . '/files/' . $source->id . '/export', $params);
 | 
        
           |  |  | 531 |             $types = get_mimetypes_array();
 | 
        
           |  |  | 532 |             $checktype = $source->exportformat;
 | 
        
           |  |  | 533 |             if ($checktype == 'application/rtf') {
 | 
        
           |  |  | 534 |                 $checktype = 'text/rtf';
 | 
        
           |  |  | 535 |             }
 | 
        
           |  |  | 536 |             // Determine the relevant default import format config for the given file.
 | 
        
           |  |  | 537 |             switch ($source->googledoctype) {
 | 
        
           |  |  | 538 |                 case 'document':
 | 
        
           |  |  | 539 |                     $importformatconfig = get_config('googledocs', 'documentformat');
 | 
        
           |  |  | 540 |                     break;
 | 
        
           |  |  | 541 |                 case 'presentation':
 | 
        
           |  |  | 542 |                     $importformatconfig = get_config('googledocs', 'presentationformat');
 | 
        
           |  |  | 543 |                     break;
 | 
        
           |  |  | 544 |                 case 'spreadsheet':
 | 
        
           |  |  | 545 |                     $importformatconfig = get_config('googledocs', 'spreadsheetformat');
 | 
        
           |  |  | 546 |                     break;
 | 
        
           |  |  | 547 |                 case 'drawing':
 | 
        
           |  |  | 548 |                     $importformatconfig = get_config('googledocs', 'drawingformat');
 | 
        
           |  |  | 549 |                     break;
 | 
        
           |  |  | 550 |                 default:
 | 
        
           |  |  | 551 |                     $importformatconfig = null;
 | 
        
           |  |  | 552 |             }
 | 
        
           |  |  | 553 |   | 
        
           |  |  | 554 |             foreach ($types as $extension => $info) {
 | 
        
           |  |  | 555 |                 if ($info['type'] == $checktype && $extension === $importformatconfig) {
 | 
        
           |  |  | 556 |                     $newfilename = $source->name . '.' . $extension;
 | 
        
           |  |  | 557 |                     break;
 | 
        
           |  |  | 558 |                 }
 | 
        
           |  |  | 559 |             }
 | 
        
           |  |  | 560 |             $source = $sourceurl->out(false);
 | 
        
           |  |  | 561 |         }
 | 
        
           |  |  | 562 |   | 
        
           |  |  | 563 |         // We use download_one and not the rest API because it has special timeouts etc.
 | 
        
           |  |  | 564 |         $path = $this->prepare_file($filename);
 | 
        
           |  |  | 565 |         $options = ['filepath' => $path, 'timeout' => 15, 'followlocation' => true, 'maxredirs' => 5];
 | 
        
           |  |  | 566 |         $success = $client->download_one($source, null, $options);
 | 
        
           |  |  | 567 |   | 
        
           |  |  | 568 |         if ($success) {
 | 
        
           |  |  | 569 |             @chmod($path, $CFG->filepermissions);
 | 
        
           |  |  | 570 |   | 
        
           |  |  | 571 |             $result = [
 | 
        
           |  |  | 572 |                 'path' => $path,
 | 
        
           |  |  | 573 |                 'url' => $reference,
 | 
        
           |  |  | 574 |             ];
 | 
        
           |  |  | 575 |             if (!empty($newfilename)) {
 | 
        
           |  |  | 576 |                 $result['newfilename'] = $newfilename;
 | 
        
           |  |  | 577 |             }
 | 
        
           |  |  | 578 |             return $result;
 | 
        
           |  |  | 579 |         }
 | 
        
           |  |  | 580 |         throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 581 |     }
 | 
        
           |  |  | 582 |   | 
        
           |  |  | 583 |     /**
 | 
        
           |  |  | 584 |      * Prepare file reference information.
 | 
        
           |  |  | 585 |      *
 | 
        
           |  |  | 586 |      * We are using this method to clean up the source to make sure that it
 | 
        
           |  |  | 587 |      * is a valid source.
 | 
        
           |  |  | 588 |      *
 | 
        
           |  |  | 589 |      * @param string $source of the file.
 | 
        
           |  |  | 590 |      * @return string file reference.
 | 
        
           |  |  | 591 |      */
 | 
        
           |  |  | 592 |     public function get_file_reference($source) {
 | 
        
           |  |  | 593 |         // We could do some magic upgrade code here.
 | 
        
           |  |  | 594 |         return $source;
 | 
        
           |  |  | 595 |     }
 | 
        
           |  |  | 596 |   | 
        
           |  |  | 597 |     /**
 | 
        
           |  |  | 598 |      * What kind of files will be in this repository?
 | 
        
           |  |  | 599 |      *
 | 
        
           |  |  | 600 |      * @return array return '*' means this repository support any files, otherwise
 | 
        
           |  |  | 601 |      *               return mimetypes of files, it can be an array
 | 
        
           |  |  | 602 |      */
 | 
        
           |  |  | 603 |     public function supported_filetypes() {
 | 
        
           |  |  | 604 |         return '*';
 | 
        
           |  |  | 605 |     }
 | 
        
           |  |  | 606 |   | 
        
           |  |  | 607 |     /**
 | 
        
           |  |  | 608 |      * Tells how the file can be picked from this repository.
 | 
        
           |  |  | 609 |      *
 | 
        
           |  |  | 610 |      * @return int
 | 
        
           |  |  | 611 |      */
 | 
        
           |  |  | 612 |     public function supported_returntypes() {
 | 
        
           |  |  | 613 |         // We can only support references if the system account is connected.
 | 
        
           |  |  | 614 |         if (!empty($this->issuer) && $this->issuer->is_system_account_connected()) {
 | 
        
           |  |  | 615 |             $setting = get_config('googledocs', 'supportedreturntypes');
 | 
        
           |  |  | 616 |             if ($setting == 'internal') {
 | 
        
           |  |  | 617 |                 return FILE_INTERNAL;
 | 
        
           |  |  | 618 |             } else if ($setting == 'external') {
 | 
        
           |  |  | 619 |                 return FILE_CONTROLLED_LINK;
 | 
        
           |  |  | 620 |             } else {
 | 
        
           |  |  | 621 |                 return FILE_CONTROLLED_LINK | FILE_INTERNAL;
 | 
        
           |  |  | 622 |             }
 | 
        
           |  |  | 623 |         } else {
 | 
        
           |  |  | 624 |             return FILE_INTERNAL;
 | 
        
           |  |  | 625 |         }
 | 
        
           |  |  | 626 |     }
 | 
        
           |  |  | 627 |   | 
        
           |  |  | 628 |     /**
 | 
        
           |  |  | 629 |      * Which return type should be selected by default.
 | 
        
           |  |  | 630 |      *
 | 
        
           |  |  | 631 |      * @return int
 | 
        
           |  |  | 632 |      */
 | 
        
           |  |  | 633 |     public function default_returntype() {
 | 
        
           |  |  | 634 |         $setting = get_config('googledocs', 'defaultreturntype');
 | 
        
           |  |  | 635 |         $supported = get_config('googledocs', 'supportedreturntypes');
 | 
        
           |  |  | 636 |         if (($setting == FILE_INTERNAL && $supported != 'external') || $supported == 'internal') {
 | 
        
           |  |  | 637 |             return FILE_INTERNAL;
 | 
        
           |  |  | 638 |         } else {
 | 
        
           |  |  | 639 |             return FILE_CONTROLLED_LINK;
 | 
        
           |  |  | 640 |         }
 | 
        
           |  |  | 641 |     }
 | 
        
           |  |  | 642 |   | 
        
           |  |  | 643 |     /**
 | 
        
           |  |  | 644 |      * Return names of the general options.
 | 
        
           |  |  | 645 |      * By default: no general option name.
 | 
        
           |  |  | 646 |      *
 | 
        
           |  |  | 647 |      * @return array
 | 
        
           |  |  | 648 |      */
 | 
        
           |  |  | 649 |     public static function get_type_option_names() {
 | 
        
           |  |  | 650 |         return array('issuerid', 'pluginname',
 | 
        
           |  |  | 651 |             'documentformat', 'drawingformat',
 | 
        
           |  |  | 652 |             'presentationformat', 'spreadsheetformat',
 | 
        
           |  |  | 653 |             'defaultreturntype', 'supportedreturntypes');
 | 
        
           |  |  | 654 |     }
 | 
        
           |  |  | 655 |   | 
        
           |  |  | 656 |     /**
 | 
        
           |  |  | 657 |      * Store the access token.
 | 
        
           |  |  | 658 |      */
 | 
        
           |  |  | 659 |     public function callback() {
 | 
        
           |  |  | 660 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 661 |         // This will upgrade to an access token if we have an authorization code and save the access token in the session.
 | 
        
           |  |  | 662 |         $client->is_logged_in();
 | 
        
           |  |  | 663 |     }
 | 
        
           |  |  | 664 |   | 
        
           |  |  | 665 |     /**
 | 
        
           |  |  | 666 |      * Repository method to serve the referenced file
 | 
        
           |  |  | 667 |      *
 | 
        
           |  |  | 668 |      * @see send_stored_file
 | 
        
           |  |  | 669 |      *
 | 
        
           |  |  | 670 |      * @param stored_file $storedfile the file that contains the reference
 | 
        
           |  |  | 671 |      * @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime)
 | 
        
           |  |  | 672 |      * @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
 | 
        
           |  |  | 673 |      * @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
 | 
        
           |  |  | 674 |      * @param array $options additional options affecting the file serving
 | 
        
           |  |  | 675 |      */
 | 
        
           | 1441 | ariadna | 676 |     public function send_file($storedfile, $lifetime=null , $filter=0, $forcedownload=false, ?array $options = null) {
 | 
        
           | 1 | efrain | 677 |         if (!$this->issuer->get('enabled')) {
 | 
        
           |  |  | 678 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 679 |         }
 | 
        
           |  |  | 680 |   | 
        
           |  |  | 681 |         $source = json_decode($storedfile->get_reference());
 | 
        
           |  |  | 682 |   | 
        
           |  |  | 683 |         $fb = get_file_browser();
 | 
        
           |  |  | 684 |         $context = context::instance_by_id($storedfile->get_contextid(), MUST_EXIST);
 | 
        
           |  |  | 685 |         $info = $fb->get_file_info($context,
 | 
        
           |  |  | 686 |                                    $storedfile->get_component(),
 | 
        
           |  |  | 687 |                                    $storedfile->get_filearea(),
 | 
        
           |  |  | 688 |                                    $storedfile->get_itemid(),
 | 
        
           |  |  | 689 |                                    $storedfile->get_filepath(),
 | 
        
           |  |  | 690 |                                    $storedfile->get_filename());
 | 
        
           |  |  | 691 |   | 
        
           |  |  | 692 |         if (empty($options['offline']) && !empty($info) && $info->is_writable() && !empty($source->usesystem)) {
 | 
        
           |  |  | 693 |             // Add the current user as an OAuth writer.
 | 
        
           |  |  | 694 |             $systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 695 |   | 
        
           |  |  | 696 |             if ($systemauth === false) {
 | 
        
           |  |  | 697 |                 $details = 'Cannot connect as system user';
 | 
        
           |  |  | 698 |                 throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 699 |             }
 | 
        
           |  |  | 700 |             $systemservice = new repository_googledocs\rest($systemauth);
 | 
        
           |  |  | 701 |   | 
        
           |  |  | 702 |             // Get the user oauth so we can get the account to add.
 | 
        
           |  |  | 703 |             $url = moodle_url::make_pluginfile_url($storedfile->get_contextid(),
 | 
        
           |  |  | 704 |                                                    $storedfile->get_component(),
 | 
        
           |  |  | 705 |                                                    $storedfile->get_filearea(),
 | 
        
           |  |  | 706 |                                                    $storedfile->get_itemid(),
 | 
        
           |  |  | 707 |                                                    $storedfile->get_filepath(),
 | 
        
           |  |  | 708 |                                                    $storedfile->get_filename(),
 | 
        
           |  |  | 709 |                                                    $forcedownload);
 | 
        
           |  |  | 710 |             $url->param('sesskey', sesskey());
 | 
        
           |  |  | 711 |             $param = ($options['embed'] == true) ? false : $url;
 | 
        
           |  |  | 712 |             $userauth = $this->get_user_oauth_client($param);
 | 
        
           |  |  | 713 |             if (!$userauth->is_logged_in()) {
 | 
        
           |  |  | 714 |                 if ($options['embed'] == true) {
 | 
        
           |  |  | 715 |                     // Due to Same-origin policy, we cannot redirect to googledocs login page.
 | 
        
           |  |  | 716 |                     // If the requested file is embed and the user is not logged in, add option to log in using a popup.
 | 
        
           |  |  | 717 |                     $this->print_login_popup(['style' => 'margin-top: 250px']);
 | 
        
           |  |  | 718 |                     exit;
 | 
        
           |  |  | 719 |                 }
 | 
        
           |  |  | 720 |                 redirect($userauth->get_login_url());
 | 
        
           |  |  | 721 |             }
 | 
        
           |  |  | 722 |             if ($userauth === false) {
 | 
        
           |  |  | 723 |                 $details = 'Cannot connect as current user';
 | 
        
           |  |  | 724 |                 throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 725 |             }
 | 
        
           |  |  | 726 |             $userinfo = $userauth->get_userinfo();
 | 
        
           |  |  | 727 |             $useremail = $userinfo['email'];
 | 
        
           |  |  | 728 |   | 
        
           |  |  | 729 |             $this->add_temp_writer_to_file($systemservice, $source->id, $useremail);
 | 
        
           |  |  | 730 |         }
 | 
        
           |  |  | 731 |   | 
        
           |  |  | 732 |         if (!empty($options['offline'])) {
 | 
        
           |  |  | 733 |             $downloaded = $this->get_file($storedfile->get_reference(), $storedfile->get_filename());
 | 
        
           |  |  | 734 |   | 
        
           |  |  | 735 |             $filename = $storedfile->get_filename();
 | 
        
           |  |  | 736 |             if (isset($downloaded['newfilename'])) {
 | 
        
           |  |  | 737 |                 $filename = $downloaded['newfilename'];
 | 
        
           |  |  | 738 |             }
 | 
        
           |  |  | 739 |             send_file($downloaded['path'], $filename, $lifetime, $filter, false, $forcedownload, '', false, $options);
 | 
        
           |  |  | 740 |         } else if ($source->link) {
 | 
        
           |  |  | 741 |             // Do not use redirect() here because is not compatible with webservice/pluginfile.php.
 | 
        
           |  |  | 742 |             header('Location: ' . $source->link);
 | 
        
           |  |  | 743 |         } else {
 | 
        
           |  |  | 744 |             $details = 'File is missing source link';
 | 
        
           |  |  | 745 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 746 |         }
 | 
        
           |  |  | 747 |     }
 | 
        
           |  |  | 748 |   | 
        
           |  |  | 749 |     /**
 | 
        
           |  |  | 750 |      * See if a folder exists within a folder
 | 
        
           |  |  | 751 |      *
 | 
        
           |  |  | 752 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 753 |      * @param string $foldername The folder we are looking for.
 | 
        
           |  |  | 754 |      * @param string $parentid The parent folder we are looking in.
 | 
        
           |  |  | 755 |      * @return string|boolean The file id if it exists or false.
 | 
        
           |  |  | 756 |      */
 | 
        
           |  |  | 757 |     protected function folder_exists_in_folder(\repository_googledocs\rest $client, $foldername, $parentid) {
 | 
        
           |  |  | 758 |         $q = '\'' . addslashes($parentid) . '\' in parents and trashed = false and name = \'' . addslashes($foldername). '\'';
 | 
        
           |  |  | 759 |         $fields = 'files(id, name)';
 | 
        
           |  |  | 760 |         $params = [ 'q' => $q, 'fields' => $fields];
 | 
        
           |  |  | 761 |         $response = $client->call('list', $params);
 | 
        
           |  |  | 762 |         $missing = true;
 | 
        
           |  |  | 763 |         foreach ($response->files as $child) {
 | 
        
           |  |  | 764 |             if ($child->name == $foldername) {
 | 
        
           |  |  | 765 |                 return $child->id;
 | 
        
           |  |  | 766 |             }
 | 
        
           |  |  | 767 |         }
 | 
        
           |  |  | 768 |         return false;
 | 
        
           |  |  | 769 |     }
 | 
        
           |  |  | 770 |   | 
        
           |  |  | 771 |     /**
 | 
        
           |  |  | 772 |      * Create a folder within a folder
 | 
        
           |  |  | 773 |      *
 | 
        
           |  |  | 774 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 775 |      * @param string $foldername The folder we are creating.
 | 
        
           |  |  | 776 |      * @param string $parentid The parent folder we are creating in.
 | 
        
           |  |  | 777 |      *
 | 
        
           |  |  | 778 |      * @return string The file id of the new folder.
 | 
        
           |  |  | 779 |      */
 | 
        
           |  |  | 780 |     protected function create_folder_in_folder(\repository_googledocs\rest $client, $foldername, $parentid) {
 | 
        
           |  |  | 781 |         $fields = 'id';
 | 
        
           |  |  | 782 |         $params = ['fields' => $fields];
 | 
        
           |  |  | 783 |         $folder = ['mimeType' => 'application/vnd.google-apps.folder', 'name' => $foldername, 'parents' => [$parentid]];
 | 
        
           |  |  | 784 |         $created = $client->call('create', $params, json_encode($folder));
 | 
        
           |  |  | 785 |         if (empty($created->id)) {
 | 
        
           |  |  | 786 |             $details = 'Cannot create folder:' . $foldername;
 | 
        
           |  |  | 787 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 788 |         }
 | 
        
           |  |  | 789 |         return $created->id;
 | 
        
           |  |  | 790 |     }
 | 
        
           |  |  | 791 |   | 
        
           |  |  | 792 |     /**
 | 
        
           |  |  | 793 |      * Get simple file info for humans.
 | 
        
           |  |  | 794 |      *
 | 
        
           |  |  | 795 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 796 |      * @param string $fileid The file we are querying.
 | 
        
           |  |  | 797 |      *
 | 
        
           |  |  | 798 |      * @return stdClass
 | 
        
           |  |  | 799 |      */
 | 
        
           |  |  | 800 |     protected function get_file_summary(\repository_googledocs\rest $client, $fileid) {
 | 
        
           |  |  | 801 |         $fields = "id,name,owners,parents";
 | 
        
           |  |  | 802 |         $params = [
 | 
        
           |  |  | 803 |             'fileid' => $fileid,
 | 
        
           |  |  | 804 |             'fields' => $fields
 | 
        
           |  |  | 805 |         ];
 | 
        
           |  |  | 806 |         return $client->call('get', $params);
 | 
        
           |  |  | 807 |     }
 | 
        
           |  |  | 808 |   | 
        
           |  |  | 809 |     /**
 | 
        
           |  |  | 810 |      * Copy a file and return the new file details. A side effect of the copy
 | 
        
           |  |  | 811 |      * is that the owner will be the account authenticated with this oauth client.
 | 
        
           |  |  | 812 |      *
 | 
        
           |  |  | 813 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 814 |      * @param string $fileid The file we are copying.
 | 
        
           |  |  | 815 |      * @param string $name The original filename (don't change it).
 | 
        
           |  |  | 816 |      *
 | 
        
           |  |  | 817 |      * @return stdClass file details.
 | 
        
           |  |  | 818 |      */
 | 
        
           |  |  | 819 |     protected function copy_file(\repository_googledocs\rest $client, $fileid, $name) {
 | 
        
           |  |  | 820 |         $fields = "id,name,mimeType,webContentLink,webViewLink,size,thumbnailLink,iconLink";
 | 
        
           |  |  | 821 |         $params = [
 | 
        
           |  |  | 822 |             'fileid' => $fileid,
 | 
        
           |  |  | 823 |             'fields' => $fields,
 | 
        
           |  |  | 824 |         ];
 | 
        
           |  |  | 825 |         // Keep the original name (don't put copy at the end of it).
 | 
        
           |  |  | 826 |         $copyinfo = [];
 | 
        
           |  |  | 827 |         if (!empty($name)) {
 | 
        
           |  |  | 828 |             $copyinfo = [ 'name' => $name ];
 | 
        
           |  |  | 829 |         }
 | 
        
           |  |  | 830 |         $fileinfo = $client->call('copy', $params, json_encode($copyinfo));
 | 
        
           |  |  | 831 |         if (empty($fileinfo->id)) {
 | 
        
           |  |  | 832 |             $details = 'Cannot copy file:' . $fileid;
 | 
        
           |  |  | 833 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 834 |         }
 | 
        
           |  |  | 835 |         return $fileinfo;
 | 
        
           |  |  | 836 |     }
 | 
        
           |  |  | 837 |   | 
        
           |  |  | 838 |     /**
 | 
        
           |  |  | 839 |      * Add a writer to the permissions on the file (temporary).
 | 
        
           |  |  | 840 |      *
 | 
        
           |  |  | 841 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 842 |      * @param string $fileid The file we are updating.
 | 
        
           |  |  | 843 |      * @param string $email The email of the writer account to add.
 | 
        
           |  |  | 844 |      * @return boolean
 | 
        
           |  |  | 845 |      */
 | 
        
           |  |  | 846 |     protected function add_temp_writer_to_file(\repository_googledocs\rest $client, $fileid, $email) {
 | 
        
           |  |  | 847 |         // Expires in 7 days.
 | 
        
           |  |  | 848 |         $expires = new DateTime();
 | 
        
           |  |  | 849 |         $expires->add(new DateInterval("P7D"));
 | 
        
           |  |  | 850 |   | 
        
           |  |  | 851 |         $updateeditor = [
 | 
        
           |  |  | 852 |             'emailAddress' => $email,
 | 
        
           |  |  | 853 |             'role' => 'writer',
 | 
        
           |  |  | 854 |             'type' => 'user',
 | 
        
           |  |  | 855 |             'expirationTime' => $expires->format(DateTime::RFC3339)
 | 
        
           |  |  | 856 |         ];
 | 
        
           |  |  | 857 |         $params = ['fileid' => $fileid, 'sendNotificationEmail' => 'false'];
 | 
        
           |  |  | 858 |         $response = $client->call('create_permission', $params, json_encode($updateeditor));
 | 
        
           |  |  | 859 |         if (empty($response->id)) {
 | 
        
           |  |  | 860 |             $details = 'Cannot add user ' . $email . ' as a writer for document: ' . $fileid;
 | 
        
           |  |  | 861 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 862 |         }
 | 
        
           |  |  | 863 |         return true;
 | 
        
           |  |  | 864 |     }
 | 
        
           |  |  | 865 |   | 
        
           |  |  | 866 |   | 
        
           |  |  | 867 |     /**
 | 
        
           |  |  | 868 |      * Add a writer to the permissions on the file.
 | 
        
           |  |  | 869 |      *
 | 
        
           |  |  | 870 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 871 |      * @param string $fileid The file we are updating.
 | 
        
           |  |  | 872 |      * @param string $email The email of the writer account to add.
 | 
        
           |  |  | 873 |      * @return boolean
 | 
        
           |  |  | 874 |      */
 | 
        
           |  |  | 875 |     protected function add_writer_to_file(\repository_googledocs\rest $client, $fileid, $email) {
 | 
        
           |  |  | 876 |         $updateeditor = [
 | 
        
           |  |  | 877 |             'emailAddress' => $email,
 | 
        
           |  |  | 878 |             'role' => 'writer',
 | 
        
           |  |  | 879 |             'type' => 'user'
 | 
        
           |  |  | 880 |         ];
 | 
        
           |  |  | 881 |         $params = ['fileid' => $fileid, 'sendNotificationEmail' => 'false'];
 | 
        
           |  |  | 882 |         $response = $client->call('create_permission', $params, json_encode($updateeditor));
 | 
        
           |  |  | 883 |         if (empty($response->id)) {
 | 
        
           |  |  | 884 |             $details = 'Cannot add user ' . $email . ' as a writer for document: ' . $fileid;
 | 
        
           |  |  | 885 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 886 |         }
 | 
        
           |  |  | 887 |         return true;
 | 
        
           |  |  | 888 |     }
 | 
        
           |  |  | 889 |   | 
        
           |  |  | 890 |     /**
 | 
        
           |  |  | 891 |      * Move from root to folder
 | 
        
           |  |  | 892 |      *
 | 
        
           |  |  | 893 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 894 |      * @param string $fileid The file we are updating.
 | 
        
           |  |  | 895 |      * @param string $folderid The id of the folder we are moving to
 | 
        
           |  |  | 896 |      * @return boolean
 | 
        
           |  |  | 897 |      */
 | 
        
           |  |  | 898 |     protected function move_file_from_root_to_folder(\repository_googledocs\rest $client, $fileid, $folderid) {
 | 
        
           |  |  | 899 |         // Set the parent.
 | 
        
           |  |  | 900 |         $params = [
 | 
        
           |  |  | 901 |             'fileid' => $fileid, 'addParents' => $folderid, 'removeParents' => 'root'
 | 
        
           |  |  | 902 |         ];
 | 
        
           |  |  | 903 |         $response = $client->call('update', $params, ' ');
 | 
        
           |  |  | 904 |         if (empty($response->id)) {
 | 
        
           |  |  | 905 |             $details = 'Cannot move the file to a folder: ' . $fileid;
 | 
        
           |  |  | 906 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 907 |         }
 | 
        
           |  |  | 908 |         return true;
 | 
        
           |  |  | 909 |     }
 | 
        
           |  |  | 910 |   | 
        
           |  |  | 911 |     /**
 | 
        
           |  |  | 912 |      * Prevent writers from sharing.
 | 
        
           |  |  | 913 |      *
 | 
        
           |  |  | 914 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 915 |      * @param string $fileid The file we are updating.
 | 
        
           |  |  | 916 |      * @return boolean
 | 
        
           |  |  | 917 |      */
 | 
        
           |  |  | 918 |     protected function prevent_writers_from_sharing_file(\repository_googledocs\rest $client, $fileid) {
 | 
        
           |  |  | 919 |         // We don't want anyone but Moodle to change the sharing settings.
 | 
        
           |  |  | 920 |         $params = [
 | 
        
           |  |  | 921 |             'fileid' => $fileid
 | 
        
           |  |  | 922 |         ];
 | 
        
           |  |  | 923 |         $update = [
 | 
        
           |  |  | 924 |             'writersCanShare' => false
 | 
        
           |  |  | 925 |         ];
 | 
        
           |  |  | 926 |         $response = $client->call('update', $params, json_encode($update));
 | 
        
           |  |  | 927 |         if (empty($response->id)) {
 | 
        
           |  |  | 928 |             $details = 'Cannot prevent writers from sharing document: ' . $fileid;
 | 
        
           |  |  | 929 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 930 |         }
 | 
        
           |  |  | 931 |         return true;
 | 
        
           |  |  | 932 |     }
 | 
        
           |  |  | 933 |   | 
        
           |  |  | 934 |     /**
 | 
        
           |  |  | 935 |      * Allow anyone with the link to read the file.
 | 
        
           |  |  | 936 |      *
 | 
        
           |  |  | 937 |      * @param \repository_googledocs\rest $client Authenticated client.
 | 
        
           |  |  | 938 |      * @param string $fileid The file we are updating.
 | 
        
           |  |  | 939 |      * @return boolean
 | 
        
           |  |  | 940 |      */
 | 
        
           |  |  | 941 |     protected function set_file_sharing_anyone_with_link_can_read(\repository_googledocs\rest $client, $fileid) {
 | 
        
           |  |  | 942 |         $updateread = [
 | 
        
           |  |  | 943 |             'type' => 'anyone',
 | 
        
           |  |  | 944 |             'role' => 'reader',
 | 
        
           |  |  | 945 |             'allowFileDiscovery' => 'false'
 | 
        
           |  |  | 946 |         ];
 | 
        
           |  |  | 947 |         $params = ['fileid' => $fileid];
 | 
        
           |  |  | 948 |         $response = $client->call('create_permission', $params, json_encode($updateread));
 | 
        
           |  |  | 949 |         if (empty($response->id) || $response->id != 'anyoneWithLink') {
 | 
        
           |  |  | 950 |             $details = 'Cannot update link sharing for the document: ' . $fileid;
 | 
        
           |  |  | 951 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 952 |         }
 | 
        
           |  |  | 953 |         return true;
 | 
        
           |  |  | 954 |     }
 | 
        
           |  |  | 955 |   | 
        
           |  |  | 956 |     /**
 | 
        
           |  |  | 957 |      * Called when a file is selected as a "link".
 | 
        
           |  |  | 958 |      * Invoked at MOODLE/repository/repository_ajax.php
 | 
        
           |  |  | 959 |      *
 | 
        
           |  |  | 960 |      * This is called at the point the reference files are being copied from the draft area to the real area
 | 
        
           |  |  | 961 |      * (when the file has really really been selected.
 | 
        
           |  |  | 962 |      *
 | 
        
           |  |  | 963 |      * @param string $reference this reference is generated by
 | 
        
           |  |  | 964 |      *                          repository::get_file_reference()
 | 
        
           |  |  | 965 |      * @param context $context the target context for this new file.
 | 
        
           |  |  | 966 |      * @param string $component the target component for this new file.
 | 
        
           |  |  | 967 |      * @param string $filearea the target filearea for this new file.
 | 
        
           |  |  | 968 |      * @param string $itemid the target itemid for this new file.
 | 
        
           |  |  | 969 |      * @return string updated reference (final one before it's saved to db).
 | 
        
           |  |  | 970 |      */
 | 
        
           |  |  | 971 |     public function reference_file_selected($reference, $context, $component, $filearea, $itemid) {
 | 
        
           |  |  | 972 |         global $CFG, $SITE;
 | 
        
           |  |  | 973 |   | 
        
           |  |  | 974 |         // What we need to do here is transfer ownership to the system user (or copy)
 | 
        
           |  |  | 975 |         // then set the permissions so anyone with the share link can view,
 | 
        
           |  |  | 976 |         // finally update the reference to contain the share link if it was not
 | 
        
           |  |  | 977 |         // already there (and point to new file id if we copied).
 | 
        
           |  |  | 978 |   | 
        
           |  |  | 979 |         // Get the details from the reference.
 | 
        
           |  |  | 980 |         $source = json_decode($reference);
 | 
        
           |  |  | 981 |         if (!empty($source->usesystem)) {
 | 
        
           |  |  | 982 |             // If we already copied this file to the system account - we are done.
 | 
        
           |  |  | 983 |             return $reference;
 | 
        
           |  |  | 984 |         }
 | 
        
           |  |  | 985 |   | 
        
           |  |  | 986 |         // Check this issuer is enabled.
 | 
        
           |  |  | 987 |         if ($this->disabled) {
 | 
        
           |  |  | 988 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 989 |         }
 | 
        
           |  |  | 990 |   | 
        
           |  |  | 991 |         // Get a system oauth client and a user oauth client.
 | 
        
           |  |  | 992 |         $systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 993 |   | 
        
           |  |  | 994 |         if ($systemauth === false) {
 | 
        
           |  |  | 995 |             $details = 'Cannot connect as system user';
 | 
        
           |  |  | 996 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 997 |         }
 | 
        
           |  |  | 998 |         // Get the system user email so we can share the file with this user.
 | 
        
           |  |  | 999 |         $systemuserinfo = $systemauth->get_userinfo();
 | 
        
           |  |  | 1000 |         $systemuseremail = $systemuserinfo['email'];
 | 
        
           |  |  | 1001 |   | 
        
           |  |  | 1002 |         $userauth = $this->get_user_oauth_client();
 | 
        
           |  |  | 1003 |         if ($userauth === false) {
 | 
        
           |  |  | 1004 |             $details = 'Cannot connect as current user';
 | 
        
           |  |  | 1005 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 1006 |         }
 | 
        
           |  |  | 1007 |   | 
        
           |  |  | 1008 |         $userservice = new repository_googledocs\rest($userauth);
 | 
        
           |  |  | 1009 |         $systemservice = new repository_googledocs\rest($systemauth);
 | 
        
           |  |  | 1010 |   | 
        
           |  |  | 1011 |         // Add Moodle as writer.
 | 
        
           |  |  | 1012 |         $this->add_writer_to_file($userservice, $source->id, $systemuseremail);
 | 
        
           |  |  | 1013 |   | 
        
           |  |  | 1014 |         // Now move it to a sensible folder.
 | 
        
           |  |  | 1015 |         $contextlist = array_reverse($context->get_parent_contexts(true));
 | 
        
           |  |  | 1016 |   | 
        
           |  |  | 1017 |         $cache = cache::make('repository_googledocs', 'folder');
 | 
        
           |  |  | 1018 |         $parentid = 'root';
 | 
        
           |  |  | 1019 |         $fullpath = 'root';
 | 
        
           |  |  | 1020 |         $allfolders = [];
 | 
        
           |  |  | 1021 |         foreach ($contextlist as $context) {
 | 
        
           |  |  | 1022 |             // Prepare human readable context folders names, making sure they are still unique within the site.
 | 
        
           |  |  | 1023 |             $prevlang = force_current_language($CFG->lang);
 | 
        
           |  |  | 1024 |             $foldername = $context->get_context_name();
 | 
        
           |  |  | 1025 |             force_current_language($prevlang);
 | 
        
           |  |  | 1026 |   | 
        
           |  |  | 1027 |             if ($context->contextlevel == CONTEXT_SYSTEM) {
 | 
        
           |  |  | 1028 |                 // Append the site short name to the root folder.
 | 
        
           |  |  | 1029 |                 $foldername .= ' ('.$SITE->shortname.')';
 | 
        
           |  |  | 1030 |                 // Append the relevant object id.
 | 
        
           |  |  | 1031 |             } else if ($context->instanceid) {
 | 
        
           |  |  | 1032 |                 $foldername .= ' (id '.$context->instanceid.')';
 | 
        
           |  |  | 1033 |             } else {
 | 
        
           |  |  | 1034 |                 // This does not really happen but just in case.
 | 
        
           |  |  | 1035 |                 $foldername .= ' (ctx '.$context->id.')';
 | 
        
           |  |  | 1036 |             }
 | 
        
           |  |  | 1037 |   | 
        
           |  |  | 1038 |             $foldername = clean_param($foldername, PARAM_PATH);
 | 
        
           |  |  | 1039 |             $allfolders[] = $foldername;
 | 
        
           |  |  | 1040 |         }
 | 
        
           |  |  | 1041 |   | 
        
           |  |  | 1042 |         $allfolders[] = clean_param($component, PARAM_PATH);
 | 
        
           |  |  | 1043 |         $allfolders[] = clean_param($filearea, PARAM_PATH);
 | 
        
           |  |  | 1044 |         $allfolders[] = clean_param($itemid, PARAM_PATH);
 | 
        
           |  |  | 1045 |   | 
        
           |  |  | 1046 |         // Variable $allfolders is the full path we want to put the file in - so walk it and create each folder.
 | 
        
           |  |  | 1047 |   | 
        
           |  |  | 1048 |         foreach ($allfolders as $foldername) {
 | 
        
           |  |  | 1049 |             // Make sure a folder exists here.
 | 
        
           |  |  | 1050 |             $fullpath .= '/' . $foldername;
 | 
        
           |  |  | 1051 |   | 
        
           |  |  | 1052 |             $folderid = $cache->get($fullpath);
 | 
        
           |  |  | 1053 |             if (empty($folderid)) {
 | 
        
           |  |  | 1054 |                 $folderid = $this->folder_exists_in_folder($systemservice, $foldername, $parentid);
 | 
        
           |  |  | 1055 |             }
 | 
        
           |  |  | 1056 |             if ($folderid !== false) {
 | 
        
           |  |  | 1057 |                 $cache->set($fullpath, $folderid);
 | 
        
           |  |  | 1058 |                 $parentid = $folderid;
 | 
        
           |  |  | 1059 |             } else {
 | 
        
           |  |  | 1060 |                 // Create it.
 | 
        
           |  |  | 1061 |                 $parentid = $this->create_folder_in_folder($systemservice, $foldername, $parentid);
 | 
        
           |  |  | 1062 |                 $cache->set($fullpath, $parentid);
 | 
        
           |  |  | 1063 |             }
 | 
        
           |  |  | 1064 |         }
 | 
        
           |  |  | 1065 |   | 
        
           |  |  | 1066 |         // Copy the file so we get a snapshot file owned by Moodle.
 | 
        
           |  |  | 1067 |         $newsource = $this->copy_file($systemservice, $source->id, $source->name);
 | 
        
           |  |  | 1068 |         // Move the copied file to the correct folder.
 | 
        
           |  |  | 1069 |         $this->move_file_from_root_to_folder($systemservice, $newsource->id, $parentid);
 | 
        
           |  |  | 1070 |   | 
        
           |  |  | 1071 |         // Set the sharing options.
 | 
        
           |  |  | 1072 |         $this->set_file_sharing_anyone_with_link_can_read($systemservice, $newsource->id);
 | 
        
           |  |  | 1073 |         $this->prevent_writers_from_sharing_file($systemservice, $newsource->id);
 | 
        
           |  |  | 1074 |   | 
        
           |  |  | 1075 |         // Update the returned reference so that the stored_file in moodle points to the newly copied file.
 | 
        
           |  |  | 1076 |         $source->id = $newsource->id;
 | 
        
           |  |  | 1077 |         $source->link = isset($newsource->webViewLink) ? $newsource->webViewLink : '';
 | 
        
           |  |  | 1078 |         $source->usesystem = true;
 | 
        
           |  |  | 1079 |         if (empty($source->link)) {
 | 
        
           |  |  | 1080 |             $source->link = isset($newsource->webContentLink) ? $newsource->webContentLink : '';
 | 
        
           |  |  | 1081 |         }
 | 
        
           |  |  | 1082 |         $reference = json_encode($source);
 | 
        
           |  |  | 1083 |   | 
        
           |  |  | 1084 |         return $reference;
 | 
        
           |  |  | 1085 |     }
 | 
        
           |  |  | 1086 |   | 
        
           |  |  | 1087 |     /**
 | 
        
           |  |  | 1088 |      * Get human readable file info from a the reference.
 | 
        
           |  |  | 1089 |      *
 | 
        
           |  |  | 1090 |      * @param string $reference
 | 
        
           |  |  | 1091 |      * @param int $filestatus
 | 
        
           |  |  | 1092 |      */
 | 
        
           |  |  | 1093 |     public function get_reference_details($reference, $filestatus = 0) {
 | 
        
           |  |  | 1094 |         if ($this->disabled) {
 | 
        
           |  |  | 1095 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 1096 |         }
 | 
        
           |  |  | 1097 |         if (empty($reference)) {
 | 
        
           |  |  | 1098 |             return get_string('unknownsource', 'repository');
 | 
        
           |  |  | 1099 |         }
 | 
        
           |  |  | 1100 |         $source = json_decode($reference);
 | 
        
           |  |  | 1101 |         if (empty($source->usesystem)) {
 | 
        
           |  |  | 1102 |             return '';
 | 
        
           |  |  | 1103 |         }
 | 
        
           |  |  | 1104 |         $systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 1105 |   | 
        
           |  |  | 1106 |         if ($systemauth === false) {
 | 
        
           |  |  | 1107 |             return '';
 | 
        
           |  |  | 1108 |         }
 | 
        
           |  |  | 1109 |         $systemservice = new repository_googledocs\rest($systemauth);
 | 
        
           |  |  | 1110 |         $info = $this->get_file_summary($systemservice, $source->id);
 | 
        
           |  |  | 1111 |   | 
        
           |  |  | 1112 |         $owner = '';
 | 
        
           |  |  | 1113 |         if (!empty($info->owners[0]->displayName)) {
 | 
        
           |  |  | 1114 |             $owner = $info->owners[0]->displayName;
 | 
        
           |  |  | 1115 |         }
 | 
        
           |  |  | 1116 |         if ($owner) {
 | 
        
           |  |  | 1117 |             return get_string('owner', 'repository_googledocs', $owner);
 | 
        
           |  |  | 1118 |         } else {
 | 
        
           |  |  | 1119 |             return $info->name;
 | 
        
           |  |  | 1120 |         }
 | 
        
           |  |  | 1121 |     }
 | 
        
           |  |  | 1122 |   | 
        
           |  |  | 1123 |     /**
 | 
        
           |  |  | 1124 |      * Edit/Create Admin Settings Moodle form.
 | 
        
           |  |  | 1125 |      *
 | 
        
           |  |  | 1126 |      * @param moodleform $mform Moodle form (passed by reference).
 | 
        
           |  |  | 1127 |      * @param string $classname repository class name.
 | 
        
           |  |  | 1128 |      */
 | 
        
           |  |  | 1129 |     public static function type_config_form($mform, $classname = 'repository') {
 | 
        
           |  |  | 1130 |         $url = new moodle_url('/admin/tool/oauth2/issuers.php');
 | 
        
           |  |  | 1131 |         $url = $url->out();
 | 
        
           |  |  | 1132 |   | 
        
           |  |  | 1133 |         $mform->addElement('static', null, '', get_string('oauth2serviceslink', 'repository_googledocs', $url));
 | 
        
           |  |  | 1134 |   | 
        
           |  |  | 1135 |         parent::type_config_form($mform);
 | 
        
           |  |  | 1136 |         $options = [];
 | 
        
           |  |  | 1137 |         $issuers = \core\oauth2\api::get_all_issuers();
 | 
        
           |  |  | 1138 |   | 
        
           |  |  | 1139 |         foreach ($issuers as $issuer) {
 | 
        
           |  |  | 1140 |             $options[$issuer->get('id')] = s($issuer->get('name'));
 | 
        
           |  |  | 1141 |         }
 | 
        
           |  |  | 1142 |   | 
        
           |  |  | 1143 |         $strrequired = get_string('required');
 | 
        
           |  |  | 1144 |   | 
        
           |  |  | 1145 |         $mform->addElement('select', 'issuerid', get_string('issuer', 'repository_googledocs'), $options);
 | 
        
           |  |  | 1146 |         $mform->addHelpButton('issuerid', 'issuer', 'repository_googledocs');
 | 
        
           |  |  | 1147 |         $mform->addRule('issuerid', $strrequired, 'required', null, 'client');
 | 
        
           |  |  | 1148 |   | 
        
           |  |  | 1149 |         $mform->addElement('static', null, '', get_string('fileoptions', 'repository_googledocs'));
 | 
        
           |  |  | 1150 |         $choices = [
 | 
        
           |  |  | 1151 |             'internal' => get_string('internal', 'repository_googledocs'),
 | 
        
           |  |  | 1152 |             'external' => get_string('external', 'repository_googledocs'),
 | 
        
           |  |  | 1153 |             'both' => get_string('both', 'repository_googledocs')
 | 
        
           |  |  | 1154 |         ];
 | 
        
           |  |  | 1155 |         $mform->addElement('select', 'supportedreturntypes', get_string('supportedreturntypes', 'repository_googledocs'), $choices);
 | 
        
           |  |  | 1156 |   | 
        
           |  |  | 1157 |         $choices = [
 | 
        
           |  |  | 1158 |             FILE_INTERNAL => get_string('internal', 'repository_googledocs'),
 | 
        
           |  |  | 1159 |             FILE_CONTROLLED_LINK => get_string('external', 'repository_googledocs'),
 | 
        
           |  |  | 1160 |         ];
 | 
        
           |  |  | 1161 |         $mform->addElement('select', 'defaultreturntype', get_string('defaultreturntype', 'repository_googledocs'), $choices);
 | 
        
           |  |  | 1162 |   | 
        
           |  |  | 1163 |         $mform->addElement('static', null, '', get_string('importformat', 'repository_googledocs'));
 | 
        
           |  |  | 1164 |   | 
        
           |  |  | 1165 |         // Documents.
 | 
        
           |  |  | 1166 |         $docsformat = array();
 | 
        
           |  |  | 1167 |         $docsformat['html'] = 'html';
 | 
        
           |  |  | 1168 |         $docsformat['docx'] = 'docx';
 | 
        
           |  |  | 1169 |         $docsformat['odt'] = 'odt';
 | 
        
           |  |  | 1170 |         $docsformat['pdf'] = 'pdf';
 | 
        
           |  |  | 1171 |         $docsformat['rtf'] = 'rtf';
 | 
        
           |  |  | 1172 |         $docsformat['txt'] = 'txt';
 | 
        
           |  |  | 1173 |         core_collator::ksort($docsformat, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 1174 |   | 
        
           |  |  | 1175 |         $mform->addElement('select', 'documentformat', get_string('docsformat', 'repository_googledocs'), $docsformat);
 | 
        
           |  |  | 1176 |         $mform->setDefault('documentformat', $docsformat['rtf']);
 | 
        
           |  |  | 1177 |         $mform->setType('documentformat', PARAM_ALPHANUM);
 | 
        
           |  |  | 1178 |   | 
        
           |  |  | 1179 |         // Drawing.
 | 
        
           |  |  | 1180 |         $drawingformat = array();
 | 
        
           |  |  | 1181 |         $drawingformat['jpeg'] = 'jpeg';
 | 
        
           |  |  | 1182 |         $drawingformat['png'] = 'png';
 | 
        
           |  |  | 1183 |         $drawingformat['svg'] = 'svg';
 | 
        
           |  |  | 1184 |         $drawingformat['pdf'] = 'pdf';
 | 
        
           |  |  | 1185 |         core_collator::ksort($drawingformat, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 1186 |   | 
        
           |  |  | 1187 |         $mform->addElement('select', 'drawingformat', get_string('drawingformat', 'repository_googledocs'), $drawingformat);
 | 
        
           |  |  | 1188 |         $mform->setDefault('drawingformat', $drawingformat['pdf']);
 | 
        
           |  |  | 1189 |         $mform->setType('drawingformat', PARAM_ALPHANUM);
 | 
        
           |  |  | 1190 |   | 
        
           |  |  | 1191 |         // Presentation.
 | 
        
           |  |  | 1192 |         $presentationformat = array();
 | 
        
           |  |  | 1193 |         $presentationformat['pdf'] = 'pdf';
 | 
        
           |  |  | 1194 |         $presentationformat['pptx'] = 'pptx';
 | 
        
           |  |  | 1195 |         $presentationformat['txt'] = 'txt';
 | 
        
           |  |  | 1196 |         core_collator::ksort($presentationformat, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 1197 |   | 
        
           |  |  | 1198 |         $str = get_string('presentationformat', 'repository_googledocs');
 | 
        
           |  |  | 1199 |         $mform->addElement('select', 'presentationformat', $str, $presentationformat);
 | 
        
           |  |  | 1200 |         $mform->setDefault('presentationformat', $presentationformat['pptx']);
 | 
        
           |  |  | 1201 |         $mform->setType('presentationformat', PARAM_ALPHANUM);
 | 
        
           |  |  | 1202 |   | 
        
           |  |  | 1203 |         // Spreadsheet.
 | 
        
           |  |  | 1204 |         $spreadsheetformat = array();
 | 
        
           |  |  | 1205 |         $spreadsheetformat['csv'] = 'csv';
 | 
        
           |  |  | 1206 |         $spreadsheetformat['ods'] = 'ods';
 | 
        
           |  |  | 1207 |         $spreadsheetformat['pdf'] = 'pdf';
 | 
        
           |  |  | 1208 |         $spreadsheetformat['xlsx'] = 'xlsx';
 | 
        
           |  |  | 1209 |         core_collator::ksort($spreadsheetformat, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 1210 |   | 
        
           |  |  | 1211 |         $str = get_string('spreadsheetformat', 'repository_googledocs');
 | 
        
           |  |  | 1212 |         $mform->addElement('select', 'spreadsheetformat', $str, $spreadsheetformat);
 | 
        
           |  |  | 1213 |         $mform->setDefault('spreadsheetformat', $spreadsheetformat['xlsx']);
 | 
        
           |  |  | 1214 |         $mform->setType('spreadsheetformat', PARAM_ALPHANUM);
 | 
        
           |  |  | 1215 |     }
 | 
        
           |  |  | 1216 | }
 | 
        
           |  |  | 1217 |   | 
        
           |  |  | 1218 | /**
 | 
        
           |  |  | 1219 |  * Callback to get the required scopes for system account.
 | 
        
           |  |  | 1220 |  *
 | 
        
           |  |  | 1221 |  * @param \core\oauth2\issuer $issuer
 | 
        
           |  |  | 1222 |  * @return string
 | 
        
           |  |  | 1223 |  */
 | 
        
           |  |  | 1224 | function repository_googledocs_oauth2_system_scopes(\core\oauth2\issuer $issuer) {
 | 
        
           |  |  | 1225 |     if ($issuer->get('id') == get_config('googledocs', 'issuerid')) {
 | 
        
           |  |  | 1226 |         return 'https://www.googleapis.com/auth/drive';
 | 
        
           |  |  | 1227 |     }
 | 
        
           |  |  | 1228 |     return '';
 | 
        
           |  |  | 1229 | }
 |