21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
23 | */
24 |
25 | $string['cachedef_unifiedfolderids'] = 'Microsoft 365 Repository - Unified folder IDs';
26 | $string['cachedef_unifiedgroupfolderids'] = 'Microsoft 365 Repository - Unified folder IDs for groups';
27 | $string['configplugin'] = 'Configure Microsoft 365 Repository';
28 | $string['coursegroup'] = 'Disable Groups (Courses) folder in file picker';
29 | $string['defaultgroupsfolder'] = 'Course Files';
30 |
31 | $string['erroraccessdenied'] = 'Access denied';
32 | $string['errorauthoidcnotconfig'] = 'Please configure the OpenID Connect authentication plugin before attempting to use the Microsoft 365 repository.';
33 | $string['errorbadclienttype'] = 'Invalid client type.';
34 | $string['errorbadpath'] = 'Bad Path';
35 | $string['errorcoursenotfound'] = 'Course not found';
36 | $string['erroro365required'] = 'This file is currently only available to Microsoft 365 users.';
37 | $string['errorwhiledownload'] = 'An error occurred while downloading the file';
38 |
39 | $string['file'] = 'File';
40 | $string['groups'] = 'Groups (Courses)';
41 | $string['myfiles'] = 'My OneDrive';
42 | $string['notconfigured'] = 'To use this plugin, you must first configure the Microsoft 365 plugins
';
43 | $string['office365:view'] = 'View Microsoft 365 repository';
44 | $string['onedrivegroup'] = 'Disable My OneDrive folder in file picker';
45 | $string['pluginname'] = 'Microsoft 365';
46 | $string['pluginname_help'] = 'A Microsoft 365 Repository';
47 | $string['privacy:metadata'] = 'This plugin communicates with the Microsoft 365 OneDrive API as the current user. Any files uploaded will be sent to the remote server';
48 | $string['trendingaround'] = 'Files Trending Around Me';
49 | $string['trendinggroup'] = 'Disable Files Trending Around Me folder in file picker';
50 | $string['upload'] = 'Upload New File';
51 |
--------------------------------------------------------------------------------
/lang/es/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = 'ID de carpetas unificadas';
25 | $string['configplugin'] = 'Configurar repositorio de OneDrive for Business';
26 | $string['courses'] = 'Cursos';
27 | $string['erroraccessdenied'] = 'Acceso denegado';
28 | $string['errorauthoidcnotconfig'] = 'Microsoft Entra ID SSO no configurado';
29 | $string['errorbadclienttype'] = 'Tipo de cliente no válido.';
30 | $string['errorbadpath'] = 'Ruta incorrecta';
31 | $string['errorcoursenotfound'] = 'No se encontró el curso';
32 | $string['errorwhiledownload'] = 'Ocurrió un error al descargar el archivo';
33 | $string['file'] = 'Archivo';
34 | $string['myfiles'] = 'Mis archivos';
35 | $string['office365:view'] = 'Ver repositorio de OneDrive for Business';
36 | $string['pluginname'] = 'Microsoft 365';
37 | $string['pluginname_help'] = 'Un repositorio de OneDrive for Business';
38 | $string['upload'] = 'Subir nuevo archivo';
39 |
--------------------------------------------------------------------------------
/lang/fi/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = 'Yhdistetyt kansiotunnukset';
25 | $string['configplugin'] = 'Määritä OneDrive for Business -tiedostopankki';
26 | $string['courses'] = 'Kurssit';
27 | $string['erroraccessdenied'] = 'Käyttö estetty';
28 | $string['errorauthoidcnotconfig'] = 'Microsoft Entra ID:n SSO-palvelua ei ole määritetty';
29 | $string['errorbadclienttype'] = 'Virheellinen asiakastyyppi.';
30 | $string['errorbadpath'] = 'Virheellinen polku';
31 | $string['errorcoursenotfound'] = 'Kurssia ei löydy';
32 | $string['errorwhiledownload'] = 'Tiedoston lataamisessa tapahtui virhe';
33 | $string['file'] = 'Tiedosto';
34 | $string['myfiles'] = 'Omat tiedostot';
35 | $string['office365:view'] = 'Näytä OneDrive for Business -tiedostopankki';
36 | $string['pluginname'] = 'Microsoft 365';
37 | $string['pluginname_help'] = 'OneDrive for Business -tiedostopankki';
38 | $string['upload'] = 'Lähetä uusi tiedosto';
39 |
--------------------------------------------------------------------------------
/lang/fr/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = 'ID de dossier unifiés';
25 | $string['configplugin'] = 'Configurer le dépôt OneDrive Entreprise';
26 | $string['courses'] = 'Cours';
27 | $string['erroraccessdenied'] = 'Accès refusé';
28 | $string['errorauthoidcnotconfig'] = 'Microsoft Entra ID SSO non configuré';
29 | $string['errorbadclienttype'] = 'Type de client non valide';
30 | $string['errorbadpath'] = 'Chemin incorrect';
31 | $string['errorcoursenotfound'] = 'Cours introuvable';
32 | $string['errorwhiledownload'] = 'Une erreur est survenue lors du téléchargement du fichier';
33 | $string['file'] = 'Fichier';
34 | $string['myfiles'] = 'Mes fichiers';
35 | $string['office365:view'] = 'Afficher le dépôt OneDrive Entreprise';
36 | $string['pluginname'] = 'OneDrive Entreprise';
37 | $string['pluginname_help'] = 'Dépôt OneDrive Entreprise';
38 | $string['upload'] = 'Télécharger un fichier';
39 |
--------------------------------------------------------------------------------
/lang/it/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = 'ID cartella unificati';
25 | $string['configplugin'] = 'Configura repository OneDrive per Business';
26 | $string['courses'] = 'Corsi';
27 | $string['erroraccessdenied'] = 'Accesso negato';
28 | $string['errorauthoidcnotconfig'] = 'SSO Microsoft Entra ID non configurato';
29 | $string['errorbadclienttype'] = 'Tipo di cliente non valido.';
30 | $string['errorbadpath'] = 'Percorso errato';
31 | $string['errorcoursenotfound'] = 'Corso non trovato';
32 | $string['errorwhiledownload'] = 'Si è verificato un errore durante lo scaricamento del file';
33 | $string['file'] = 'File';
34 | $string['myfiles'] = 'I miei file';
35 | $string['office365:view'] = 'Visualizza repository OneDrive per Business';
36 | $string['pluginname'] = 'Microsoft 365';
37 | $string['pluginname_help'] = 'Un repository OneDrive for Business';
38 | $string['upload'] = 'Carica nuovo file';
39 |
--------------------------------------------------------------------------------
/lang/ja/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = '統合フォルダID';
25 | $string['configplugin'] = 'OneDrive for Businessリポジトリを設定する';
26 | $string['courses'] = 'コース';
27 | $string['erroraccessdenied'] = 'アクセスが拒否されました';
28 | $string['errorauthoidcnotconfig'] = 'Microsoft Entra ID SSOが設定されていません';
29 | $string['errorbadclienttype'] = '無効なクライアントタイプです。';
30 | $string['errorbadpath'] = '不正なパス';
31 | $string['errorcoursenotfound'] = 'コースが見つかりませんでした';
32 | $string['errorwhiledownload'] = 'ファイルのダウンロード中にエラーが発生しました';
33 | $string['file'] = 'ファイル';
34 | $string['myfiles'] = 'マイファイル';
35 | $string['office365:view'] = 'OneDrive for Businessリポジトリを表示する';
36 | $string['pluginname'] = 'Microsoft 365';
37 | $string['pluginname_help'] = 'OneDrive for Businessリポジトリ';
38 | $string['upload'] = '新しいファイルをアップロードする';
39 |
--------------------------------------------------------------------------------
/lang/nl/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = 'Uniforme map-ID\'s';
25 | $string['configplugin'] = 'Opslagruimte voor OneDrive voor Bedrijven configureren';
26 | $string['courses'] = 'Cursussen';
27 | $string['erroraccessdenied'] = 'Toegang geweigerd';
28 | $string['errorauthoidcnotconfig'] = 'SSO voor Microsoft Entra ID niet geconfigureerd';
29 | $string['errorbadclienttype'] = 'Ongeldig clienttype.';
30 | $string['errorbadpath'] = 'Verkeerd pad';
31 | $string['errorcoursenotfound'] = 'Cursus niet gevonden';
32 | $string['errorwhiledownload'] = 'Er is een fout opgetreden bij het downloaden van het bestand';
33 | $string['file'] = 'Bestand';
34 | $string['myfiles'] = 'Mijn bestanden';
35 | $string['office365:view'] = 'Opslagruimte van OneDrive voor Bedrijven weergeven';
36 | $string['pluginname'] = 'OneDrive voor Bedrijven';
37 | $string['pluginname_help'] = 'Een opslagruimte voor OneDrive voor Bedrijven';
38 | $string['upload'] = 'Nieuw bestand uploaden';
39 |
--------------------------------------------------------------------------------
/lang/pl/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = 'Identyfikatory ujednoliconych folderów';
25 | $string['configplugin'] = 'Skonfiguruj repozytorium usługi OneDrive dla firm';
26 | $string['courses'] = 'Kursy';
27 | $string['erroraccessdenied'] = 'Brak dostępu';
28 | $string['errorauthoidcnotconfig'] = 'Nie skonfigurowano funkcji rejestracji jednokrotnej do usługi Microsoft Entra ID';
29 | $string['errorbadclienttype'] = 'Nieprawidłowy typ klienta.';
30 | $string['errorbadpath'] = 'Nieprawidłowa ścieżka';
31 | $string['errorcoursenotfound'] = 'Nie znaleziono kursu';
32 | $string['errorwhiledownload'] = 'Wystąpił błąd podczas pobierania pliku';
33 | $string['file'] = 'Plik';
34 | $string['myfiles'] = 'Moje pliki';
35 | $string['office365:view'] = 'Wyświetl repozytorium usługi OneDrive dla firm';
36 | $string['pluginname'] = 'OneDrive dla firm';
37 | $string['pluginname_help'] = 'Repozytorium usługi OneDrive dla firm';
38 | $string['upload'] = 'Prześlij nowy plik';
39 |
--------------------------------------------------------------------------------
/lang/pt_br/repository_office365.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Language file
19 | * @package repository_office365
20 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | */
23 |
24 | $string['cachedef_unifiedfolderids'] = 'IDs de pastas unificadas';
25 | $string['configplugin'] = 'Configurar o repositório do OneDrive for Business';
26 | $string['courses'] = 'Cursos';
27 | $string['erroraccessdenied'] = 'Acesso negado';
28 | $string['errorauthoidcnotconfig'] = 'Microsoft Entra ID SSO não configurado';
29 | $string['errorbadclienttype'] = 'Tipo inválido de cliente.';
30 | $string['errorbadpath'] = 'Caminho inválido';
31 | $string['errorcoursenotfound'] = 'Curso não encontrado';
32 | $string['errorwhiledownload'] = 'Ocorreu um erro durante o download do arquivo';
33 | $string['file'] = 'Arquivo';
34 | $string['myfiles'] = 'Meus arquivos';
35 | $string['office365:view'] = 'Visualizar o repositório do OneDrive for Business';
36 | $string['pluginname'] = 'Microsoft 365';
37 | $string['pluginname_help'] = 'Um repositório do OneDrive for Business';
38 | $string['upload'] = 'Fazer upload de novo arquivo';
39 |
--------------------------------------------------------------------------------
/lib.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Office365 repository lib.
19 | *
20 | * @package repository_office365
21 | * @author James McQuillan
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
24 | */
25 |
26 | use local_o365\httpclient;
27 | use local_o365\oauth2\clientdata;
28 | use local_o365\oauth2\token;
29 | use local_o365\rest\unified;
30 | use local_o365\utils;
31 |
32 | /**
33 | * Microsoft 365 repository.
34 | */
35 | class repository_office365 extends repository {
36 |
37 | /** @var httpclient An HTTP client to use. */
38 | protected $httpclient;
39 |
40 | /** @var bool Whether the Microsoft Graph API is configured. */
41 | protected $unifiedconfigured = false;
42 |
43 | /** @var clientdata A clientdata object to use with an o365 api class. */
44 | protected $clientdata = null;
45 |
46 | /**
47 | * Constructor.
48 | *
49 | * @param int $repositoryid repository instance id
50 | * @param int|stdClass $context a context id or context object
51 | * @param array $options repository options
52 | * @param int $readonly indicate this repo is readonly or not
53 | */
54 | public function __construct($repositoryid, $context = SYSCONTEXTID, $options = [], $readonly = 0) {
55 | parent::__construct($repositoryid, $context, $options, $readonly);
56 | $this->httpclient = new httpclient();
57 | if (utils::is_connected()) {
58 | $this->clientdata = clientdata::instance_from_oidc();
59 | }
60 | $this->unifiedconfigured = unified::is_configured();
61 | }
62 |
63 | /**
64 | * Get a Microsoft Graph API token.
65 | *
66 | * @param bool $system If true, get a system API ser token instead of the user's token.
67 | * @param int|null $userid The userid to get a token for. If null, the current user will be used.
68 | * @return token A Microsoft Graph API token object.
69 | */
70 | protected function get_unified_token($system = false, $userid = null) {
71 | global $USER;
72 | $resource = unified::get_tokenresource();
73 | if ($system === true) {
74 | return utils::get_application_token($resource, $this->clientdata, $this->httpclient);
75 | } else {
76 | $userid = (!empty($userid)) ? $userid : $USER->id;
77 | return token::instance($userid, $resource, $this->clientdata, $this->httpclient);
78 | }
79 | }
80 |
81 | /**
82 | * Get a Microsoft Graph API client.
83 | *
84 | * @param bool $system If true, get a system API ser token instead of the user's token.
85 | * @param int|null $userid The userid to get an API client for. If null, the current user will be used.
86 | * @return unified|bool A Microsoft Graph API client object.
87 | */
88 | protected function get_unified_apiclient($system = false, $userid = null) {
89 | if ($this->unifiedconfigured === true) {
90 | $token = $this->get_unified_token($system, $userid);
91 | if (!empty($token)) {
92 | return new unified($token, $this->httpclient);
93 | }
94 | }
95 | return false;
96 | }
97 |
98 | /**
99 | * Given a path, and perhaps a search, get a list of files.
100 | *
101 | * See details on {@link http://docs.moodle.org/dev/Repository_plugins}
102 | *
103 | * @param string $path this parameter can a folder name, or a identification of folder
104 | * @param string $page the page number of file list
105 | * @return array the list of files, including meta infomation, containing the following keys
106 | * manage, url to manage url
107 | * client_id
108 | * login, login form
109 | * repo_id, active repository id
110 | * login_btn_action, the login button action
111 | * login_btn_label, the login button label
112 | * total, number of results
113 | * perpage, items per page
114 | * page
115 | * pages, total pages
116 | * issearchresult, is it a search result?
117 | * list, file list
118 | * path, current path and parent path
119 | */
120 | public function get_listing($path = '', $page = '') {
121 | global $OUTPUT, $SESSION, $USER;
122 |
123 | if (utils::is_connected() !== true) {
124 | throw new moodle_exception('errorauthoidcnotconfig', 'repository_office365');
125 | }
126 |
127 | $clientid = optional_param('client_id', '', PARAM_TEXT);
128 | if (!empty($clientid)) {
129 | $SESSION->repository_office365['curpath'][$clientid] = $path;
130 | }
131 |
132 | $list = [];
133 | $breadcrumb = [['name' => $this->name, 'path' => '/']];
134 |
135 | $unifiedactive = false;
136 | $trendingactive = false;
137 | $trendingdisabled = get_config('office365', 'trendinggroup');
138 | if ($this->unifiedconfigured === true) {
139 | $unifiedtoken = $this->get_unified_token();
140 | if (!empty($unifiedtoken)) {
141 | $unifiedactive = true;
142 | $trendingactive = (empty($trendingdisabled)) ? true : false;
143 | }
144 | }
145 |
146 | $courses = enrol_get_users_courses($USER->id, true);
147 | $showgroups = false;
148 | $coursegroupdisabled = get_config('office365', 'coursegroup');
149 | if (unified::is_configured() === true && empty($coursegroupdisabled)) {
150 | foreach ($courses as $course) {
151 | if (\local_o365\feature\coursesync\utils::is_course_sync_enabled($course->id)) {
152 | $showgroups = true;
153 | break;
154 | }
155 | }
156 | }
157 |
158 | if (strpos($path, '/my/') === 0) {
159 | if ($unifiedactive === true) {
160 | // Path is in my files.
161 | [$list, $breadcrumb] = $this->get_listing_my_unified(substr($path, 3));
162 | }
163 | } else if (strpos($path, '/groups/') === 0) {
164 | if ($showgroups === true) {
165 | // Path is in group files.
166 | [$list, $breadcrumb] = $this->get_listing_groups(substr($path, 7));
167 | }
168 | } else if (strpos($path, '/trending/') === 0) {
169 | if ($trendingactive === true) {
170 | // Path is in trending files.
171 | [$list, $breadcrumb] = $this->get_listing_trending_unified(substr($path, 9));
172 | }
173 | } else {
174 | if ($unifiedactive === true) {
175 | $list[] = [
176 | 'title' => get_string('myfiles', 'repository_office365'),
177 | 'path' => '/my/',
178 | 'thumbnail' => $OUTPUT->pix_url('onedrive', 'repository_office365')->out(false),
179 | 'children' => [],
180 | ];
181 | }
182 | if ($showgroups === true) {
183 | $list[] = [
184 | 'title' => get_string('groups', 'repository_office365'),
185 | 'path' => '/groups/',
186 | 'thumbnail' => $OUTPUT->pix_url('coursegroups', 'repository_office365')->out(false),
187 | 'children' => [],
188 | ];
189 | }
190 | if ($trendingactive === true) {
191 | $list[] = [
192 | 'title' => get_string('trendingaround', 'repository_office365'),
193 | 'path' => '/trending/',
194 | 'thumbnail' => $OUTPUT->pix_url('delve', 'repository_office365')->out(false),
195 | 'children' => [],
196 | ];
197 | }
198 | }
199 | if ($this->path_is_upload($path) === true) {
200 | return [
201 | 'dynload' => true,
202 | 'nologin' => true,
203 | 'nosearch' => true,
204 | 'path' => $breadcrumb,
205 | 'upload' => [
206 | 'label' => get_string('file', 'repository_office365'),
207 | ],
208 | ];
209 | }
210 |
211 | return [
212 | 'dynload' => true,
213 | 'nologin' => true,
214 | 'nosearch' => true,
215 | 'list' => $list,
216 | 'path' => $breadcrumb,
217 | ];
218 | }
219 |
220 | /**
221 | * Determine whether a given path is an upload path.
222 | *
223 | * @param string $path A path to check.
224 | * @return bool Whether the path is an upload path.
225 | */
226 | protected function path_is_upload($path) {
227 | return (substr($path, -strlen('/upload/')) === '/upload/') ? true : false;
228 | }
229 |
230 | /**
231 | * Process uploaded file.
232 | *
233 | * @param string $saveasfilename
234 | * @param int $maxbytes
235 | * @return array Array of uploaded file information.
236 | * @throws moodle_exception
237 | */
238 | public function upload($saveasfilename, $maxbytes) {
239 | global $CFG, $USER, $SESSION, $DB;
240 |
241 | $savepath = optional_param('savepath', '/', PARAM_PATH);
242 | $itemid = optional_param('itemid', 0, PARAM_INT);
243 | $license = optional_param('license', $CFG->sitedefaultlicense, PARAM_TEXT);
244 | $author = optional_param('author', '', PARAM_TEXT);
245 | $clientid = optional_param('client_id', '', PARAM_TEXT);
246 |
247 | $filepath = '/';
248 | if (!empty($SESSION->repository_office365)) {
249 | if (isset($SESSION->repository_office365['curpath']) && isset($SESSION->repository_office365['curpath'][$clientid])) {
250 | $filepath = $SESSION->repository_office365['curpath'][$clientid];
251 | if (strpos($filepath, '/my/') === 0) {
252 | $clienttype = 'onedrive';
253 | $filepath = substr($filepath, 3);
254 | } else if (strpos($filepath, '/groups/') === 0) {
255 | $clienttype = 'onedrivegroup';
256 | $filepath = substr($filepath, 7);
257 | } else {
258 | $errmsg = get_string('errorbadclienttype', 'repository_office365');
259 | $debugdata = [
260 | 'filepath' => $filepath,
261 | ];
262 | utils::debug($errmsg, __METHOD__, $debugdata);
263 | throw new moodle_exception('errorbadclienttype', 'repository_office365');
264 | }
265 | }
266 | }
267 | if ($this->path_is_upload($filepath) === true) {
268 | $filepath = substr($filepath, 0, -strlen('/upload/'));
269 | }
270 | $filename = (!empty($saveasfilename)) ? $saveasfilename : $_FILES['repo_upload_file']['name'];
271 | $filename = clean_param($filename, PARAM_FILE);
272 | $content = file_get_contents($_FILES['repo_upload_file']['tmp_name']);
273 |
274 | if ($clienttype === 'onedrive') {
275 | if ($this->unifiedconfigured === true) {
276 | $apiclient = $this->get_unified_apiclient();
277 | $parentid = (!empty($filepath)) ? substr($filepath, 1) : '';
278 | $o365userid = utils::get_o365_userid($USER->id);
279 | $result = $apiclient->create_file($parentid, $filename, $content, 'application/octet-stream', $o365userid);
280 | }
281 | $source = $this->pack_reference(['id' => $result['id'], 'source' => 'onedrive']);
282 | } else if ($clienttype === 'onedrivegroup') {
283 | if ($this->unifiedconfigured === true) {
284 | $apiclient = $this->get_unified_apiclient();
285 | $parentid = (!empty($filepath)) ? substr($filepath, 1) : '';
286 | $pathtrimmed = trim($parentid, '/');
287 | $pathparts = explode('/', $pathtrimmed);
288 | $coursesbyid = enrol_get_users_courses($USER->id, true);
289 | if (!is_numeric($pathparts[0]) || !isset($coursesbyid[$pathparts[0]])
290 | || \local_o365\feature\coursesync\utils::is_course_sync_enabled($pathparts[0]) !== true) {
291 | utils::debug(get_string('errorbadpath', 'repository_office365'), __METHOD__, ['path' => $filepath]);
292 | throw new moodle_exception('errorbadpath', 'repository_office365');
293 | }
294 | $courseid = (int)$pathparts[0];
295 | if (!is_numeric($pathparts[1]) && $pathparts[1] !== 'coursegroup') {
296 | utils::debug(get_string('errorbadpath', 'repository_office365'), __METHOD__, ['path' => $filepath]);
297 | throw new moodle_exception('errorbadpath', 'repository_office365');
298 | }
299 | if ($pathparts[1] === 'coursegroup') {
300 | $filters = ['type' => 'group', 'subtype' => 'course', 'moodleid' => $courseid];
301 | $group = $DB->get_record('local_o365_objects', $filters);
302 | } else {
303 | $groupid = (int)$pathparts[1];
304 | $group = $DB->get_record('groups', ['id' => $groupid]);
305 | $filters = ['type' => 'group', 'subtype' => 'usergroup', 'moodleid' => $groupid];
306 | $group = $DB->get_record('local_o365_objects', $filters);
307 | }
308 | try {
309 | $result = $apiclient->create_group_file($group->objectid, $filename, $content);
310 | $source = $this->pack_reference(['id' => $result['id'], 'source' => $clienttype,
311 | 'groupid' => $group->objectid]);
312 | } catch (moodle_exception $e) {
313 | $errmsg = 'Exception when uploading share point files for group';
314 | $debugdata = [
315 | 'fullpath' => $filepath,
316 | 'message' => $e->getMessage(),
317 | 'groupid' => $group->objectid,
318 | ];
319 | utils::debug($errmsg, __METHOD__, $debugdata);
320 | $source = $this->pack_reference([]);
321 | }
322 | } else {
323 | utils::debug('Tried to Upload a onedrive group file while the graph api is disabled.', __METHOD__);
324 | throw new moodle_exception('errorwhileupload', 'repository_office365');
325 | }
326 | } else {
327 | $errmsg = get_string('errorbadclienttype', 'repository_office365');
328 | $debugdata = [
329 | 'clienttype' => $clienttype,
330 | ];
331 | utils::debug($errmsg, __METHOD__, $debugdata);
332 | throw new moodle_exception('errorbadclienttype', 'repository_office365');
333 | }
334 |
335 | $downloadedfile = $this->get_file($source, $filename);
336 | $record = new stdClass();
337 | $record->filename = $filename;
338 | $record->filepath = $savepath;
339 | $record->component = 'user';
340 | $record->filearea = 'draft';
341 | $record->itemid = $itemid;
342 | $record->license = $license;
343 | $record->author = $author;
344 | $usercontext = context_user::instance($USER->id);
345 | $now = time();
346 | $record->contextid = $usercontext->id;
347 | $record->timecreated = $now;
348 | $record->timemodified = $now;
349 | $record->userid = $USER->id;
350 | $record->sortorder = 0;
351 | $record->source = $this->build_source_field($source);
352 | $info = repository::move_to_filepool($downloadedfile['path'], $record);
353 |
354 | return $info;
355 | }
356 |
357 | /**
358 | * Get listing for a group folder.
359 | *
360 | * @param string $path Folder path.
361 | * @return array List of $list array and $path array.
362 | */
363 | protected function get_listing_groups($path = '') {
364 | global $OUTPUT, $USER, $DB;
365 |
366 | $list = [];
367 | $breadcrumb = [
368 | ['name' => $this->name, 'path' => '/'],
369 | ['name' => get_string('groups', 'repository_office365'), 'path' => '/groups/'],
370 | ];
371 |
372 | $coursesbyid = enrol_get_users_courses($USER->id, true);
373 |
374 | if ($path === '/') {
375 | // Show available courses.
376 | $enabledcourses = \local_o365\feature\coursesync\utils::get_enabled_courses(true);
377 | foreach ($coursesbyid as $course) {
378 | if ($enabledcourses === true || in_array($course->id, $enabledcourses)) {
379 | $list[] = [
380 | 'title' => $course->shortname,
381 | 'path' => '/groups/'.$course->id,
382 | 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
383 | 'children' => [],
384 | ];
385 | }
386 | }
387 | } else {
388 | $pathtrimmed = trim($path, '/');
389 | $pathparts = explode('/', $pathtrimmed);
390 | if (!is_numeric($pathparts[0]) || !isset($coursesbyid[$pathparts[0]])
391 | || \local_o365\feature\coursesync\utils::is_course_sync_enabled($pathparts[0]) !== true) {
392 | utils::debug(get_string('errorbadpath', 'repository_office365'), __METHOD__, ['path' => $path]);
393 | throw new moodle_exception('errorbadpath', 'repository_office365');
394 | }
395 | $courseid = (int)$pathparts[0];
396 | $curpath = '/groups/'.$courseid;
397 | $breadcrumb[] = ['name' => $coursesbyid[$courseid]->shortname, 'path' => $curpath];
398 |
399 | $sql = 'SELECT g.*
400 | FROM {groups} g
401 | JOIN {groups_members} m ON m.groupid = g.id
402 | WHERE m.userid = ? AND g.courseid = ?';
403 | $coursegroups = $DB->get_records_sql($sql, [$USER->id, $courseid]);
404 |
405 | if (count($pathparts) === 1) {
406 | $list[] = [
407 | 'title' => get_string('defaultgroupsfolder', 'repository_office365'),
408 | 'path' => $curpath.'/coursegroup/',
409 | 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
410 | 'children' => [],
411 | ];
412 |
413 | foreach ($coursegroups as $group) {
414 | $list[] = [
415 | 'title' => $group->name,
416 | 'path' => $curpath.'/'.$group->id.'/',
417 | 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
418 | 'children' => [],
419 | ];
420 | }
421 | } else {
422 | // Validate the received group identifier.
423 | if (!is_numeric($pathparts[1]) && $pathparts[1] !== 'coursegroup') {
424 | utils::debug(get_string('errorbadpath', 'repository_office365'), __METHOD__, ['path' => $path]);
425 | throw new moodle_exception('errorbadpath', 'repository_office365');
426 | }
427 | $curpath .= '/'.$pathparts[1].'/';
428 | if ($pathparts[1] === 'coursegroup') {
429 | $breadcrumb[] = ['name' => get_string('defaultgroupsfolder', 'repository_office365'), 'path' => $curpath];
430 | $filters = ['type' => 'group', 'subtype' => 'course', 'moodleid' => $courseid];
431 | $group = $DB->get_record('local_o365_objects', $filters);
432 | } else {
433 | // Validate the user is a member of the group.
434 | if (!isset($coursegroups[$pathparts[1]])) {
435 | utils::debug(get_string('errorbadpath', 'repository_office365'), __METHOD__, ['path' => $path]);
436 | throw new moodle_exception('errorbadpath', 'repository_office365');
437 | }
438 | $groupid = (int)$pathparts[1];
439 | $group = $DB->get_record('groups', ['id' => $groupid]);
440 | $breadcrumb[] = ['name' => $group->name, 'path' => $curpath];
441 | $filters = ['type' => 'group', 'subtype' => 'usergroup', 'moodleid' => $groupid];
442 | $group = $DB->get_record('local_o365_objects', $filters);
443 | }
444 |
445 | $intragrouppath = $pathparts;
446 | unset($intragrouppath[0], $intragrouppath[1]);
447 | $curparent = trim(end($intragrouppath));
448 |
449 | if (!empty($group)) {
450 | if ($curparent === 'upload') {
451 | $breadcrumb[] = ['name' => get_string('upload', 'repository_office365'), 'path' => $curpath.'upload/'];
452 | } else {
453 | $unified = $this->get_unified_apiclient();
454 |
455 | if (!empty($curparent)) {
456 | $metadata = $unified->get_group_file_metadata($group->objectid, $curparent);
457 | if (!empty($metadata['parentReference']) && !empty($metadata['parentReference']['path'])) {
458 | $parentrefpath = substr($metadata['parentReference']['path'],
459 | (strpos($metadata['parentReference']['path'], ':') + 1));
460 | $cache = cache::make('repository_office365', 'unifiedgroupfolderids');
461 | $cache->set($parentrefpath.'/'.$metadata['name'], $metadata['id']);
462 | if (!empty($parentrefpath)) {
463 | $parentrefpath = explode('/', trim($parentrefpath, '/'));
464 | $currentfullpath = '';
465 | foreach ($parentrefpath as $folder) {
466 | $currentfullpath .= '/'.$folder;
467 | $folderid = $cache->get($currentfullpath);
468 | $breadcrumb[] = ['name' => $folder, 'path' => $curpath.$folderid];
469 | }
470 | }
471 | }
472 | $breadcrumb[] = ['name' => $metadata['name'], 'path' => $curpath.$metadata['id']];
473 | }
474 | try {
475 | $filesresults = $unified->get_group_files($group->objectid, $curparent);
476 | $contents = $filesresults['value'];
477 | while (!empty($filesresults['@odata.nextLink'])) {
478 | $nextlink = parse_url($filesresults['@odata.nextLink']);
479 | $filesresults = [];
480 | if (isset($nextlink['query'])) {
481 | $query = [];
482 | parse_str($nextlink['query'], $query);
483 | if (isset($query['$skiptoken'])) {
484 | $filesresults = $unified->get_group_files($group->objectid, $curparent,
485 | $query['$skiptoken']);
486 | $contents = array_merge($contents, $filesresults['value']);
487 | }
488 | }
489 | }
490 |
491 | $list = $this->contents_api_response_to_list($contents, $path, 'unifiedgroup', $group->objectid, true);
492 | } catch (moodle_exception $e) {
493 | $errmsg = 'Exception when retrieving share point files for group';
494 | $debugdata = [
495 | 'fullpath' => $path,
496 | 'message' => $e->getMessage(),
497 | 'groupid' => $group->objectid,
498 | ];
499 | utils::debug($errmsg, __METHOD__, $debugdata);
500 | }
501 | }
502 | } else {
503 | utils::debug('Could not file group object record', __METHOD__, ['path' => $path]);
504 | }
505 | }
506 | }
507 |
508 | return [$list, $breadcrumb];
509 | }
510 |
511 | /**
512 | * Get listing for a personal onedrive folder using the Microsoft Graph API.
513 | *
514 | * @param string $path Folder path.
515 | * @return array List of $list array and $path array.
516 | */
517 | protected function get_listing_my_unified($path = '') {
518 | global $USER;
519 |
520 | $path = (empty($path)) ? '/' : $path;
521 |
522 | $list = [];
523 |
524 | $unified = $this->get_unified_apiclient();
525 | $realpath = $path;
526 |
527 | // Generate path.
528 | $strmyfiles = get_string('myfiles', 'repository_office365');
529 | $breadcrumb = [['name' => $this->name, 'path' => '/'], ['name' => $strmyfiles, 'path' => '/my/']];
530 |
531 | if ($this->path_is_upload($path) === true) {
532 | $realpath = substr($path, 0, -strlen('/upload/'));
533 | } else {
534 | try {
535 | $o365userid = utils::get_o365_userid($USER->id);
536 |
537 | $filesresults = $unified->get_user_files($realpath, $o365userid);
538 | $contents = $filesresults['value'];
539 | while (!empty($filesresults['@odata.nextLink'])) {
540 | $nextlink = parse_url($filesresults['@odata.nextLink']);
541 | $filesresults = [];
542 | if (isset($nextlink['query'])) {
543 | $query = [];
544 | parse_str($nextlink['query'], $query);
545 | if (isset($query['$skiptoken'])) {
546 | $filesresults = $unified->get_user_files($realpath, $o365userid, $query['$skiptoken']);
547 | $contents = array_merge($contents, $filesresults['value']);
548 | }
549 | }
550 | }
551 |
552 | $list = $this->contents_api_response_to_list($contents, $realpath, 'unified');
553 | } catch (moodle_exception $e) {
554 | $errmsg = 'Exception when retrieving personal onedrive files for folder';
555 | $debugdata = [
556 | 'fullpath' => $path,
557 | 'message' => $e->getMessage(),
558 | ];
559 | utils::debug($errmsg, __METHOD__, $debugdata);
560 | return [[], $breadcrumb];
561 | }
562 | }
563 |
564 | if ($realpath !== '/') {
565 | $o365userid = utils::get_o365_userid($USER->id);
566 | $metadata = $unified->get_file_metadata($realpath, $o365userid);
567 | if (!empty($metadata['parentReference']) && !empty($metadata['parentReference']['path'])) {
568 | $parentrefpath = substr($metadata['parentReference']['path']
569 | , (strpos($metadata['parentReference']['path'], ':') + 1));
570 | $cache = cache::make('repository_office365', 'unifiedfolderids');
571 | $result = $cache->set($parentrefpath.'/'.$metadata['name'], $metadata['id']);
572 | if (!empty($parentrefpath)) {
573 | $parentrefpath = explode('/', trim($parentrefpath, '/'));
574 | $currentfullpath = '';
575 | foreach ($parentrefpath as $folder) {
576 | $currentfullpath .= '/'.$folder;
577 | $folderid = $cache->get($currentfullpath);
578 | $breadcrumb[] = ['name' => $folder, 'path' => '/my/'.$folderid];
579 | }
580 | }
581 | }
582 | $breadcrumb[] = ['name' => $metadata['name'], 'path' => '/my/'.$metadata['id']];
583 | }
584 |
585 | if ($this->path_is_upload($path) === true) {
586 | $breadcrumb[] = ['name' => get_string('upload', 'repository_office365'),
587 | 'path' => '/my/' . $metadata['id'] . '/upload/'];
588 | }
589 |
590 | return [$list, $breadcrumb];
591 | }
592 |
593 | /**
594 | * Get listing for a trending files folder using the unified api.
595 | *
596 | * @param string $path Folder path.
597 | * @return array List of $list array and $path array.
598 | */
599 | protected function get_listing_trending_unified($path = '') {
600 | global $USER;
601 |
602 | $path = (empty($path)) ? '/' : $path;
603 | $unified = $this->get_unified_apiclient();
604 | $realpath = $path;
605 | try {
606 | $o365upn = utils::get_o365_upn($USER->id);
607 | $filesresults = $unified->get_trending_files($o365upn);
608 | $contents = $filesresults['value'];
609 | while (!empty($filesresults['@odata.nextLink'])) {
610 | $nextlink = parse_url($filesresults['@odata.nextLink']);
611 | $filesresults = [];
612 | if (isset($nextlink['query'])) {
613 | $query = [];
614 | parse_str($nextlink['query'], $query);
615 | if (isset($query['$skiptoken'])) {
616 | $filesresults = $unified->get_trending_files($o365upn, $query['$skiptoken']);
617 | $contents = array_merge($contents, $filesresults['value']);
618 | }
619 | }
620 | }
621 |
622 | $list = $this->contents_api_response_to_list($contents, $realpath, 'trendingaround', null, false);
623 | } catch (moodle_exception $e) {
624 | $errmsg = 'Exception when retrieving personal trending files';
625 | $debugdata = [
626 | 'fullpath' => $path,
627 | 'message' => $e->getMessage(),
628 | ];
629 | utils::debug($errmsg, __METHOD__, $debugdata);
630 | $list = [];
631 | }
632 |
633 | // Generate path.
634 | $strtrendingfiles = get_string('trendingaround', 'repository_office365');
635 | $breadcrumb = [['name' => $this->name, 'path' => '/'], ['name' => $strtrendingfiles, 'path' => '/trending/']];
636 | return [$list, $breadcrumb];
637 | }
638 |
639 | /**
640 | * Transform a onedrive API response for a folder into a list parameter that the respository class can understand.
641 | *
642 | * @param string $response The response from the API.
643 | * @param string $path The list path.
644 | * @param string $clienttype The type of client that the response is from. onedrive/unified
645 | * @param string $parentinfo Client type-specific parent information.
646 | * If using the unifiedgroup clienttype, this is the parent group ID.
647 | * @param bool $addupload Whether to add the "Upload" file item.
648 | * @return array A $list array to be used by the respository class in get_listing.
649 | */
650 | protected function contents_api_response_to_list($response, $path, $clienttype, $parentinfo = null, $addupload = true) {
651 | global $OUTPUT;
652 | $list = [];
653 | if ($clienttype === 'onedrive') {
654 | $pathprefix = '/my'.$path;
655 | $uploadpathprefix = $pathprefix;
656 | } else if ($clienttype === 'unified') {
657 | $pathprefix = '/my';
658 | $uploadpathprefix = $pathprefix.$path;
659 | } else if ($clienttype === 'unifiedgroup') {
660 | $pathprefix = '/groups'.$path;
661 | $uploadpathprefix = $pathprefix;
662 | } else if ($clienttype === 'trendingaround') {
663 | $pathprefix = '/my';
664 | }
665 |
666 | if ($addupload === true) {
667 | $list[] = [
668 | 'title' => get_string('upload', 'repository_office365'),
669 | 'path' => $uploadpathprefix.'/upload/',
670 | 'thumbnail' => $OUTPUT->pix_url('a/add_file')->out(false),
671 | 'children' => [],
672 | ];
673 | }
674 |
675 | if (isset($response)) {
676 | foreach ($response as $content) {
677 | if ($clienttype === 'unified' || $clienttype === 'unifiedgroup') {
678 | $itempath = $pathprefix . '/' . $content['id'];
679 | if (isset($content['folder'])) {
680 | $list[] = [
681 | 'title' => $content['name'],
682 | 'path' => $itempath,
683 | 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
684 | 'date' => strtotime($content['createdDateTime']),
685 | 'datemodified' => strtotime($content['lastModifiedDateTime']),
686 | 'datecreated' => strtotime($content['createdDateTime']),
687 | 'children' => [],
688 | ];
689 | } else if (isset($content['file'])) {
690 | $url = $content['webUrl'] . '?web=1';
691 | if ($clienttype === 'unified') {
692 | $source = [
693 | 'id' => $content['id'],
694 | 'source' => 'onedrive',
695 | ];
696 | } else if ($clienttype === 'unifiedgroup') {
697 | $source = [
698 | 'id' => $content['id'],
699 | 'source' => 'onedrivegroup',
700 | 'groupid' => $parentinfo,
701 | ];
702 | }
703 |
704 | $author = '';
705 | if (!empty($content['createdBy']['user']['displayName'])) {
706 | $author = $content['createdBy']['user']['displayName'];
707 | $author = explode(',', $author);
708 | $author = $author[0];
709 | }
710 |
711 | $list[] = [
712 | 'title' => $content['name'],
713 | 'date' => strtotime($content['createdDateTime']),
714 | 'datemodified' => strtotime($content['lastModifiedDateTime']),
715 | 'datecreated' => strtotime($content['createdDateTime']),
716 | 'size' => $content['size'],
717 | 'url' => $url,
718 | 'thumbnail' => $OUTPUT->pix_url(file_extension_icon($content['name'], 90))->out(false),
719 | 'author' => $author,
720 | 'source' => $this->pack_reference($source),
721 | ];
722 | }
723 | } else if ($clienttype === 'trendingaround') {
724 | if (isset($content['folder'])) {
725 | $list[] = [
726 | 'title' => $content['name'],
727 | 'path' => $pathprefix . '/' . $content['name'],
728 | 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
729 | 'date' => strtotime($content['DateTimeCreated']),
730 | 'datemodified' => strtotime($content['DateTimeLastModified']),
731 | 'datecreated' => strtotime($content['DateTimeCreated']),
732 | 'children' => [],
733 | ];
734 | } else {
735 | $url = $content['webUrl'] . '?web=1';
736 | $source = [
737 | 'id' => $content['@odata.id'],
738 | 'source' => 'trendingaround',
739 | ];
740 |
741 | $list[] = [
742 | 'title' => $content['name'],
743 | 'date' => strtotime($content['DateTimeCreated']),
744 | 'datemodified' => strtotime($content['DateTimeLastModified']),
745 | 'datecreated' => strtotime($content['DateTimeCreated']),
746 | 'url' => $url,
747 | 'thumbnail' => $OUTPUT->pix_url(file_extension_icon($content['name'], 90))->out(false),
748 | 'source' => $this->pack_reference($source),
749 | ];
750 | }
751 | } else {
752 | $itempath = $pathprefix . '/' . $content['name'];
753 | if ($content['type'] === 'Folder') {
754 | $list[] = [
755 | 'title' => $content['name'],
756 | 'path' => $itempath,
757 | 'thumbnail' => $OUTPUT->pix_url(file_folder_icon(90))->out(false),
758 | 'date' => strtotime($content['dateTimeCreated']),
759 | 'datemodified' => strtotime($content['dateTimeLastModified']),
760 | 'datecreated' => strtotime($content['dateTimeCreated']),
761 | 'children' => [],
762 | ];
763 | } else if ($content['type'] === 'File') {
764 | $url = $content['webUrl'] . '?web=1';
765 | $source = [
766 | 'id' => $content['id'],
767 | 'source' => 'onedrive',
768 | ];
769 |
770 | $author = '';
771 | if (!empty($content['createdBy']['user']['displayName'])) {
772 | $author = $content['createdBy']['user']['displayName'];
773 | $author = explode(',', $author);
774 | $author = $author[0];
775 | }
776 |
777 | $list[] = [
778 | 'title' => $content['name'],
779 | 'date' => strtotime($content['dateTimeCreated']),
780 | 'datemodified' => strtotime($content['dateTimeLastModified']),
781 | 'datecreated' => strtotime($content['dateTimeCreated']),
782 | 'size' => $content['size'],
783 | 'url' => $url,
784 | 'thumbnail' => $OUTPUT->pix_url(file_extension_icon($content['name'], 90))->out(false),
785 | 'author' => $author,
786 | 'source' => $this->pack_reference($source),
787 | ];
788 | }
789 | }
790 | }
791 | }
792 |
793 | return $list;
794 | }
795 |
796 | /**
797 | * Tells how the file can be picked from this repository
798 | *
799 | * Maximum value is FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE
800 | *
801 | * @return int
802 | */
803 | public function supported_returntypes() {
804 | return FILE_INTERNAL;
805 | }
806 |
807 | /**
808 | * Downloads a file from external repository and saves it in temp dir
809 | *
810 | * @param string $reference The file reference.
811 | * @param string $filename filename (without path) to save the downloaded file in the temporary directory, if omitted
812 | * or file already exists the new filename will be generated
813 | * @return array with elements:
814 | * path: internal location of the file
815 | * url: URL to the source (from parameters)
816 | */
817 | public function get_file($reference, $filename = '') {
818 | global $USER;
819 |
820 | $reference = $this->unpack_reference($reference);
821 |
822 | if ($reference['source'] === 'onedrive') {
823 | if ($this->unifiedconfigured === true) {
824 | $sourceclient = $this->get_unified_apiclient();
825 | }
826 | if (empty($sourceclient)) {
827 | utils::debug('Could not construct onedrive api.', __METHOD__);
828 | throw new moodle_exception('errorwhiledownload', 'repository_office365');
829 | }
830 | $o365userid = utils::get_o365_userid($USER->id);
831 | $file = $sourceclient->get_file_by_id($reference['id'], $o365userid);
832 | } else if ($reference['source'] === 'onedrivegroup') {
833 | if ($this->unifiedconfigured === true) {
834 | $sourceclient = $this->get_unified_apiclient();
835 | } else {
836 | utils::debug('Tried to access a onedrive group file while the graph api is disabled.', __METHOD__);
837 | throw new moodle_exception('errorwhiledownload', 'repository_office365');
838 | }
839 | $file = $sourceclient->get_group_file_by_id($reference['groupid'], $reference['id']);
840 | } else if ($reference['source'] === 'trendingaround') {
841 | if ($this->unifiedconfigured === true) {
842 | $sourceclient = $this->get_unified_apiclient();
843 | }
844 | if (empty($sourceclient)) {
845 | utils::debug('Could not construct unified api.', __METHOD__);
846 | throw new moodle_exception('errorwhiledownload', 'repository_office365');
847 | }
848 | $file = $sourceclient->get_file_by_url($reference['url']);
849 | }
850 |
851 | if (!empty($file)) {
852 | $path = $this->prepare_file($filename);
853 | if (!empty($path)) {
854 | $result = file_put_contents($path, $file);
855 | }
856 | }
857 | if (empty($result)) {
858 | $errmsg = get_string('errorwhiledownload', 'repository_office365');
859 | $debugdata = [
860 | 'reference' => $reference,
861 | 'filename' => $filename,
862 | ];
863 | utils::debug($errmsg, __METHOD__, $debugdata);
864 | throw new moodle_exception('errorwhiledownload', 'repository_office365');
865 | }
866 | return ['path' => $path, 'url' => $reference];
867 | }
868 |
869 | /**
870 | * Pack file reference information into a string.
871 | *
872 | * @param array $reference The information to pack.
873 | * @return string The packed information.
874 | */
875 | protected function pack_reference($reference) {
876 | return base64_encode(serialize($reference));
877 | }
878 |
879 | /**
880 | * Unpack file reference information from a string.
881 | *
882 | * @param string $reference The information to unpack.
883 | * @return array The unpacked information.
884 | */
885 | protected function unpack_reference($reference) {
886 | return unserialize(base64_decode($reference));
887 | }
888 |
889 | /**
890 | * Prepare file reference information
891 | *
892 | * @param string $source source of the file, returned by repository as 'source' and received back from user (not cleaned)
893 | * @return string file reference, ready to be stored
894 | */
895 | public function get_file_reference($source) {
896 | global $USER;
897 |
898 | $sourceunpacked = $this->unpack_reference($source);
899 | if (isset($sourceunpacked['source']) && isset($sourceunpacked['id'])) {
900 | $fileid = $sourceunpacked['id'];
901 | $filesource = $sourceunpacked['source'];
902 |
903 | $reference = [
904 | 'source' => $filesource,
905 | 'id' => $fileid,
906 | 'url' => '',
907 | ];
908 |
909 | if (isset($sourceunpacked['url'])) {
910 | $reference['url'] = $sourceunpacked['url'];
911 | }
912 | if (isset($sourceunpacked['downloadurl'])) {
913 | $reference['downloadurl'] = $sourceunpacked['downloadurl'];
914 | }
915 |
916 | try {
917 | if ($filesource === 'onedrive') {
918 | if ($this->unifiedconfigured === true) {
919 | $sourceclient = $this->get_unified_apiclient();
920 | $o365userid = utils::get_o365_userid($USER->id);
921 | $reference['url'] = $sourceclient->get_sharing_link($fileid, $o365userid);
922 | }
923 | } else if ($filesource === 'onedrivegroup') {
924 | if ($this->unifiedconfigured !== true) {
925 | utils::debug('Tried to access a onedrive group file while the graph api is disabled.', __METHOD__);
926 | throw new moodle_exception('errorwhiledownload', 'repository_office365');
927 | }
928 | $sourceclient = $this->get_unified_apiclient();
929 | $reference['groupid'] = $sourceunpacked['groupid'];
930 | $reference['url'] = $sourceclient->get_group_file_sharing_link($sourceunpacked['groupid'], $fileid);
931 | } else if ($filesource === 'trendingaround') {
932 | if ($this->unifiedconfigured !== true) {
933 | utils::debug('Tried to access a trending around me file while the graph api is disabled.', __METHOD__);
934 | throw new moodle_exception('errorwhiledownload', 'repository_office365');
935 | }
936 | $sourceclient = $this->get_unified_apiclient();
937 | $filedata = $sourceclient->get_file_data($fileid);
938 | if (isset($filedata['@microsoft.graph.downloadUrl'])) {
939 | $reference['url'] = $filedata['@microsoft.graph.downloadUrl'];
940 | }
941 | }
942 |
943 | } catch (moodle_exception $e) {
944 | $errmsg = 'There was a problem making the API call.';
945 | $debugdata = [
946 | 'source' => $filesource,
947 | 'id' => $fileid,
948 | 'message' => $e->getMessage(),
949 | 'e' => $e,
950 | ];
951 | utils::debug($errmsg, __METHOD__, $debugdata);
952 | }
953 |
954 | return $this->pack_reference($reference);
955 | } else {
956 | $errmsg = '';
957 | if (!isset($sourceunpacked['source'])) {
958 | $errmsg = 'Source is not set.';
959 | }
960 | if (isset($sourceunpacked['id'])) {
961 | $errmsg .= ' id is not set.';
962 | }
963 | $debugdata = ['sourceunpacked' => $sourceunpacked];
964 | utils::debug($errmsg, __METHOD__, $debugdata);
965 | }
966 | return $source;
967 | }
968 |
969 | /**
970 | * Return file URL, for most plugins, the parameter is the original
971 | * url, but some plugins use a file id, so we need this function to
972 | * convert file id to original url.
973 | *
974 | * @param string $url the url of file
975 | * @return string
976 | */
977 | public function get_link($url) {
978 | $reference = $this->unpack_reference($url);
979 | return $reference['url'];
980 | }
981 |
982 | /**
983 | * Determine whether a "send_file" request should be a redirect to the embed URL for a file.
984 | *
985 | * @param array $reference The file reference array.
986 | * @param bool $forcedownload The send_file "forcedownload" param.
987 | * @return bool True if we should do embedding, false otherwise.
988 | */
989 | public function do_embedding($reference, $forcedownload) {
990 | global $PAGE, $DB;
991 |
992 | if (empty($reference['source']) || !in_array($reference['source'], ['onedrive'])) {
993 | return false;
994 | }
995 |
996 | if (!empty($forcedownload)) {
997 | return false;
998 | }
999 |
1000 | $cm = $PAGE->cm;
1001 | if (!empty($cm)) {
1002 | $sql = 'SELECT cm.instance
1003 | FROM {course_modules} cm
1004 | JOIN {modules} m ON m.id = cm.module
1005 | WHERE cm.id = ? AND m.name = ?';
1006 | $rec = $DB->get_record_sql($sql, [$cm->id, 'resource']);
1007 | if (!empty($rec)) {
1008 | $resourcerec = $DB->get_record('resource', ['id' => $rec->instance]);
1009 | if (!empty($resourcerec)) {
1010 | if (defined('RESOURCELIB_DISPLAY_EMBED') && $resourcerec->display == RESOURCELIB_DISPLAY_EMBED) {
1011 | return true;
1012 | }
1013 | }
1014 | }
1015 | }
1016 | return false;
1017 | }
1018 |
1019 | /**
1020 | * Repository method to serve the referenced file
1021 | *
1022 | * @param stored_file $storedfile the file that contains the reference
1023 | * @param null $lifetime Number of seconds before the file should expire from caches (null means $CFG->filelifetime)
1024 | * @param int $filter 0 (default)=no filtering, 1=all files, 2=html files only
1025 | * @param bool $forcedownload If true (default false), forces download of file rather than view in browser/plugin
1026 | * @param array|null $options additional options affecting the file serving
1027 | */
1028 | public function send_file($storedfile, $lifetime = null , $filter = 0, $forcedownload = false, ?array $options = null) {
1029 | global $USER;
1030 |
1031 | $reference = $this->unpack_reference($storedfile->get_reference());
1032 |
1033 | $fileuserid = $storedfile->get_userid();
1034 |
1035 | if (!isset($reference['source'])) {
1036 | utils::debug('File reference is broken - no source parameter.', __METHOD__, $reference);
1037 | send_file_not_found();
1038 | die();
1039 | }
1040 |
1041 | $doembed = $this->do_embedding($reference, $forcedownload);
1042 |
1043 | switch ($reference['source']) {
1044 | case 'onedrive':
1045 | $sourceclient = $this->get_unified_apiclient(false, $fileuserid);
1046 | if (empty($sourceclient)) {
1047 | utils::debug('Could not construct api client for user', __METHOD__, $fileuserid);
1048 | send_file_not_found();
1049 | die();
1050 | }
1051 | if ($doembed === true) {
1052 | $o365userupn = utils::get_o365_upn($fileuserid);
1053 | $fileinfo = $sourceclient->get_file_metadata($reference['id'], $o365userupn);
1054 | if (isset($fileinfo['webUrl'])) {
1055 | $fileurl = $fileinfo['webUrl'];
1056 | } else {
1057 | $fileurl = (isset($reference['url'])) ? $reference['url'] : '';
1058 | }
1059 | } else {
1060 | $fileurl = (isset($reference['url'])) ? $reference['url'] : '';
1061 | }
1062 | break;
1063 |
1064 | case 'onedrivegroup':
1065 | $sourceclient = $this->get_unified_apiclient();
1066 | $fileurl = (isset($reference['url'])) ? $reference['url'] : '';
1067 | break;
1068 |
1069 | default:
1070 | utils::debug('File reference is broken - invalid source parameter.', __METHOD__, $reference);
1071 | send_file_not_found();
1072 | die();
1073 | }
1074 |
1075 | // Do embedding if relevant.
1076 | if ($doembed === true) {
1077 | if (utils::is_o365_connected($USER->id) !== true) {
1078 | // Embedding currently only supported for logged-in Microsoft 365 users.
1079 | echo get_string('erroro365required', 'repository_office365');
1080 | die();
1081 | }
1082 | if (!empty($sourceclient)) {
1083 | if (empty($fileurl)) {
1084 | $errstr = 'Embed was requested, but could not get file info to complete request.';
1085 | utils::debug($errstr, __METHOD__, ['reference' => $reference, 'fileinfo' => $fileinfo]);
1086 | } else {
1087 | try {
1088 | $embedurl = $sourceclient->get_embed_url($reference['id'], $fileurl);
1089 | $embedurl = (isset($embedurl['value'])) ? $embedurl['value'] : '';
1090 | } catch (moodle_exception $e) {
1091 | // Note: exceptions will already be logged in get_embed_url.
1092 | $embedurl = '';
1093 | }
1094 | if (!empty($embedurl)) {
1095 | redirect($embedurl);
1096 | } else if (!empty($fileurl)) {
1097 | redirect($fileurl);
1098 | } else {
1099 | $errstr = 'Embed was requested, but could not complete.';
1100 | utils::debug($errstr, __METHOD__, $reference);
1101 | }
1102 | }
1103 | } else {
1104 | utils::debug('Could not construct OneDrive client for system api user.', __METHOD__);
1105 | }
1106 | }
1107 |
1108 | redirect($fileurl);
1109 | }
1110 |
1111 | /**
1112 | * Validate Admin Settings Moodle form
1113 | *
1114 | * @param moodleform $mform Moodle form (passed by reference)
1115 | * @param array $data array of ("fieldname"=>value) of submitted data
1116 | * @param array $errors array of ("fieldname"=>errormessage) of errors
1117 | * @return array array of errors
1118 | */
1119 | public static function type_form_validation($mform, $data, $errors) {
1120 | global $CFG;
1121 | if (utils::is_connected() !== true) {
1122 | array_push($errors, get_string('notconfigured', 'repository_office365', $CFG->wwwroot));
1123 | }
1124 | return $errors;
1125 | }
1126 |
1127 | /**
1128 | * Setup repository form.
1129 | *
1130 | * @param moodleform $mform Moodle form (passed by reference)
1131 | * @param string $classname repository class name
1132 | */
1133 | public static function type_config_form($mform, $classname = 'repository') {
1134 | global $CFG;
1135 |
1136 | if (utils::is_connected() !== true) {
1137 | $mform->addElement('static', null, '', get_string('notconfigured', 'repository_office365', $CFG->wwwroot));
1138 | }
1139 | parent::type_config_form($mform);
1140 | $mform->addElement('checkbox', 'coursegroup', get_string('coursegroup', 'repository_office365'));
1141 | $mform->setType('coursegroup', PARAM_INT);
1142 | $mform->addElement('checkbox', 'onedrivegroup', get_string('onedrivegroup', 'repository_office365'));
1143 | $mform->setType('onedrivegroup', PARAM_INT);
1144 | $mform->addElement('checkbox', 'trendinggroup', get_string('trendinggroup', 'repository_office365'));
1145 | $mform->setType('trendinggroup', PARAM_INT);
1146 | }
1147 |
1148 | /**
1149 | * Option names of dropbox office365
1150 | *
1151 | * @return array
1152 | */
1153 | public static function get_type_option_names() {
1154 | return ['coursegroup', 'onedrivegroup', 'trendinggroup', 'pluginname'];
1155 | }
1156 | }
1157 |
--------------------------------------------------------------------------------
/pix/coursegroups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moodle-repository_office365/0c76ecd368b08ab51b72bed0fe26686cf635497e/pix/coursegroups.png
--------------------------------------------------------------------------------
/pix/delve.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moodle-repository_office365/0c76ecd368b08ab51b72bed0fe26686cf635497e/pix/delve.png
--------------------------------------------------------------------------------
/pix/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moodle-repository_office365/0c76ecd368b08ab51b72bed0fe26686cf635497e/pix/icon.png
--------------------------------------------------------------------------------
/pix/office365video.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moodle-repository_office365/0c76ecd368b08ab51b72bed0fe26686cf635497e/pix/office365video.png
--------------------------------------------------------------------------------
/pix/onedrive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moodle-repository_office365/0c76ecd368b08ab51b72bed0fe26686cf635497e/pix/onedrive.png
--------------------------------------------------------------------------------
/pix/sharepoint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moodle-repository_office365/0c76ecd368b08ab51b72bed0fe26686cf635497e/pix/sharepoint.png
--------------------------------------------------------------------------------
/pix/trendingaround.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/microsoft/moodle-repository_office365/0c76ecd368b08ab51b72bed0fe26686cf635497e/pix/trendingaround.png
--------------------------------------------------------------------------------
/version.php:
--------------------------------------------------------------------------------
1 | .
16 |
17 | /**
18 | * Office365 Repository
19 | * @package repository_office365
20 | * @author James McQuillan
21 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22 | * @copyright (C) 2014 onwards Microsoft, Inc. (http://microsoft.com/)
23 | */
24 |
25 | defined('MOODLE_INTERNAL') || die();
26 |
27 | $plugin->version = 2024100705;
28 | $plugin->requires = 2024100700;
29 | $plugin->release = '4.5.1';
30 | $plugin->component = 'repository_office365';
31 | $plugin->maturity = MATURITY_STABLE;
32 | $plugin->dependencies = [
33 | 'local_o365' => 2024100705,
34 | ];
35 |
--------------------------------------------------------------------------------