Skip to content

Commit ce7a174

Browse files
committed
Merge branch 'm36migration'
2 parents 322820f + ea36057 commit ce7a174

File tree

8 files changed

+425
-61
lines changed

8 files changed

+425
-61
lines changed

.travis.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,12 @@ env:
4444
- DB=pgsql MOODLE_BRANCH=MOODLE_33_STABLE
4545
- DB=pgsql MOODLE_BRANCH=MOODLE_34_STABLE
4646
- DB=pgsql MOODLE_BRANCH=MOODLE_35_STABLE
47+
#- DB=pgsql MOODLE_BRANCH=MOODLE_36_STABLE
4748
- DB=pgsql MOODLE_BRANCH=master
4849
- DB=mysqli MOODLE_BRANCH=MOODLE_33_STABLE
4950
- DB=mysqli MOODLE_BRANCH=MOODLE_34_STABLE
5051
- DB=mysqli MOODLE_BRANCH=MOODLE_35_STABLE
52+
#- DB=mysqli MOODLE_BRANCH=MOODLE_36_STABLE
5153
- DB=mysqli MOODLE_BRANCH=master
5254

5355
before_install:
@@ -63,7 +65,7 @@ jobs:
6365
# Prechecks against latest Moodle stable only.
6466
- stage: static
6567
php: 7.2
66-
env: DB=mysqli MOODLE_BRANCH=MOODLE_35_STABLE
68+
env: DB=mysqli MOODLE_BRANCH=master #MOODLE_36_STABLE
6769
install:
6870
- moodle-plugin-ci install --no-init
6971
script:
@@ -78,7 +80,7 @@ jobs:
7880
# Smaller build matrix for development builds
7981
- stage: develop
8082
php: 7.2
81-
env: DB=mysqli MOODLE_BRANCH=MOODLE_35_STABLE
83+
env: DB=mysqli MOODLE_BRANCH=master #MOODLE_36_STABLE
8284
install:
8385
- moodle-plugin-ci install
8486
script:

