| 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 |  * Microsoft onedrive repository plugin.
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * @package    repository_onedrive
 | 
        
           |  |  | 21 |  * @copyright  2012 Lancaster University Network Services Ltd
 | 
        
           |  |  | 22 |  * @author     Dan Poltawski <dan.poltawski@luns.net.uk>
 | 
        
           |  |  | 23 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 24 |  */
 | 
        
           |  |  | 25 | class repository_onedrive extends repository {
 | 
        
           |  |  | 26 |     /**
 | 
        
           |  |  | 27 |      * OAuth 2 client
 | 
        
           |  |  | 28 |      * @var \core\oauth2\client
 | 
        
           |  |  | 29 |      */
 | 
        
           |  |  | 30 |     private $client = null;
 | 
        
           |  |  | 31 |   | 
        
           |  |  | 32 |     /**
 | 
        
           |  |  | 33 |      * OAuth 2 Issuer
 | 
        
           |  |  | 34 |      * @var \core\oauth2\issuer
 | 
        
           |  |  | 35 |      */
 | 
        
           |  |  | 36 |     private $issuer = null;
 | 
        
           |  |  | 37 |   | 
        
           |  |  | 38 |     /**
 | 
        
           |  |  | 39 |      * Additional scopes required for drive.
 | 
        
           |  |  | 40 |      */
 | 
        
           |  |  | 41 |     const SCOPES = 'files.readwrite.all';
 | 
        
           |  |  | 42 |   | 
        
           |  |  | 43 |     /**
 | 
        
           |  |  | 44 |      * Constructor.
 | 
        
           |  |  | 45 |      *
 | 
        
           |  |  | 46 |      * @param int $repositoryid repository instance id.
 | 
        
           |  |  | 47 |      * @param int|stdClass $context a context id or context object.
 | 
        
           |  |  | 48 |      * @param array $options repository options.
 | 
        
           |  |  | 49 |      * @param int $readonly indicate this repo is readonly or not.
 | 
        
           |  |  | 50 |      * @return void
 | 
        
           |  |  | 51 |      */
 | 
        
           |  |  | 52 |     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array(), $readonly = 0) {
 | 
        
           |  |  | 53 |         parent::__construct($repositoryid, $context, $options, $readonly = 0);
 | 
        
           |  |  | 54 |   | 
        
           |  |  | 55 |         try {
 | 
        
           |  |  | 56 |             $this->issuer = \core\oauth2\api::get_issuer(get_config('onedrive', 'issuerid'));
 | 
        
           |  |  | 57 |         } catch (dml_missing_record_exception $e) {
 | 
        
           |  |  | 58 |             $this->disabled = true;
 | 
        
           |  |  | 59 |         }
 | 
        
           |  |  | 60 |   | 
        
           |  |  | 61 |         if ($this->issuer && !$this->issuer->get('enabled')) {
 | 
        
           |  |  | 62 |             $this->disabled = true;
 | 
        
           |  |  | 63 |         }
 | 
        
           |  |  | 64 |     }
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 |     /**
 | 
        
           |  |  | 67 |      * Get a cached user authenticated oauth client.
 | 
        
           |  |  | 68 |      *
 | 
        
           |  |  | 69 |      * @param moodle_url $overrideurl - Use this url instead of the repo callback.
 | 
        
           |  |  | 70 |      * @return \core\oauth2\client
 | 
        
           |  |  | 71 |      */
 | 
        
           |  |  | 72 |     protected function get_user_oauth_client($overrideurl = false) {
 | 
        
           |  |  | 73 |         if ($this->client) {
 | 
        
           |  |  | 74 |             return $this->client;
 | 
        
           |  |  | 75 |         }
 | 
        
           |  |  | 76 |         if ($overrideurl) {
 | 
        
           |  |  | 77 |             $returnurl = $overrideurl;
 | 
        
           |  |  | 78 |         } else {
 | 
        
           |  |  | 79 |             $returnurl = new moodle_url('/repository/repository_callback.php');
 | 
        
           |  |  | 80 |             $returnurl->param('callback', 'yes');
 | 
        
           |  |  | 81 |             $returnurl->param('repo_id', $this->id);
 | 
        
           |  |  | 82 |             $returnurl->param('sesskey', sesskey());
 | 
        
           |  |  | 83 |         }
 | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 |         $this->client = \core\oauth2\api::get_user_oauth_client($this->issuer, $returnurl, self::SCOPES, true);
 | 
        
           |  |  | 86 |   | 
        
           |  |  | 87 |         return $this->client;
 | 
        
           |  |  | 88 |     }
 | 
        
           |  |  | 89 |   | 
        
           |  |  | 90 |     /**
 | 
        
           |  |  | 91 |      * Checks whether the user is authenticate or not.
 | 
        
           |  |  | 92 |      *
 | 
        
           |  |  | 93 |      * @return bool true when logged in.
 | 
        
           |  |  | 94 |      */
 | 
        
           |  |  | 95 |     public function check_login() {
 | 
        
           |  |  | 96 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 97 |         return $client->is_logged_in();
 | 
        
           |  |  | 98 |     }
 | 
        
           |  |  | 99 |   | 
        
           |  |  | 100 |     /**
 | 
        
           |  |  | 101 |      * Print or return the login form.
 | 
        
           |  |  | 102 |      *
 | 
        
           |  |  | 103 |      * @return void|array for ajax.
 | 
        
           |  |  | 104 |      */
 | 
        
           |  |  | 105 |     public function print_login() {
 | 
        
           |  |  | 106 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 107 |         $url = $client->get_login_url();
 | 
        
           |  |  | 108 |   | 
        
           |  |  | 109 |         if ($this->options['ajax']) {
 | 
        
           |  |  | 110 |             $popup = new stdClass();
 | 
        
           |  |  | 111 |             $popup->type = 'popup';
 | 
        
           |  |  | 112 |             $popup->url = $url->out(false);
 | 
        
           |  |  | 113 |             return array('login' => array($popup));
 | 
        
           |  |  | 114 |         } else {
 | 
        
           |  |  | 115 |             echo '<a target="_blank" href="'.$url->out(false).'">'.get_string('login', 'repository').'</a>';
 | 
        
           |  |  | 116 |         }
 | 
        
           |  |  | 117 |     }
 | 
        
           |  |  | 118 |   | 
        
           |  |  | 119 |     /**
 | 
        
           |  |  | 120 |      * Print the login in a popup.
 | 
        
           |  |  | 121 |      *
 | 
        
           |  |  | 122 |      * @param array|null $attr Custom attributes to be applied to popup div.
 | 
        
           |  |  | 123 |      */
 | 
        
           |  |  | 124 |     public function print_login_popup($attr = null) {
 | 
        
           |  |  | 125 |         global $OUTPUT, $PAGE;
 | 
        
           |  |  | 126 |   | 
        
           |  |  | 127 |         $client = $this->get_user_oauth_client(false);
 | 
        
           |  |  | 128 |         $url = new moodle_url($client->get_login_url());
 | 
        
           |  |  | 129 |         $state = $url->get_param('state') . '&reloadparent=true';
 | 
        
           |  |  | 130 |         $url->param('state', $state);
 | 
        
           |  |  | 131 |   | 
        
           |  |  | 132 |         $PAGE->set_pagelayout('embedded');
 | 
        
           |  |  | 133 |         echo $OUTPUT->header();
 | 
        
           |  |  | 134 |   | 
        
           |  |  | 135 |         $repositoryname = get_string('pluginname', 'repository_onedrive');
 | 
        
           |  |  | 136 |   | 
        
           |  |  | 137 |         $button = new single_button(
 | 
        
           |  |  | 138 |             $url,
 | 
        
           |  |  | 139 |             get_string('logintoaccount', 'repository', $repositoryname),
 | 
        
           |  |  | 140 |             'post',
 | 
        
           |  |  | 141 |             single_button::BUTTON_PRIMARY
 | 
        
           |  |  | 142 |         );
 | 
        
           |  |  | 143 |         $button->add_action(new popup_action('click', $url, 'Login'));
 | 
        
           |  |  | 144 |         $button->class = 'mdl-align';
 | 
        
           |  |  | 145 |         $button = $OUTPUT->render($button);
 | 
        
           |  |  | 146 |         echo html_writer::div($button, '', $attr);
 | 
        
           |  |  | 147 |   | 
        
           |  |  | 148 |         echo $OUTPUT->footer();
 | 
        
           |  |  | 149 |     }
 | 
        
           |  |  | 150 |   | 
        
           |  |  | 151 |     /**
 | 
        
           |  |  | 152 |      * Build the breadcrumb from a path.
 | 
        
           |  |  | 153 |      *
 | 
        
           |  |  | 154 |      * @param string $path to create a breadcrumb from.
 | 
        
           |  |  | 155 |      * @return array containing name and path of each crumb.
 | 
        
           |  |  | 156 |      */
 | 
        
           |  |  | 157 |     protected function build_breadcrumb($path) {
 | 
        
           |  |  | 158 |         $bread = explode('/', $path);
 | 
        
           |  |  | 159 |         $crumbtrail = '';
 | 
        
           |  |  | 160 |         foreach ($bread as $crumb) {
 | 
        
           |  |  | 161 |             list($id, $name) = $this->explode_node_path($crumb);
 | 
        
           |  |  | 162 |             $name = empty($name) ? $id : $name;
 | 
        
           |  |  | 163 |             $breadcrumb[] = array(
 | 
        
           |  |  | 164 |                 'name' => $name,
 | 
        
           |  |  | 165 |                 'path' => $this->build_node_path($id, $name, $crumbtrail)
 | 
        
           |  |  | 166 |             );
 | 
        
           |  |  | 167 |             $tmp = end($breadcrumb);
 | 
        
           |  |  | 168 |             $crumbtrail = $tmp['path'];
 | 
        
           |  |  | 169 |         }
 | 
        
           |  |  | 170 |         return $breadcrumb;
 | 
        
           |  |  | 171 |     }
 | 
        
           |  |  | 172 |   | 
        
           |  |  | 173 |     /**
 | 
        
           |  |  | 174 |      * Generates a safe path to a node.
 | 
        
           |  |  | 175 |      *
 | 
        
           |  |  | 176 |      * Typically, a node will be id|Name of the node.
 | 
        
           |  |  | 177 |      *
 | 
        
           |  |  | 178 |      * @param string $id of the node.
 | 
        
           |  |  | 179 |      * @param string $name of the node, will be URL encoded.
 | 
        
           |  |  | 180 |      * @param string $root to append the node on, must be a result of this function.
 | 
        
           |  |  | 181 |      * @return string path to the node.
 | 
        
           |  |  | 182 |      */
 | 
        
           |  |  | 183 |     protected function build_node_path($id, $name = '', $root = '') {
 | 
        
           |  |  | 184 |         $path = $id;
 | 
        
           |  |  | 185 |         if (!empty($name)) {
 | 
        
           |  |  | 186 |             $path .= '|' . urlencode($name);
 | 
        
           |  |  | 187 |         }
 | 
        
           |  |  | 188 |         if (!empty($root)) {
 | 
        
           |  |  | 189 |             $path = trim($root, '/') . '/' . $path;
 | 
        
           |  |  | 190 |         }
 | 
        
           |  |  | 191 |         return $path;
 | 
        
           |  |  | 192 |     }
 | 
        
           |  |  | 193 |   | 
        
           |  |  | 194 |     /**
 | 
        
           |  |  | 195 |      * Returns information about a node in a path.
 | 
        
           |  |  | 196 |      *
 | 
        
           |  |  | 197 |      * @see self::build_node_path()
 | 
        
           |  |  | 198 |      * @param string $node to extrat information from.
 | 
        
           |  |  | 199 |      * @return array about the node.
 | 
        
           |  |  | 200 |      */
 | 
        
           |  |  | 201 |     protected function explode_node_path($node) {
 | 
        
           |  |  | 202 |         if (strpos($node, '|') !== false) {
 | 
        
           |  |  | 203 |             list($id, $name) = explode('|', $node, 2);
 | 
        
           |  |  | 204 |             $name = urldecode($name);
 | 
        
           |  |  | 205 |         } else {
 | 
        
           |  |  | 206 |             $id = $node;
 | 
        
           |  |  | 207 |             $name = '';
 | 
        
           |  |  | 208 |         }
 | 
        
           |  |  | 209 |         $id = urldecode($id);
 | 
        
           |  |  | 210 |         return array(
 | 
        
           |  |  | 211 |   | 
        
           |  |  | 212 |             1 => $name,
 | 
        
           |  |  | 213 |             'id' => $id,
 | 
        
           |  |  | 214 |             'name' => $name
 | 
        
           |  |  | 215 |         );
 | 
        
           |  |  | 216 |     }
 | 
        
           |  |  | 217 |   | 
        
           |  |  | 218 |     /**
 | 
        
           |  |  | 219 |      * List the files and folders.
 | 
        
           |  |  | 220 |      *
 | 
        
           |  |  | 221 |      * @param  string $path path to browse.
 | 
        
           |  |  | 222 |      * @param  string $page page to browse.
 | 
        
           |  |  | 223 |      * @return array of result.
 | 
        
           |  |  | 224 |      */
 | 
        
           |  |  | 225 |     public function get_listing($path='', $page = '') {
 | 
        
           |  |  | 226 |         if (empty($path)) {
 | 
        
           |  |  | 227 |             $path = $this->build_node_path('root', get_string('pluginname', 'repository_onedrive'));
 | 
        
           |  |  | 228 |         }
 | 
        
           |  |  | 229 |   | 
        
           |  |  | 230 |         if ($this->disabled) {
 | 
        
           |  |  | 231 |             // Empty list of files for disabled repository.
 | 
        
           |  |  | 232 |             return ['dynload' => false, 'list' => [], 'nologin' => true];
 | 
        
           |  |  | 233 |         }
 | 
        
           |  |  | 234 |   | 
        
           |  |  | 235 |         // We analyse the path to extract what to browse.
 | 
        
           |  |  | 236 |         $trail = explode('/', $path);
 | 
        
           |  |  | 237 |         $uri = array_pop($trail);
 | 
        
           |  |  | 238 |         list($id, $name) = $this->explode_node_path($uri);
 | 
        
           |  |  | 239 |   | 
        
           |  |  | 240 |         // Handle the special keyword 'search', which we defined in self::search() so that
 | 
        
           |  |  | 241 |         // we could set up a breadcrumb in the search results. In any other case ID would be
 | 
        
           |  |  | 242 |         // 'root' which is a special keyword, or a parent (folder) ID.
 | 
        
           |  |  | 243 |         if ($id === 'search') {
 | 
        
           |  |  | 244 |             $q = $name;
 | 
        
           |  |  | 245 |             $id = 'root';
 | 
        
           |  |  | 246 |   | 
        
           |  |  | 247 |             // Append the active path for search.
 | 
        
           |  |  | 248 |             $str = get_string('searchfor', 'repository_onedrive', $searchtext);
 | 
        
           |  |  | 249 |             $path = $this->build_node_path('search', $str, $path);
 | 
        
           |  |  | 250 |         }
 | 
        
           |  |  | 251 |   | 
        
           |  |  | 252 |         // Query the Drive.
 | 
        
           |  |  | 253 |         $parent = $id;
 | 
        
           |  |  | 254 |         if ($parent != 'root') {
 | 
        
           |  |  | 255 |             $parent = 'items/' . $parent;
 | 
        
           |  |  | 256 |         }
 | 
        
           |  |  | 257 |         $q = '';
 | 
        
           |  |  | 258 |         $results = $this->query($q, $path, $parent);
 | 
        
           |  |  | 259 |   | 
        
           |  |  | 260 |         $ret = [];
 | 
        
           |  |  | 261 |         $ret['dynload'] = true;
 | 
        
           |  |  | 262 |         $ret['path'] = $this->build_breadcrumb($path);
 | 
        
           |  |  | 263 |         $ret['list'] = $results;
 | 
        
           |  |  | 264 |         $ret['manage'] = 'https://www.office.com/';
 | 
        
           |  |  | 265 |         return $ret;
 | 
        
           |  |  | 266 |     }
 | 
        
           |  |  | 267 |   | 
        
           |  |  | 268 |     /**
 | 
        
           |  |  | 269 |      * Search throughout the OneDrive
 | 
        
           |  |  | 270 |      *
 | 
        
           |  |  | 271 |      * @param string $searchtext text to search for.
 | 
        
           |  |  | 272 |      * @param int $page search page.
 | 
        
           |  |  | 273 |      * @return array of results.
 | 
        
           |  |  | 274 |      */
 | 
        
           |  |  | 275 |     public function search($searchtext, $page = 0) {
 | 
        
           |  |  | 276 |         $path = $this->build_node_path('root', get_string('pluginname', 'repository_onedrive'));
 | 
        
           |  |  | 277 |         $str = get_string('searchfor', 'repository_onedrive', $searchtext);
 | 
        
           |  |  | 278 |         $path = $this->build_node_path('search', $str, $path);
 | 
        
           |  |  | 279 |   | 
        
           |  |  | 280 |         // Query the Drive.
 | 
        
           |  |  | 281 |         $parent = 'root';
 | 
        
           |  |  | 282 |         $results = $this->query($searchtext, $path, 'root');
 | 
        
           |  |  | 283 |   | 
        
           |  |  | 284 |         $ret = [];
 | 
        
           |  |  | 285 |         $ret['dynload'] = true;
 | 
        
           |  |  | 286 |         $ret['path'] = $this->build_breadcrumb($path);
 | 
        
           |  |  | 287 |         $ret['list'] = $results;
 | 
        
           |  |  | 288 |         $ret['manage'] = 'https://www.office.com/';
 | 
        
           |  |  | 289 |         return $ret;
 | 
        
           |  |  | 290 |     }
 | 
        
           |  |  | 291 |   | 
        
           |  |  | 292 |     /**
 | 
        
           |  |  | 293 |      * Query OneDrive for files and folders using a search query.
 | 
        
           |  |  | 294 |      *
 | 
        
           |  |  | 295 |      * Documentation about the query format can be found here:
 | 
        
           |  |  | 296 |      *   https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/driveitem
 | 
        
           |  |  | 297 |      *   https://developer.microsoft.com/en-us/graph/docs/overview/query_parameters
 | 
        
           |  |  | 298 |      *
 | 
        
           |  |  | 299 |      * This returns a list of files and folders with their details as they should be
 | 
        
           |  |  | 300 |      * formatted and returned by functions such as get_listing() or search().
 | 
        
           |  |  | 301 |      *
 | 
        
           |  |  | 302 |      * @param string $q search query as expected by the Graph API.
 | 
        
           |  |  | 303 |      * @param string $path parent path of the current files, will not be used for the query.
 | 
        
           |  |  | 304 |      * @param string $parent Parent id.
 | 
        
           |  |  | 305 |      * @param int $page page.
 | 
        
           |  |  | 306 |      * @return array of files and folders.
 | 
        
           |  |  | 307 |      * @throws Exception
 | 
        
           |  |  | 308 |      * @throws repository_exception
 | 
        
           |  |  | 309 |      */
 | 
        
           |  |  | 310 |     protected function query($q, $path = null, $parent = null, $page = 0) {
 | 
        
           |  |  | 311 |         global $OUTPUT;
 | 
        
           |  |  | 312 |   | 
        
           |  |  | 313 |         $files = [];
 | 
        
           |  |  | 314 |         $folders = [];
 | 
        
           |  |  | 315 |         $fields = "folder,id,lastModifiedDateTime,name,size,webUrl,thumbnails";
 | 
        
           |  |  | 316 |         $params = ['$select' => $fields, '$expand' => 'thumbnails', 'parent' => $parent];
 | 
        
           |  |  | 317 |   | 
        
           |  |  | 318 |         try {
 | 
        
           |  |  | 319 |             // Retrieving files and folders.
 | 
        
           |  |  | 320 |             $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 321 |             $service = new repository_onedrive\rest($client);
 | 
        
           |  |  | 322 |   | 
        
           |  |  | 323 |             if (!empty($q)) {
 | 
        
           |  |  | 324 |                 $params['search'] = urlencode($q);
 | 
        
           |  |  | 325 |   | 
        
           |  |  | 326 |                 // MS does not return thumbnails on a search.
 | 
        
           |  |  | 327 |                 unset($params['$expand']);
 | 
        
           |  |  | 328 |                 $response = $service->call('search', $params);
 | 
        
           |  |  | 329 |             } else {
 | 
        
           |  |  | 330 |                 $response = $service->call('list', $params);
 | 
        
           |  |  | 331 |             }
 | 
        
           |  |  | 332 |         } catch (Exception $e) {
 | 
        
           |  |  | 333 |             if ($e->getCode() == 403 && strpos($e->getMessage(), 'Access Not Configured') !== false) {
 | 
        
           |  |  | 334 |                 throw new repository_exception('servicenotenabled', 'repository_onedrive');
 | 
        
           |  |  | 335 |             } else if (strpos($e->getMessage(), 'mysite not found') !== false) {
 | 
        
           |  |  | 336 |                 throw new repository_exception('mysitenotfound', 'repository_onedrive');
 | 
        
           |  |  | 337 |             }
 | 
        
           |  |  | 338 |         }
 | 
        
           |  |  | 339 |   | 
        
           |  |  | 340 |         $remotefiles = isset($response->value) ? $response->value : [];
 | 
        
           |  |  | 341 |         foreach ($remotefiles as $remotefile) {
 | 
        
           |  |  | 342 |             if (!empty($remotefile->folder)) {
 | 
        
           |  |  | 343 |                 // This is a folder.
 | 
        
           |  |  | 344 |                 $folders[$remotefile->id] = [
 | 
        
           |  |  | 345 |                     'title' => $remotefile->name,
 | 
        
           |  |  | 346 |                     'path' => $this->build_node_path($remotefile->id, $remotefile->name, $path),
 | 
        
           |  |  | 347 |                     'date' => strtotime($remotefile->lastModifiedDateTime),
 | 
        
           |  |  | 348 |                     'thumbnail' => $OUTPUT->image_url(file_folder_icon())->out(false),
 | 
        
           |  |  | 349 |                     'thumbnail_height' => 64,
 | 
        
           |  |  | 350 |                     'thumbnail_width' => 64,
 | 
        
           |  |  | 351 |                     'children' => []
 | 
        
           |  |  | 352 |                 ];
 | 
        
           |  |  | 353 |             } else {
 | 
        
           |  |  | 354 |                 // We can download all other file types.
 | 
        
           |  |  | 355 |                 $title = $remotefile->name;
 | 
        
           |  |  | 356 |                 $source = json_encode([
 | 
        
           |  |  | 357 |                         'id' => $remotefile->id,
 | 
        
           |  |  | 358 |                         'name' => $remotefile->name,
 | 
        
           |  |  | 359 |                         'link' => $remotefile->webUrl
 | 
        
           |  |  | 360 |                     ]);
 | 
        
           |  |  | 361 |   | 
        
           |  |  | 362 |                 $thumb = '';
 | 
        
           |  |  | 363 |                 $thumbwidth = 0;
 | 
        
           |  |  | 364 |                 $thumbheight = 0;
 | 
        
           |  |  | 365 |                 $extendedinfoerr = false;
 | 
        
           |  |  | 366 |   | 
        
           |  |  | 367 |                 if (empty($remotefile->thumbnails)) {
 | 
        
           |  |  | 368 |                     // Try and get it directly from the item.
 | 
        
           |  |  | 369 |                     $params = ['fileid' => $remotefile->id, '$select' => $fields, '$expand' => 'thumbnails'];
 | 
        
           |  |  | 370 |                     try {
 | 
        
           |  |  | 371 |                         $response = $service->call('get', $params);
 | 
        
           |  |  | 372 |                         $remotefile = $response;
 | 
        
           |  |  | 373 |                     } catch (Exception $e) {
 | 
        
           |  |  | 374 |                         // This is not a failure condition - we just could not get extended info about the file.
 | 
        
           |  |  | 375 |                         $extendedinfoerr = true;
 | 
        
           |  |  | 376 |                     }
 | 
        
           |  |  | 377 |                 }
 | 
        
           |  |  | 378 |   | 
        
           |  |  | 379 |                 if (!empty($remotefile->thumbnails)) {
 | 
        
           |  |  | 380 |                     $thumbs = $remotefile->thumbnails;
 | 
        
           |  |  | 381 |                     if (count($thumbs)) {
 | 
        
           |  |  | 382 |                         $first = reset($thumbs);
 | 
        
           |  |  | 383 |                         if (!empty($first->medium) && !empty($first->medium->url)) {
 | 
        
           |  |  | 384 |                             $thumb = $first->medium->url;
 | 
        
           |  |  | 385 |                             $thumbwidth = min($first->medium->width, 64);
 | 
        
           |  |  | 386 |                             $thumbheight = min($first->medium->height, 64);
 | 
        
           |  |  | 387 |                         }
 | 
        
           |  |  | 388 |                     }
 | 
        
           |  |  | 389 |                 }
 | 
        
           |  |  | 390 |   | 
        
           |  |  | 391 |                 $files[$remotefile->id] = [
 | 
        
           |  |  | 392 |                     'title' => $title,
 | 
        
           |  |  | 393 |                     'source' => $source,
 | 
        
           |  |  | 394 |                     'date' => strtotime($remotefile->lastModifiedDateTime),
 | 
        
           |  |  | 395 |                     'size' => isset($remotefile->size) ? $remotefile->size : null,
 | 
        
           |  |  | 396 |                     'thumbnail' => $thumb,
 | 
        
           |  |  | 397 |                     'thumbnail_height' => $thumbwidth,
 | 
        
           |  |  | 398 |                     'thumbnail_width' => $thumbheight,
 | 
        
           |  |  | 399 |                 ];
 | 
        
           |  |  | 400 |             }
 | 
        
           |  |  | 401 |         }
 | 
        
           |  |  | 402 |   | 
        
           |  |  | 403 |         // Filter and order the results.
 | 
        
           |  |  | 404 |         $files = array_filter($files, [$this, 'filter']);
 | 
        
           |  |  | 405 |         core_collator::ksort($files, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 406 |         core_collator::ksort($folders, core_collator::SORT_NATURAL);
 | 
        
           |  |  | 407 |         return array_merge(array_values($folders), array_values($files));
 | 
        
           |  |  | 408 |     }
 | 
        
           |  |  | 409 |   | 
        
           |  |  | 410 |     /**
 | 
        
           |  |  | 411 |      * Logout.
 | 
        
           |  |  | 412 |      *
 | 
        
           |  |  | 413 |      * @return string
 | 
        
           |  |  | 414 |      */
 | 
        
           |  |  | 415 |     public function logout() {
 | 
        
           |  |  | 416 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 417 |         $client->log_out();
 | 
        
           |  |  | 418 |         return parent::logout();
 | 
        
           |  |  | 419 |     }
 | 
        
           |  |  | 420 |   | 
        
           |  |  | 421 |     /**
 | 
        
           |  |  | 422 |      * Get a file.
 | 
        
           |  |  | 423 |      *
 | 
        
           |  |  | 424 |      * @param string $reference reference of the file.
 | 
        
           |  |  | 425 |      * @param string $filename filename to save the file to.
 | 
        
           |  |  | 426 |      * @return string JSON encoded array of information about the file.
 | 
        
           |  |  | 427 |      */
 | 
        
           |  |  | 428 |     public function get_file($reference, $filename = '') {
 | 
        
           |  |  | 429 |         global $CFG;
 | 
        
           |  |  | 430 |   | 
        
           |  |  | 431 |         if ($this->disabled) {
 | 
        
           |  |  | 432 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 433 |         }
 | 
        
           |  |  | 434 |         $sourceinfo = json_decode($reference);
 | 
        
           |  |  | 435 |   | 
        
           |  |  | 436 |         $client = null;
 | 
        
           |  |  | 437 |         if (!empty($sourceinfo->usesystem)) {
 | 
        
           |  |  | 438 |             $client = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 439 |         } else {
 | 
        
           |  |  | 440 |             $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 441 |         }
 | 
        
           |  |  | 442 |   | 
        
           |  |  | 443 |         $base = 'https://graph.microsoft.com/v1.0/';
 | 
        
           |  |  | 444 |   | 
        
           | 1441 | ariadna | 445 |         // Fetch the item info.
 | 
        
           |  |  | 446 |         $infourl = (new moodle_url($base . 'me/drive/items/' . $sourceinfo->id))->out(false);
 | 
        
           |  |  | 447 |         $response = $client->get($infourl);
 | 
        
           |  |  | 448 |         if (!$response) {
 | 
        
           |  |  | 449 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 450 |         }
 | 
        
           |  |  | 451 |         $response = json_decode($response, true);
 | 
        
           |  |  | 452 |         $downloadurl = $response['@microsoft.graph.downloadUrl'];
 | 
        
           | 1 | efrain | 453 |   | 
        
           |  |  | 454 |         // We use download_one and not the rest API because it has special timeouts etc.
 | 
        
           |  |  | 455 |         $path = $this->prepare_file($filename);
 | 
        
           |  |  | 456 |         $options = ['filepath' => $path, 'timeout' => 15, 'followlocation' => true, 'maxredirs' => 5];
 | 
        
           | 1441 | ariadna | 457 |         // We cannot send authorization headers in the direct download request, it will fail.
 | 
        
           |  |  | 458 |         $c = new curl();
 | 
        
           |  |  | 459 |         $result = $c->download_one($downloadurl, null, $options);
 | 
        
           | 1 | efrain | 460 |   | 
        
           |  |  | 461 |         if ($result) {
 | 
        
           |  |  | 462 |             @chmod($path, $CFG->filepermissions);
 | 
        
           |  |  | 463 |             return array(
 | 
        
           |  |  | 464 |                 'path' => $path,
 | 
        
           |  |  | 465 |                 'url' => $reference
 | 
        
           |  |  | 466 |             );
 | 
        
           |  |  | 467 |         }
 | 
        
           |  |  | 468 |         throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 469 |     }
 | 
        
           |  |  | 470 |   | 
        
           |  |  | 471 |     /**
 | 
        
           |  |  | 472 |      * Prepare file reference information.
 | 
        
           |  |  | 473 |      *
 | 
        
           |  |  | 474 |      * We are using this method to clean up the source to make sure that it
 | 
        
           |  |  | 475 |      * is a valid source.
 | 
        
           |  |  | 476 |      *
 | 
        
           |  |  | 477 |      * @param string $source of the file.
 | 
        
           |  |  | 478 |      * @return string file reference.
 | 
        
           |  |  | 479 |      */
 | 
        
           |  |  | 480 |     public function get_file_reference($source) {
 | 
        
           |  |  | 481 |         // We could do some magic upgrade code here.
 | 
        
           |  |  | 482 |         return $source;
 | 
        
           |  |  | 483 |     }
 | 
        
           |  |  | 484 |   | 
        
           |  |  | 485 |     /**
 | 
        
           |  |  | 486 |      * What kind of files will be in this repository?
 | 
        
           |  |  | 487 |      *
 | 
        
           |  |  | 488 |      * @return array return '*' means this repository support any files, otherwise
 | 
        
           |  |  | 489 |      *               return mimetypes of files, it can be an array
 | 
        
           |  |  | 490 |      */
 | 
        
           |  |  | 491 |     public function supported_filetypes() {
 | 
        
           |  |  | 492 |         return '*';
 | 
        
           |  |  | 493 |     }
 | 
        
           |  |  | 494 |   | 
        
           |  |  | 495 |     /**
 | 
        
           |  |  | 496 |      * Tells how the file can be picked from this repository.
 | 
        
           |  |  | 497 |      *
 | 
        
           |  |  | 498 |      * @return int
 | 
        
           |  |  | 499 |      */
 | 
        
           |  |  | 500 |     public function supported_returntypes() {
 | 
        
           |  |  | 501 |         // We can only support references if the system account is connected.
 | 
        
           |  |  | 502 |         if (!empty($this->issuer) && $this->issuer->is_system_account_connected()) {
 | 
        
           |  |  | 503 |             $setting = get_config('onedrive', 'supportedreturntypes');
 | 
        
           |  |  | 504 |             if ($setting == 'internal') {
 | 
        
           |  |  | 505 |                 return FILE_INTERNAL;
 | 
        
           |  |  | 506 |             } else if ($setting == 'external') {
 | 
        
           |  |  | 507 |                 return FILE_CONTROLLED_LINK;
 | 
        
           |  |  | 508 |             } else {
 | 
        
           |  |  | 509 |                 return FILE_CONTROLLED_LINK | FILE_INTERNAL;
 | 
        
           |  |  | 510 |             }
 | 
        
           |  |  | 511 |         } else {
 | 
        
           |  |  | 512 |             return FILE_INTERNAL;
 | 
        
           |  |  | 513 |         }
 | 
        
           |  |  | 514 |     }
 | 
        
           |  |  | 515 |   | 
        
           |  |  | 516 |     /**
 | 
        
           |  |  | 517 |      * Which return type should be selected by default.
 | 
        
           |  |  | 518 |      *
 | 
        
           |  |  | 519 |      * @return int
 | 
        
           |  |  | 520 |      */
 | 
        
           |  |  | 521 |     public function default_returntype() {
 | 
        
           |  |  | 522 |         $setting = get_config('onedrive', 'defaultreturntype');
 | 
        
           |  |  | 523 |         $supported = get_config('onedrive', 'supportedreturntypes');
 | 
        
           |  |  | 524 |         if (($setting == FILE_INTERNAL && $supported != 'external') || $supported == 'internal') {
 | 
        
           |  |  | 525 |             return FILE_INTERNAL;
 | 
        
           |  |  | 526 |         } else {
 | 
        
           |  |  | 527 |             return FILE_CONTROLLED_LINK;
 | 
        
           |  |  | 528 |         }
 | 
        
           |  |  | 529 |     }
 | 
        
           |  |  | 530 |   | 
        
           |  |  | 531 |     /**
 | 
        
           |  |  | 532 |      * Return names of the general options.
 | 
        
           |  |  | 533 |      * By default: no general option name.
 | 
        
           |  |  | 534 |      *
 | 
        
           |  |  | 535 |      * @return array
 | 
        
           |  |  | 536 |      */
 | 
        
           |  |  | 537 |     public static function get_type_option_names() {
 | 
        
           |  |  | 538 |         return array('issuerid', 'pluginname', 'defaultreturntype', 'supportedreturntypes');
 | 
        
           |  |  | 539 |     }
 | 
        
           |  |  | 540 |   | 
        
           |  |  | 541 |     /**
 | 
        
           |  |  | 542 |      * Store the access token.
 | 
        
           |  |  | 543 |      */
 | 
        
           |  |  | 544 |     public function callback() {
 | 
        
           |  |  | 545 |         $client = $this->get_user_oauth_client();
 | 
        
           |  |  | 546 |         // This will upgrade to an access token if we have an authorization code and save the access token in the session.
 | 
        
           |  |  | 547 |         $client->is_logged_in();
 | 
        
           |  |  | 548 |     }
 | 
        
           |  |  | 549 |   | 
        
           |  |  | 550 |     /**
 | 
        
           |  |  | 551 |      * Repository method to serve the referenced file
 | 
        
           |  |  | 552 |      *
 | 
        
           |  |  | 553 |      * @see send_stored_file
 | 
        
           |  |  | 554 |      *
 | 
        
           |  |  | 555 |      * @param stored_file $storedfile the file that contains the reference
 | 
        
           |  |  | 556 |      * @param int $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime)
 | 
        
           |  |  | 557 |      * @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
 | 
        
           |  |  | 558 |      * @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
 | 
        
           |  |  | 559 |      * @param array $options additional options affecting the file serving
 | 
        
           |  |  | 560 |      */
 | 
        
           | 1441 | ariadna | 561 |     public function send_file($storedfile, $lifetime=null , $filter=0, $forcedownload=false, ?array $options = null) {
 | 
        
           | 1 | efrain | 562 |         if ($this->disabled) {
 | 
        
           |  |  | 563 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 564 |         }
 | 
        
           |  |  | 565 |   | 
        
           |  |  | 566 |         $source = json_decode($storedfile->get_reference());
 | 
        
           |  |  | 567 |   | 
        
           |  |  | 568 |         $fb = get_file_browser();
 | 
        
           |  |  | 569 |         $context = context::instance_by_id($storedfile->get_contextid(), MUST_EXIST);
 | 
        
           |  |  | 570 |         $info = $fb->get_file_info($context,
 | 
        
           |  |  | 571 |                                    $storedfile->get_component(),
 | 
        
           |  |  | 572 |                                    $storedfile->get_filearea(),
 | 
        
           |  |  | 573 |                                    $storedfile->get_itemid(),
 | 
        
           |  |  | 574 |                                    $storedfile->get_filepath(),
 | 
        
           |  |  | 575 |                                    $storedfile->get_filename());
 | 
        
           |  |  | 576 |   | 
        
           |  |  | 577 |         if (empty($options['offline']) && !empty($info) && $info->is_writable() && !empty($source->usesystem)) {
 | 
        
           |  |  | 578 |             // Add the current user as an OAuth writer.
 | 
        
           |  |  | 579 |             $systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 580 |   | 
        
           |  |  | 581 |             if ($systemauth === false) {
 | 
        
           |  |  | 582 |                 $details = 'Cannot connect as system user';
 | 
        
           |  |  | 583 |                 throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 584 |             }
 | 
        
           |  |  | 585 |             $systemservice = new repository_onedrive\rest($systemauth);
 | 
        
           |  |  | 586 |   | 
        
           |  |  | 587 |             // Get the user oauth so we can get the account to add.
 | 
        
           |  |  | 588 |             $url = moodle_url::make_pluginfile_url($storedfile->get_contextid(),
 | 
        
           |  |  | 589 |                                                    $storedfile->get_component(),
 | 
        
           |  |  | 590 |                                                    $storedfile->get_filearea(),
 | 
        
           |  |  | 591 |                                                    $storedfile->get_itemid(),
 | 
        
           |  |  | 592 |                                                    $storedfile->get_filepath(),
 | 
        
           |  |  | 593 |                                                    $storedfile->get_filename(),
 | 
        
           |  |  | 594 |                                                    $forcedownload);
 | 
        
           |  |  | 595 |             $url->param('sesskey', sesskey());
 | 
        
           |  |  | 596 |             $param = ($options['embed'] == true) ? false : $url;
 | 
        
           |  |  | 597 |             $userauth = $this->get_user_oauth_client($param);
 | 
        
           |  |  | 598 |   | 
        
           |  |  | 599 |             if (!$userauth->is_logged_in()) {
 | 
        
           |  |  | 600 |                 if ($options['embed'] == true) {
 | 
        
           |  |  | 601 |                     // Due to Same-origin policy, we cannot redirect to onedrive login page.
 | 
        
           |  |  | 602 |                     // If the requested file is embed and the user is not logged in, add option to log in using a popup.
 | 
        
           |  |  | 603 |                     $this->print_login_popup(['style' => 'margin-top: 250px']);
 | 
        
           |  |  | 604 |                     exit;
 | 
        
           |  |  | 605 |                 }
 | 
        
           |  |  | 606 |                 redirect($userauth->get_login_url());
 | 
        
           |  |  | 607 |             }
 | 
        
           |  |  | 608 |             if ($userauth === false) {
 | 
        
           |  |  | 609 |                 $details = 'Cannot connect as current user';
 | 
        
           |  |  | 610 |                 throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 611 |             }
 | 
        
           |  |  | 612 |             $userinfo = $userauth->get_userinfo();
 | 
        
           |  |  | 613 |             $useremail = $userinfo['email'];
 | 
        
           |  |  | 614 |   | 
        
           |  |  | 615 |             $this->add_temp_writer_to_file($systemservice, $source->id, $useremail);
 | 
        
           |  |  | 616 |         }
 | 
        
           |  |  | 617 |   | 
        
           |  |  | 618 |         if (!empty($options['offline'])) {
 | 
        
           |  |  | 619 |             $downloaded = $this->get_file($storedfile->get_reference(), $storedfile->get_filename());
 | 
        
           |  |  | 620 |             $filename = $storedfile->get_filename();
 | 
        
           |  |  | 621 |             send_file($downloaded['path'], $filename, $lifetime, $filter, false, $forcedownload, '', false, $options);
 | 
        
           |  |  | 622 |         } else if ($source->link) {
 | 
        
           |  |  | 623 |             // Do not use redirect() here because is not compatible with webservice/pluginfile.php.
 | 
        
           |  |  | 624 |             header('Location: ' . $source->link);
 | 
        
           |  |  | 625 |         } else {
 | 
        
           |  |  | 626 |             $details = 'File is missing source link';
 | 
        
           |  |  | 627 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 628 |         }
 | 
        
           |  |  | 629 |     }
 | 
        
           |  |  | 630 |   | 
        
           |  |  | 631 |     /**
 | 
        
           |  |  | 632 |      * See if a folder exists within a folder
 | 
        
           |  |  | 633 |      *
 | 
        
           |  |  | 634 |      * @param \repository_onedrive\rest $client Authenticated client.
 | 
        
           |  |  | 635 |      * @param string $fullpath
 | 
        
           |  |  | 636 |      * @return string|boolean The file id if it exists or false.
 | 
        
           |  |  | 637 |      */
 | 
        
           |  |  | 638 |     protected function get_file_id_by_path(\repository_onedrive\rest $client, $fullpath) {
 | 
        
           |  |  | 639 |         $fields = "id";
 | 
        
           |  |  | 640 |         try {
 | 
        
           |  |  | 641 |             $response = $client->call('get_file_by_path', ['fullpath' => $fullpath, '$select' => $fields]);
 | 
        
           |  |  | 642 |         } catch (\core\oauth2\rest_exception $re) {
 | 
        
           |  |  | 643 |             return false;
 | 
        
           |  |  | 644 |         }
 | 
        
           |  |  | 645 |         return $response->id;
 | 
        
           |  |  | 646 |     }
 | 
        
           |  |  | 647 |   | 
        
           |  |  | 648 |     /**
 | 
        
           |  |  | 649 |      * Delete a file by full path.
 | 
        
           |  |  | 650 |      *
 | 
        
           |  |  | 651 |      * @param \repository_onedrive\rest $client Authenticated client.
 | 
        
           |  |  | 652 |      * @param string $fullpath
 | 
        
           |  |  | 653 |      * @return boolean
 | 
        
           |  |  | 654 |      */
 | 
        
           |  |  | 655 |     protected function delete_file_by_path(\repository_onedrive\rest $client, $fullpath) {
 | 
        
           |  |  | 656 |         try {
 | 
        
           |  |  | 657 |             $response = $client->call('delete_file_by_path', ['fullpath' => $fullpath]);
 | 
        
           |  |  | 658 |         } catch (\core\oauth2\rest_exception $re) {
 | 
        
           |  |  | 659 |             return false;
 | 
        
           |  |  | 660 |         }
 | 
        
           |  |  | 661 |         return true;
 | 
        
           |  |  | 662 |     }
 | 
        
           |  |  | 663 |   | 
        
           |  |  | 664 |     /**
 | 
        
           |  |  | 665 |      * Create a folder within a folder
 | 
        
           |  |  | 666 |      *
 | 
        
           |  |  | 667 |      * @param \repository_onedrive\rest $client Authenticated client.
 | 
        
           |  |  | 668 |      * @param string $foldername The folder we are creating.
 | 
        
           |  |  | 669 |      * @param string $parentid The parent folder we are creating in.
 | 
        
           |  |  | 670 |      *
 | 
        
           |  |  | 671 |      * @return string The file id of the new folder.
 | 
        
           |  |  | 672 |      */
 | 
        
           |  |  | 673 |     protected function create_folder_in_folder(\repository_onedrive\rest $client, $foldername, $parentid) {
 | 
        
           |  |  | 674 |         $params = ['parentid' => $parentid];
 | 
        
           |  |  | 675 |         $folder = [ 'name' => $foldername, 'folder' => [ 'childCount' => 0 ]];
 | 
        
           |  |  | 676 |         $created = $client->call('create_folder', $params, json_encode($folder));
 | 
        
           |  |  | 677 |         if (empty($created->id)) {
 | 
        
           |  |  | 678 |             $details = 'Cannot create folder:' . $foldername;
 | 
        
           |  |  | 679 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 680 |         }
 | 
        
           |  |  | 681 |         return $created->id;
 | 
        
           |  |  | 682 |     }
 | 
        
           |  |  | 683 |   | 
        
           |  |  | 684 |     /**
 | 
        
           |  |  | 685 |      * Get simple file info for humans.
 | 
        
           |  |  | 686 |      *
 | 
        
           |  |  | 687 |      * @param \repository_onedrive\rest $client Authenticated client.
 | 
        
           |  |  | 688 |      * @param string $fileid The file we are querying.
 | 
        
           |  |  | 689 |      *
 | 
        
           |  |  | 690 |      * @return stdClass
 | 
        
           |  |  | 691 |      */
 | 
        
           |  |  | 692 |     protected function get_file_summary(\repository_onedrive\rest $client, $fileid) {
 | 
        
           |  |  | 693 |         $fields = "folder,id,lastModifiedDateTime,name,size,webUrl,createdByUser";
 | 
        
           |  |  | 694 |         $response = $client->call('get', ['fileid' => $fileid, '$select' => $fields]);
 | 
        
           |  |  | 695 |         return $response;
 | 
        
           |  |  | 696 |     }
 | 
        
           |  |  | 697 |   | 
        
           |  |  | 698 |     /**
 | 
        
           |  |  | 699 |      * Add a writer to the permissions on the file (temporary).
 | 
        
           |  |  | 700 |      *
 | 
        
           |  |  | 701 |      * @param \repository_onedrive\rest $client Authenticated client.
 | 
        
           |  |  | 702 |      * @param string $fileid The file we are updating.
 | 
        
           |  |  | 703 |      * @param string $email The email of the writer account to add.
 | 
        
           |  |  | 704 |      * @return boolean
 | 
        
           |  |  | 705 |      */
 | 
        
           |  |  | 706 |     protected function add_temp_writer_to_file(\repository_onedrive\rest $client, $fileid, $email) {
 | 
        
           |  |  | 707 |         // Expires in 7 days.
 | 
        
           |  |  | 708 |         $expires = new DateTime();
 | 
        
           |  |  | 709 |         $expires->add(new DateInterval("P7D"));
 | 
        
           |  |  | 710 |   | 
        
           |  |  | 711 |         $updateeditor = [
 | 
        
           |  |  | 712 |             'recipients' => [[ 'email' => $email ]],
 | 
        
           |  |  | 713 |             'roles' => ['write'],
 | 
        
           |  |  | 714 |             'requireSignIn' => true,
 | 
        
           |  |  | 715 |             'sendInvitation' => false
 | 
        
           |  |  | 716 |         ];
 | 
        
           |  |  | 717 |         $params = ['fileid' => $fileid];
 | 
        
           |  |  | 718 |         $response = $client->call('create_permission', $params, json_encode($updateeditor));
 | 
        
           |  |  | 719 |         if (empty($response->value[0]->id)) {
 | 
        
           |  |  | 720 |             $details = 'Cannot add user ' . $email . ' as a writer for document: ' . $fileid;
 | 
        
           |  |  | 721 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 722 |         }
 | 
        
           |  |  | 723 |         // Store the permission id in the DB. Scheduled task will remove this permission after 7 days.
 | 
        
           |  |  | 724 |         if ($access = repository_onedrive\access::get_record(['permissionid' => $response->value[0]->id, 'itemid' => $fileid ])) {
 | 
        
           |  |  | 725 |             // Update the timemodified.
 | 
        
           |  |  | 726 |             $access->update();
 | 
        
           |  |  | 727 |         } else {
 | 
        
           |  |  | 728 |             $record = (object) [ 'permissionid' => $response->value[0]->id, 'itemid' => $fileid ];
 | 
        
           |  |  | 729 |             $access = new repository_onedrive\access(0, $record);
 | 
        
           |  |  | 730 |             $access->create();
 | 
        
           |  |  | 731 |         }
 | 
        
           |  |  | 732 |         return true;
 | 
        
           |  |  | 733 |     }
 | 
        
           |  |  | 734 |   | 
        
           |  |  | 735 |     /**
 | 
        
           |  |  | 736 |      * Allow anyone with the link to read the file.
 | 
        
           |  |  | 737 |      *
 | 
        
           |  |  | 738 |      * @param \repository_onedrive\rest $client Authenticated client.
 | 
        
           |  |  | 739 |      * @param string $fileid The file we are updating.
 | 
        
           |  |  | 740 |      * @return boolean
 | 
        
           |  |  | 741 |      */
 | 
        
           |  |  | 742 |     protected function set_file_sharing_anyone_with_link_can_read(\repository_onedrive\rest $client, $fileid) {
 | 
        
           |  |  | 743 |   | 
        
           |  |  | 744 |         $type = (isset($this->options['embed']) && $this->options['embed'] == true) ? 'embed' : 'view';
 | 
        
           |  |  | 745 |         $updateread = [
 | 
        
           |  |  | 746 |             'type' => $type,
 | 
        
           |  |  | 747 |             'scope' => 'anonymous'
 | 
        
           |  |  | 748 |         ];
 | 
        
           |  |  | 749 |         $params = ['fileid' => $fileid];
 | 
        
           |  |  | 750 |         $response = $client->call('create_link', $params, json_encode($updateread));
 | 
        
           |  |  | 751 |         if (empty($response->link)) {
 | 
        
           |  |  | 752 |             $details = 'Cannot update link sharing for the document: ' . $fileid;
 | 
        
           |  |  | 753 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 754 |         }
 | 
        
           |  |  | 755 |         return $response->link->webUrl;
 | 
        
           |  |  | 756 |     }
 | 
        
           |  |  | 757 |   | 
        
           |  |  | 758 |     /**
 | 
        
           |  |  | 759 |      * Given a filename, use the core_filetypes registered types to guess a mimetype.
 | 
        
           |  |  | 760 |      *
 | 
        
           |  |  | 761 |      * If no mimetype is known, return 'application/unknown';
 | 
        
           |  |  | 762 |      *
 | 
        
           |  |  | 763 |      * @param string $filename
 | 
        
           |  |  | 764 |      * @return string $mimetype
 | 
        
           |  |  | 765 |      */
 | 
        
           |  |  | 766 |     protected function get_mimetype_from_filename($filename) {
 | 
        
           |  |  | 767 |         $mimetype = 'application/unknown';
 | 
        
           |  |  | 768 |         $types = core_filetypes::get_types();
 | 
        
           |  |  | 769 |         $fileextension = '.bin';
 | 
        
           |  |  | 770 |         if (strpos($filename, '.') !== false) {
 | 
        
           |  |  | 771 |             $fileextension = substr($filename, strrpos($filename, '.') + 1);
 | 
        
           |  |  | 772 |         }
 | 
        
           |  |  | 773 |   | 
        
           |  |  | 774 |         if (isset($types[$fileextension])) {
 | 
        
           |  |  | 775 |             $mimetype = $types[$fileextension]['type'];
 | 
        
           |  |  | 776 |         }
 | 
        
           |  |  | 777 |         return $mimetype;
 | 
        
           |  |  | 778 |     }
 | 
        
           |  |  | 779 |   | 
        
           |  |  | 780 |     /**
 | 
        
           |  |  | 781 |      * Upload a file to onedrive.
 | 
        
           |  |  | 782 |      *
 | 
        
           |  |  | 783 |      * @param \repository_onedrive\rest $service Authenticated client.
 | 
        
           |  |  | 784 |      * @param \curl $curl Curl client to perform the put operation (with no auth headers).
 | 
        
           |  |  | 785 |      * @param \curl $authcurl Curl client that will send authentication headers
 | 
        
           |  |  | 786 |      * @param string $filepath The local path to the file to upload
 | 
        
           |  |  | 787 |      * @param string $mimetype The new mimetype
 | 
        
           |  |  | 788 |      * @param string $parentid The folder to put it.
 | 
        
           |  |  | 789 |      * @param string $filename The name of the new file
 | 
        
           |  |  | 790 |      * @return string $fileid
 | 
        
           |  |  | 791 |      */
 | 
        
           |  |  | 792 |     protected function upload_file(\repository_onedrive\rest $service, \curl $curl, \curl $authcurl,
 | 
        
           |  |  | 793 |                                    $filepath, $mimetype, $parentid, $filename) {
 | 
        
           |  |  | 794 |         // Start an upload session.
 | 
        
           |  |  | 795 |         // Docs https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/api/item_createuploadsession link.
 | 
        
           |  |  | 796 |   | 
        
           |  |  | 797 |         $params = ['parentid' => $parentid, 'filename' => urlencode($filename)];
 | 
        
           |  |  | 798 |         $behaviour = [ 'item' => [ "@microsoft.graph.conflictBehavior" => "rename" ] ];
 | 
        
           |  |  | 799 |         $created = $service->call('create_upload', $params, json_encode($behaviour));
 | 
        
           |  |  | 800 |         if (empty($created->uploadUrl)) {
 | 
        
           |  |  | 801 |             $details = 'Cannot begin upload session:' . $parentid;
 | 
        
           |  |  | 802 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 803 |         }
 | 
        
           |  |  | 804 |   | 
        
           |  |  | 805 |         $options = ['file' => $filepath];
 | 
        
           |  |  | 806 |   | 
        
           |  |  | 807 |         // Try each curl class in turn until we succeed.
 | 
        
           |  |  | 808 |         // First attempt an upload with no auth headers (will work for personal onedrive accounts).
 | 
        
           |  |  | 809 |         // If that fails, try an upload with the auth headers (will work for work onedrive accounts).
 | 
        
           |  |  | 810 |         $curls = [$curl, $authcurl];
 | 
        
           |  |  | 811 |         $response = null;
 | 
        
           |  |  | 812 |         foreach ($curls as $curlinstance) {
 | 
        
           |  |  | 813 |             $curlinstance->setHeader('Content-type: ' . $mimetype);
 | 
        
           |  |  | 814 |             $size = filesize($filepath);
 | 
        
           |  |  | 815 |             $curlinstance->setHeader('Content-Range: bytes 0-' . ($size - 1) . '/' . $size);
 | 
        
           |  |  | 816 |             $response = $curlinstance->put($created->uploadUrl, $options);
 | 
        
           |  |  | 817 |             if ($curlinstance->errno == 0) {
 | 
        
           |  |  | 818 |                 $response = json_decode($response);
 | 
        
           |  |  | 819 |             }
 | 
        
           |  |  | 820 |             if (!empty($response->id)) {
 | 
        
           |  |  | 821 |                 // We can stop now - there is a valid file returned.
 | 
        
           |  |  | 822 |                 break;
 | 
        
           |  |  | 823 |             }
 | 
        
           |  |  | 824 |         }
 | 
        
           |  |  | 825 |   | 
        
           |  |  | 826 |         if (empty($response->id)) {
 | 
        
           |  |  | 827 |             $details = 'File not created';
 | 
        
           |  |  | 828 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 829 |         }
 | 
        
           |  |  | 830 |   | 
        
           |  |  | 831 |         return $response->id;
 | 
        
           |  |  | 832 |     }
 | 
        
           |  |  | 833 |   | 
        
           |  |  | 834 |   | 
        
           |  |  | 835 |     /**
 | 
        
           |  |  | 836 |      * Called when a file is selected as a "link".
 | 
        
           |  |  | 837 |      * Invoked at MOODLE/repository/repository_ajax.php
 | 
        
           |  |  | 838 |      *
 | 
        
           |  |  | 839 |      * What should happen here is that the file should be copied to a new file owned by the moodle system user.
 | 
        
           |  |  | 840 |      * It should be organised in a folder based on the file context.
 | 
        
           |  |  | 841 |      * It's sharing permissions should allow read access with the link.
 | 
        
           |  |  | 842 |      * The returned reference should point to the newly copied file - not the original.
 | 
        
           |  |  | 843 |      *
 | 
        
           |  |  | 844 |      * @param string $reference this reference is generated by
 | 
        
           |  |  | 845 |      *                          repository::get_file_reference()
 | 
        
           |  |  | 846 |      * @param context $context the target context for this new file.
 | 
        
           |  |  | 847 |      * @param string $component the target component for this new file.
 | 
        
           |  |  | 848 |      * @param string $filearea the target filearea for this new file.
 | 
        
           |  |  | 849 |      * @param string $itemid the target itemid for this new file.
 | 
        
           |  |  | 850 |      * @return string $modifiedreference (final one before saving to DB)
 | 
        
           |  |  | 851 |      */
 | 
        
           |  |  | 852 |     public function reference_file_selected($reference, $context, $component, $filearea, $itemid) {
 | 
        
           |  |  | 853 |         global $CFG, $SITE;
 | 
        
           |  |  | 854 |   | 
        
           |  |  | 855 |         // What we need to do here is transfer ownership to the system user (or copy)
 | 
        
           |  |  | 856 |         // then set the permissions so anyone with the share link can view,
 | 
        
           |  |  | 857 |         // finally update the reference to contain the share link if it was not
 | 
        
           |  |  | 858 |         // already there (and point to new file id if we copied).
 | 
        
           |  |  | 859 |         $source = json_decode($reference);
 | 
        
           |  |  | 860 |         if (!empty($source->usesystem)) {
 | 
        
           |  |  | 861 |             // If we already copied this file to the system account - we are done.
 | 
        
           |  |  | 862 |             return $reference;
 | 
        
           |  |  | 863 |         }
 | 
        
           |  |  | 864 |   | 
        
           |  |  | 865 |         // Get a system and a user oauth client.
 | 
        
           |  |  | 866 |         $systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 867 |   | 
        
           |  |  | 868 |         if ($systemauth === false) {
 | 
        
           |  |  | 869 |             $details = 'Cannot connect as system user';
 | 
        
           |  |  | 870 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 871 |         }
 | 
        
           |  |  | 872 |   | 
        
           |  |  | 873 |         $userauth = $this->get_user_oauth_client();
 | 
        
           |  |  | 874 |         if ($userauth === false) {
 | 
        
           |  |  | 875 |             $details = 'Cannot connect as current user';
 | 
        
           |  |  | 876 |             throw new repository_exception('errorwhilecommunicatingwith', 'repository', '', $details);
 | 
        
           |  |  | 877 |         }
 | 
        
           |  |  | 878 |   | 
        
           |  |  | 879 |         $systemservice = new repository_onedrive\rest($systemauth);
 | 
        
           |  |  | 880 |   | 
        
           | 1441 | ariadna | 881 |         $base = 'https://graph.microsoft.com/v1.0/';
 | 
        
           |  |  | 882 |   | 
        
           |  |  | 883 |         // Fetch the item info.
 | 
        
           |  |  | 884 |         $infourl = (new moodle_url($base . 'me/drive/items/' . $source->id))->out(false);
 | 
        
           |  |  | 885 |         $response = $userauth->get($infourl);
 | 
        
           |  |  | 886 |         if (!$response) {
 | 
        
           |  |  | 887 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 888 |         }
 | 
        
           |  |  | 889 |         $response = json_decode($response, true);
 | 
        
           |  |  | 890 |         $downloadurl = $response['@microsoft.graph.downloadUrl'];
 | 
        
           |  |  | 891 |   | 
        
           | 1 | efrain | 892 |         // Download the file.
 | 
        
           |  |  | 893 |         $tmpfilename = clean_param($source->id, PARAM_PATH);
 | 
        
           |  |  | 894 |         $temppath = make_request_directory() . $tmpfilename;
 | 
        
           |  |  | 895 |   | 
        
           | 1441 | ariadna | 896 |         // We cannot send authorization headers in the direct download request, it will fail.
 | 
        
           |  |  | 897 |         $c = new curl();
 | 
        
           | 1 | efrain | 898 |         $options = ['filepath' => $temppath, 'timeout' => 60, 'followlocation' => true, 'maxredirs' => 5];
 | 
        
           | 1441 | ariadna | 899 |         $result = $c->download_one($downloadurl, null, $options);
 | 
        
           | 1 | efrain | 900 |   | 
        
           |  |  | 901 |         if (!$result) {
 | 
        
           |  |  | 902 |             throw new repository_exception('cannotdownload', 'repository');
 | 
        
           |  |  | 903 |         }
 | 
        
           |  |  | 904 |   | 
        
           |  |  | 905 |         // Now copy it to a sensible folder.
 | 
        
           |  |  | 906 |         $contextlist = array_reverse($context->get_parent_contexts(true));
 | 
        
           |  |  | 907 |   | 
        
           |  |  | 908 |         $cache = cache::make('repository_onedrive', 'folder');
 | 
        
           |  |  | 909 |         $parentid = 'root';
 | 
        
           |  |  | 910 |         $fullpath = '';
 | 
        
           |  |  | 911 |         $allfolders = [];
 | 
        
           |  |  | 912 |         foreach ($contextlist as $context) {
 | 
        
           |  |  | 913 |             // Prepare human readable context folders names, making sure they are still unique within the site.
 | 
        
           |  |  | 914 |             $prevlang = force_current_language($CFG->lang);
 | 
        
           |  |  | 915 |             $foldername = $context->get_context_name();
 | 
        
           |  |  | 916 |             force_current_language($prevlang);
 | 
        
           |  |  | 917 |   | 
        
           |  |  | 918 |             if ($context->contextlevel == CONTEXT_SYSTEM) {
 | 
        
           |  |  | 919 |                 // Append the site short name to the root folder.
 | 
        
           |  |  | 920 |                 $foldername .= '_'.$SITE->shortname;
 | 
        
           |  |  | 921 |                 // Append the relevant object id.
 | 
        
           |  |  | 922 |             } else if ($context->instanceid) {
 | 
        
           |  |  | 923 |                 $foldername .= '_id_'.$context->instanceid;
 | 
        
           |  |  | 924 |             } else {
 | 
        
           |  |  | 925 |                 // This does not really happen but just in case.
 | 
        
           |  |  | 926 |                 $foldername .= '_ctx_'.$context->id;
 | 
        
           |  |  | 927 |             }
 | 
        
           |  |  | 928 |   | 
        
           |  |  | 929 |             $foldername = urlencode(clean_param($foldername, PARAM_PATH));
 | 
        
           |  |  | 930 |             $allfolders[] = $foldername;
 | 
        
           |  |  | 931 |         }
 | 
        
           |  |  | 932 |   | 
        
           |  |  | 933 |         $allfolders[] = urlencode(clean_param($component, PARAM_PATH));
 | 
        
           |  |  | 934 |         $allfolders[] = urlencode(clean_param($filearea, PARAM_PATH));
 | 
        
           |  |  | 935 |         $allfolders[] = urlencode(clean_param($itemid, PARAM_PATH));
 | 
        
           |  |  | 936 |   | 
        
           |  |  | 937 |         // Variable $allfolders now has the complete path we want to store the file in.
 | 
        
           |  |  | 938 |         // Create each folder in $allfolders under the system account.
 | 
        
           |  |  | 939 |         foreach ($allfolders as $foldername) {
 | 
        
           |  |  | 940 |             if ($fullpath) {
 | 
        
           |  |  | 941 |                 $fullpath .= '/';
 | 
        
           |  |  | 942 |             }
 | 
        
           |  |  | 943 |             $fullpath .= $foldername;
 | 
        
           |  |  | 944 |   | 
        
           |  |  | 945 |             $folderid = $cache->get($fullpath);
 | 
        
           |  |  | 946 |             if (empty($folderid)) {
 | 
        
           |  |  | 947 |                 $folderid = $this->get_file_id_by_path($systemservice, $fullpath);
 | 
        
           |  |  | 948 |             }
 | 
        
           |  |  | 949 |             if ($folderid !== false) {
 | 
        
           |  |  | 950 |                 $cache->set($fullpath, $folderid);
 | 
        
           |  |  | 951 |                 $parentid = $folderid;
 | 
        
           |  |  | 952 |             } else {
 | 
        
           |  |  | 953 |                 // Create it.
 | 
        
           |  |  | 954 |                 $parentid = $this->create_folder_in_folder($systemservice, $foldername, $parentid);
 | 
        
           |  |  | 955 |                 $cache->set($fullpath, $parentid);
 | 
        
           |  |  | 956 |             }
 | 
        
           |  |  | 957 |         }
 | 
        
           |  |  | 958 |   | 
        
           |  |  | 959 |         // Delete any existing file at this path.
 | 
        
           |  |  | 960 |         $path = $fullpath . '/' . urlencode(clean_param($source->name, PARAM_PATH));
 | 
        
           |  |  | 961 |         $this->delete_file_by_path($systemservice, $path);
 | 
        
           |  |  | 962 |   | 
        
           |  |  | 963 |         // Upload the file.
 | 
        
           |  |  | 964 |         $safefilename = clean_param($source->name, PARAM_PATH);
 | 
        
           |  |  | 965 |         $mimetype = $this->get_mimetype_from_filename($safefilename);
 | 
        
           |  |  | 966 |         // We cannot send authorization headers in the upload or personal microsoft accounts will fail (what a joke!).
 | 
        
           |  |  | 967 |         $curl = new \curl();
 | 
        
           |  |  | 968 |         $fileid = $this->upload_file($systemservice, $curl, $systemauth, $temppath, $mimetype, $parentid, $safefilename);
 | 
        
           |  |  | 969 |   | 
        
           |  |  | 970 |         // Read with link.
 | 
        
           |  |  | 971 |         $link = $this->set_file_sharing_anyone_with_link_can_read($systemservice, $fileid);
 | 
        
           |  |  | 972 |   | 
        
           |  |  | 973 |         $summary = $this->get_file_summary($systemservice, $fileid);
 | 
        
           |  |  | 974 |   | 
        
           |  |  | 975 |         // Update the details in the file reference before it is saved.
 | 
        
           |  |  | 976 |         $source->id = $summary->id;
 | 
        
           |  |  | 977 |         $source->link = $link;
 | 
        
           |  |  | 978 |         $source->usesystem = true;
 | 
        
           |  |  | 979 |   | 
        
           |  |  | 980 |         $reference = json_encode($source);
 | 
        
           |  |  | 981 |   | 
        
           |  |  | 982 |         return $reference;
 | 
        
           |  |  | 983 |     }
 | 
        
           |  |  | 984 |   | 
        
           |  |  | 985 |     /**
 | 
        
           |  |  | 986 |      * Get human readable file info from the reference.
 | 
        
           |  |  | 987 |      *
 | 
        
           |  |  | 988 |      * @param string $reference
 | 
        
           |  |  | 989 |      * @param int $filestatus
 | 
        
           |  |  | 990 |      */
 | 
        
           |  |  | 991 |     public function get_reference_details($reference, $filestatus = 0) {
 | 
        
           |  |  | 992 |         if (empty($reference)) {
 | 
        
           |  |  | 993 |             return get_string('unknownsource', 'repository');
 | 
        
           |  |  | 994 |         }
 | 
        
           |  |  | 995 |         $source = json_decode($reference);
 | 
        
           |  |  | 996 |         if (empty($source->usesystem)) {
 | 
        
           |  |  | 997 |             return '';
 | 
        
           |  |  | 998 |         }
 | 
        
           |  |  | 999 |         $systemauth = \core\oauth2\api::get_system_oauth_client($this->issuer);
 | 
        
           |  |  | 1000 |   | 
        
           |  |  | 1001 |         if ($systemauth === false) {
 | 
        
           |  |  | 1002 |             return '';
 | 
        
           |  |  | 1003 |         }
 | 
        
           |  |  | 1004 |         $systemservice = new repository_onedrive\rest($systemauth);
 | 
        
           |  |  | 1005 |         $info = $this->get_file_summary($systemservice, $source->id);
 | 
        
           |  |  | 1006 |   | 
        
           |  |  | 1007 |         $owner = '';
 | 
        
           |  |  | 1008 |         if (!empty($info->createdByUser->displayName)) {
 | 
        
           |  |  | 1009 |             $owner = $info->createdByUser->displayName;
 | 
        
           |  |  | 1010 |         }
 | 
        
           |  |  | 1011 |         if ($owner) {
 | 
        
           |  |  | 1012 |             return get_string('owner', 'repository_onedrive', $owner);
 | 
        
           |  |  | 1013 |         } else {
 | 
        
           |  |  | 1014 |             return $info->name;
 | 
        
           |  |  | 1015 |         }
 | 
        
           |  |  | 1016 |     }
 | 
        
           |  |  | 1017 |   | 
        
           |  |  | 1018 |     /**
 | 
        
           |  |  | 1019 |      * @deprecated since Moodle 4.0
 | 
        
           |  |  | 1020 |      */
 | 
        
           | 1441 | ariadna | 1021 |     #[\core\attribute\deprecated(null, reason: 'It is no longer used', since: '4.0', final: true)]
 | 
        
           | 1 | efrain | 1022 |     public static function can_import_skydrive_files() {
 | 
        
           | 1441 | ariadna | 1023 |         \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
 | 
        
           | 1 | efrain | 1024 |     }
 | 
        
           |  |  | 1025 |   | 
        
           |  |  | 1026 |     /**
 | 
        
           |  |  | 1027 |      * @deprecated since Moodle 4.0
 | 
        
           |  |  | 1028 |      */
 | 
        
           | 1441 | ariadna | 1029 |     #[\core\attribute\deprecated(null, reason: 'It is no longer used', since: '4.0', final: true)]
 | 
        
           | 1 | efrain | 1030 |     public static function import_skydrive_files() {
 | 
        
           | 1441 | ariadna | 1031 |         \core\deprecation::emit_deprecation([self::class, __FUNCTION__]);
 | 
        
           | 1 | efrain | 1032 |     }
 | 
        
           |  |  | 1033 |   | 
        
           |  |  | 1034 |     /**
 | 
        
           |  |  | 1035 |      * Edit/Create Admin Settings Moodle form.
 | 
        
           |  |  | 1036 |      *
 | 
        
           |  |  | 1037 |      * @param moodleform $mform Moodle form (passed by reference).
 | 
        
           |  |  | 1038 |      * @param string $classname repository class name.
 | 
        
           |  |  | 1039 |      */
 | 
        
           |  |  | 1040 |     public static function type_config_form($mform, $classname = 'repository') {
 | 
        
           |  |  | 1041 |         global $OUTPUT;
 | 
        
           |  |  | 1042 |   | 
        
           |  |  | 1043 |         $url = new moodle_url('/admin/tool/oauth2/issuers.php');
 | 
        
           |  |  | 1044 |         $url = $url->out();
 | 
        
           |  |  | 1045 |   | 
        
           |  |  | 1046 |         $mform->addElement('static', null, '', get_string('oauth2serviceslink', 'repository_onedrive', $url));
 | 
        
           |  |  | 1047 |   | 
        
           |  |  | 1048 |         parent::type_config_form($mform);
 | 
        
           |  |  | 1049 |         $options = [];
 | 
        
           |  |  | 1050 |         $issuers = \core\oauth2\api::get_all_issuers();
 | 
        
           |  |  | 1051 |   | 
        
           |  |  | 1052 |         foreach ($issuers as $issuer) {
 | 
        
           |  |  | 1053 |             $options[$issuer->get('id')] = s($issuer->get('name'));
 | 
        
           |  |  | 1054 |         }
 | 
        
           |  |  | 1055 |   | 
        
           |  |  | 1056 |         $strrequired = get_string('required');
 | 
        
           |  |  | 1057 |   | 
        
           |  |  | 1058 |         $mform->addElement('select', 'issuerid', get_string('issuer', 'repository_onedrive'), $options);
 | 
        
           |  |  | 1059 |         $mform->addHelpButton('issuerid', 'issuer', 'repository_onedrive');
 | 
        
           |  |  | 1060 |         $mform->addRule('issuerid', $strrequired, 'required', null, 'client');
 | 
        
           |  |  | 1061 |   | 
        
           |  |  | 1062 |         $mform->addElement('static', null, '', get_string('fileoptions', 'repository_onedrive'));
 | 
        
           |  |  | 1063 |         $choices = [
 | 
        
           |  |  | 1064 |             'internal' => get_string('internal', 'repository_onedrive'),
 | 
        
           |  |  | 1065 |             'external' => get_string('external', 'repository_onedrive'),
 | 
        
           |  |  | 1066 |             'both' => get_string('both', 'repository_onedrive')
 | 
        
           |  |  | 1067 |         ];
 | 
        
           |  |  | 1068 |         $mform->addElement('select', 'supportedreturntypes', get_string('supportedreturntypes', 'repository_onedrive'), $choices);
 | 
        
           |  |  | 1069 |   | 
        
           |  |  | 1070 |         $choices = [
 | 
        
           |  |  | 1071 |             FILE_INTERNAL => get_string('internal', 'repository_onedrive'),
 | 
        
           |  |  | 1072 |             FILE_CONTROLLED_LINK => get_string('external', 'repository_onedrive'),
 | 
        
           |  |  | 1073 |         ];
 | 
        
           |  |  | 1074 |         $mform->addElement('select', 'defaultreturntype', get_string('defaultreturntype', 'repository_onedrive'), $choices);
 | 
        
           |  |  | 1075 |   | 
        
           |  |  | 1076 |     }
 | 
        
           |  |  | 1077 | }
 | 
        
           |  |  | 1078 |   | 
        
           |  |  | 1079 | /**
 | 
        
           |  |  | 1080 |  * Callback to get the required scopes for system account.
 | 
        
           |  |  | 1081 |  *
 | 
        
           |  |  | 1082 |  * @param \core\oauth2\issuer $issuer
 | 
        
           |  |  | 1083 |  * @return string
 | 
        
           |  |  | 1084 |  */
 | 
        
           |  |  | 1085 | function repository_onedrive_oauth2_system_scopes(\core\oauth2\issuer $issuer) {
 | 
        
           |  |  | 1086 |     if ($issuer->get('id') == get_config('onedrive', 'issuerid')) {
 | 
        
           |  |  | 1087 |         return repository_onedrive::SCOPES;
 | 
        
           |  |  | 1088 |     }
 | 
        
           |  |  | 1089 |     return '';
 | 
        
           |  |  | 1090 | }
 |