classes/migration.php

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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+
* Helper for migrating to repository_nextcloud.
19+
*
20+
* Don't worry, repository_nextcloud is based on the same code and will work perfectly fine with ownCloud
21+
* as well as with Nextcloud!
22+
*
23+
* @package repository_owncloud
24+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25+
* @copyright 2018 Jan Dageförde (Learnweb, University of Münster)
26+
*/
27+
28+
namespace repository_owncloud;
29+
30+
defined('MOODLE_INTERNAL') || die();
31+
require_once($CFG->dirroot . '/repository/lib.php');
32+
33+
/**
34+
* Helper for migrating to repository_nextcloud.
35+
*
36+
* @package repository_owncloud
37+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38+
* @copyright 2018 Jan Dageförde (Learnweb, University of Münster)
39+
*/
40+
class migration {
41+
/**
42+
* Migrate existing instances of repository_owncloud to the more recent repository_nextcloud.
43+
* (Note: If you are using ownCloud, the connection between Moodle and ownCloud will continue to work!)
44+
*
45+
* @return bool A status indicating success or failure
46+
*/
47+
public static function migrate_all_instances() {
48+
global $DB, $CFG;
49+
50+
// Sanity checks -- this method should really never be called for a non-admin. M3.6 and above only.
51+
require_capability('moodle/site:config', \context_system::instance());
52+
if ($CFG->branch < 36) {
53+
die('This functionality is only available in Moodle 3.6 and above.');
54+
}
55+
56+
$formertype = \repository::get_type_by_typename('owncloud');
57+
if (!$formertype) {
58+
// Nothing to do! Old plugin was not installed or inactive.
59+
return true;
60+
}
61+
62+
$owncloudinstances = \repository::get_instances(['type' => 'owncloud', 'onlyvisible' => false]);
63+
64+
if (empty($owncloudinstances)) {
65+
// Nothing to do! No instances were configured.
66+
return false;
67+
}
68+
69+
// Whether or not there is a repository_nextcloud type yet, let's be sure that now there is.
70+
$nextcloud = $DB->get_record('repository', ['type' => 'nextcloud'], 'id', IGNORE_MISSING);
71+
if ($nextcloud) {
72+
$nextcloudtypeid = $nextcloud->id;
73+
} else {
74+
$nextcloudtype = new \repository_type('nextcloud', array(), $formertype->get_visible());
75+
if (!($nextcloudtypeid = $nextcloudtype->create(true))) {
76+
// Needed to create the new type but couldn't.
77+
return false;
78+
}
79+
}
80+
81+
// Migrate each repository_owncloud instance.
82+
foreach ($owncloudinstances as $instance) {
83+
// Download file references that used the "alias/shortcut" link option (not supported anymore).
84+
if (!self::download_legacy_alias_references($instance->id)) {
85+
// Somehow failed; do not migrate this instance!
86+
// Purge cache in case previous instances were migrated successfully.
87+
\cache::make('core', 'repositories')->purge();
88+
89+
// Indicate failure.
90+
return false;
91+
}
92+
93+
// Other references are migrated automatically as they refer to instanceid only, which we will not change.
94+
// Instance configuration is migrated automatically as settings refer to instanceid only.
95+
96+
// Change type of repository instance to that of repository_nextcloud.
97+
$DB->set_field('repository_instances', 'typeid', $nextcloudtypeid, ['id' => $instance->id]);
98+
99+
}
100+
101+
// Reset repository cache to avoid deleting those instances that we just migrated.
102+
\cache::make('core', 'repositories')->purge();
103+
104+
// Delete and disable the ownCloud repo.
105+
$formertype->delete();
106+
\core_plugin_manager::reset_caches();
107+
108+
$sql = "SELECT count('x')
109+
FROM {repository_instances} i, {repository} r
110+
WHERE r.type=:plugin AND r.id=i.typeid";
111+
$params = array('plugin' => 'owncloud');
112+
return $DB->count_records_sql($sql, $params) === 0;
113+
}
114+
115+
/**
116+
* Download file references that used the "alias/shortcut" link option into local file storage.
117+
* This kind of reference is not supported anymore.
118+
*
119+
* @param int $instanceid Repository instance
120+
* @return bool true if everything succeeded, false if any download failed.
121+
*/
122+
private static function download_legacy_alias_references($instanceid) {
123+
$fs = get_file_storage();
124+
$files = $fs->get_external_files($instanceid);
125+
foreach ($files as $storedfile) {
126+
// Check whether this is an alias or an access controlled link first.
127+
$ref = json_decode($storedfile->get_reference());
128+
if (!is_object($ref)) {
129+
// Intermediate (draft) reference, do not alter.
130+
continue;
131+
}
132+
if ($ref->type === "FILE_CONTROLLED_LINK") {
133+
// ACL, do not alter.
134+
continue;
135+
}
136+
137+
// Import reference.
138+
try {
139+
$fs->import_external_file($storedfile);
140+
} catch (\moodle_exception $e) {
141+
debugging($e->getMessage(), DEBUG_NORMAL);
142+
return false;
143+
}
144+
}
145+
return true;
146+
}
147+
}

classes/privacy/provider.php

Lines changed: 8 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -25,71 +25,24 @@
2525

2626
defined('MOODLE_INTERNAL') || die();
2727

28-
use core_privacy\local\metadata\collection;
29-
use core_privacy\local\request\approved_contextlist;
30-
use core_privacy\local\request\contextlist;
31-
3228
/**
33-
* Provider Class to implement the Privacy API of Moodle35.
29+
* Provider Class to implement the Privacy API.
3430
*
3531
* @package repository_owncloud
3632
* @copyright 2018 Nina Herrmann (Learnweb, University of Münster)
3733
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
3834
*/
39-
class provider implements
40-
\core_privacy\local\metadata\provider,
41-
\core_privacy\local\request\plugin\provider {
42-
use \core_privacy\local\legacy_polyfill;
43-
44-
/**
45-
* Get the list of items.
46-
*
47-
* @param collection $collection The initialised collection to add items to.
48-
* @return collection A listing of user data stored through this system.
49-
*/
50-
public static function _get_metadata(collection $collection) {
51-
// The repository uses a user specific access token (called confirmation token), provided by the oauthlib, ...
52-
// Saved in the session to access files. However, the oauthlib Privacy API is outsourced to the oauth2 plugin.
53-
// For this reason the collections includes the oauth2 subplugin.
54-
$collection->add_subsystem_link(
55-
'auth_oauth2',
56-
[],
57-
'privacy:metadata:auth_oauth2'
58-
);
59-
return $collection;
60-
}
35+
class provider implements \core_privacy\local\metadata\null_provider {
6136

62-
/**
63-
* Get the list of contexts that contain user information for the specified user.
64-
*
65-
* @param int $userid The user to search.
66-
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
67-
*/
68-
public static function _get_contexts_for_userid($userid) {
69-
return new contextlist();
70-
}
71-
72-
/**
73-
* Export all user data for the specified user, in the specified contexts.
74-
*
75-
* @param approved_contextlist $contextlist The approved contexts to export information for.
76-
*/
77-
public static function _export_user_data(approved_contextlist $contextlist) {
78-
}
79-
80-
/**
81-
* Delete all data for all users in the specified context.
82-
*
83-
* @param \context $context The specific context to delete data for.
84-
*/
85-
public static function _delete_data_for_all_users_in_context(\context $context) {
86-
}
37+
use \core_privacy\local\legacy_polyfill;
8738

8839
/**
89-
* Delete all user data for the specified user, in the specified contexts.
40+
* Get the language string identifier with the component's language
41+
* file to explain why this plugin stores no data.
9042
*
91-
* @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
43+
* @return string
9244
*/
93-
public static function _delete_data_for_user(approved_contextlist $contextlist) {
45+
public static function _get_reason() {
46+
return 'privacy:metadata';
9447
}
9548
}

lang/en/repository_owncloud.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
$string['foldername_help'] = 'To assure users find files shared with them, shares are saved into a specific folder. <br>
4343
This setting determines the name of the folder. It is recommended to chose a name associated with your Moodle instance.';
4444
$string['oauth2serviceslink'] = '<a href="{$a}" title="Link to OAuth 2 services configuration">OAuth 2 services configuration</a>';
45-
$string['privacy:metadata:auth_oauth2'] = 'The repository uses a user specific access token (called confirmation token), provided by the oauthlib, saved in the session to access files.';
45+
$string['privacy:metadata'] = 'The ownCloud repository plugin neither stores any personal data nor transmits user data to the remote system.';
4646
$string['internal'] = 'Internal (files stored in Moodle)';
4747
$string['external'] = 'External (only links stored in Moodle)';
4848
$string['both'] = 'Internal and external';
@@ -59,3 +59,11 @@
5959
$string['cannotconnect'] = 'The user could not be authenticated, please log in and then upload the file.';
6060
$string['filenotaccessed'] = 'The requested file could not be accessed. Please check whether you have chosen a valid file and you are authenticated with the right account.';
6161
$string['couldnotmove'] = 'The requested file could not be moved in the {$a} folder.';
62+
63+
// Migrations.
64+
$string['migrationexplanation'] = 'Starting with Moodle 3.6, the ownCloud repository is integrated into Moodle and is now called Nextcloud repository. It caters for both ownCloud and Nextcloud. As a consequence, this plugin is not maintained anymore. Please migrate files and configuration to the newer repository plugin using the following option.';
65+
$string['migrationlink'] = 'Start migration';
66+
$string['migration'] = 'Migrate repository';
67+
$string['owncloudfilesmigrated'] = 'All configuration and files have been migrated to the Nextcloud repository. The ownCloud repository plugin can be deleted safely.';
68+
$string['owncloudfilesnotmigrated'] = 'An error occurred when trying to migrate all configuration and files to the Nextcloud repository.';
69+
$string['confirmmigration'] = 'Are you sure you want to migrate all configuration and files to the Nextcloud repository? The Nextcloud repository must be installed for files to continue working as before. Warning: This action cannot be undone!';

lib.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,13 @@ private function initiate_webdavclient() {
219219
* @return array|bool returns either the moodle path to the file or false.
220220
*/
221221
public function get_file($reference, $title = '') {
222-
// Normal file.
222+
// Special handling if we are downloading a former repository instance's contents.
223+
$specialref = json_decode($reference);
224+
if (is_object($specialref)) {
225+
return parent::get_file($specialref->link);
226+
}
227+
228+
// Was not JSON-encoded, so this is a normal file.
223229
$reference = urldecode($reference);
224230

225231
// Prepare a file with an arbitrary name - cannot be $title because of special chars (cf. MDL-57002).
@@ -646,6 +652,24 @@ public static function create($type, $userid, $context, $params, $readonly=0) {
646652
return parent::create($type, $userid, $context, $params, $readonly);
647653
}
648654

655+
/**
656+
* Repository settings form - used to provide users of Moodle 3.6 and above with an option to migrate to the core plugin.
657+
*
658+
* @param moodleform $mform Moodle form (passed by reference)
659+
* @param string $classname repository class name
660+
*/
661+
public static function type_config_form($mform, $classname = 'repository') {
662+
global $CFG;
663+
if ($CFG->branch >= 36) {
664+
$mform->addElement('static', null, '',
665+
html_writer::div(get_string('migrationexplanation', 'repository_owncloud')) .
666+
html_writer::div(html_writer::link(new moodle_url('/repository/owncloud/migrate.php'),
667+
get_string('migrationlink', 'repository_owncloud'), ['class' => 'btn btn-primary'])
668+
));
669+
}
670+
671+
parent::type_config_form($mform);
672+
}
649673

650674
/**
651675
* This method adds a select form and additional information to the settings form..

migrate.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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+
* Perform migration to the core plugin repository_nextcloud (M3.6 and above only).
19+
*
20+
* @package repository_owncloud
21+
* @copyright 2018 Jan Dageförde (Learnweb, University of Münster), based on code by
22+
* 2017 Damyon Wiese <[email protected]>
23+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24+
*/
25+
26+
require_once(__DIR__ . '/../../config.php');
27+
28+
$PAGE->set_url('/repository/owncloud/migrate.php');
29+
$PAGE->set_context(context_system::instance());
30+
$strheading = get_string('migration', 'repository_owncloud');
31+
$PAGE->set_title($strheading);
32+
$PAGE->set_heading($strheading);
33+
34+
require_login();
35+
36+
require_capability('moodle/site:config', context_system::instance());
37+
38+
if ($CFG->branch < 36) {
39+
die('This functionality is only available in Moodle 3.6 and above.');
40+
}
41+
42+
$confirm = optional_param('confirm', false, PARAM_BOOL);
43+
44+
if ($confirm) {
45+
require_sesskey();
46+
47+
if (\repository_owncloud\migration::migrate_all_instances()) {
48+
$mesg = get_string('owncloudfilesmigrated', 'repository_owncloud');
49+
redirect(new moodle_url('/admin/repository.php', ['action' => 'edit', 'repos' => 'nextcloud', 'sesskey' => sesskey()]),
50+
$mesg, null, \core\output\notification::NOTIFY_SUCCESS);
51+
} else {
52+
$mesg = get_string('owncloudfilesnotmigrated', 'repository_owncloud');
53+
redirect(new moodle_url('/admin/repository.php', ['action' => 'edit', 'repos' => 'owncloud', 'sesskey' => sesskey()]),
54+
$mesg, null, \core\output\notification::NOTIFY_ERROR);
55+
}
56+
} else {
57+
$continueurl = new moodle_url('/repository/owncloud/migrate.php', ['confirm' => true]);
58+
$cancelurl = new moodle_url('/admin/repository.php', ['action' => 'edit', 'repos' => 'owncloud', 'sesskey' => sesskey()]);
59+
echo $OUTPUT->header();
60+
echo $OUTPUT->confirm(get_string('confirmmigration', 'repository_owncloud'), $continueurl, $cancelurl);
61+
echo $OUTPUT->footer();
62+
}

0 commit comments

Comments
 (0)