MDL-28488 backup - make backup and import capabilities independent
[moodle.git] / backup / util / checks / backup_check.class.php
blob63ec0cd16a84f712bab075def9fece10dd84bf03
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * @package moodlecore
20 * @subpackage backup-factories
21 * @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 /**
26 * Non instantiable helper class providing different backup checks
28 * This class contains various static methods available in order to easily
29 * perform a bunch of backup architecture tests
31 * TODO: Finish phpdocs
33 abstract class backup_check {
35 public static function check_format_and_type($format, $type) {
36 global $CFG;
38 $file = $CFG->dirroot . '/backup/' . $format . '/backup_plan_builder.class.php';
39 if (! file_exists($file)) {
40 throw new backup_controller_exception('backup_check_unsupported_format', $format);
42 require_once($file);
43 if (!in_array($type, backup_plan_builder::supported_backup_types())) {
44 throw new backup_controller_exception('backup_check_unsupported_type', $type);
47 require_once($CFG->dirroot . '/backup/moodle2/backup_plan_builder.class.php');
50 public static function check_id($type, $id) {
51 global $DB;
52 switch ($type) {
53 case backup::TYPE_1ACTIVITY:
54 // id must exist in course_modules table
55 if (! $DB->record_exists('course_modules', array('id' => $id))) {
56 throw new backup_controller_exception('backup_check_module_not_exists', $id);
58 break;
59 case backup::TYPE_1SECTION:
60 // id must exist in course_sections table
61 if (! $DB->record_exists('course_sections', array('id' => $id))) {
62 throw new backup_controller_exception('backup_check_section_not_exists', $id);
64 break;
65 case backup::TYPE_1COURSE:
66 // id must exist in course table
67 if (! $DB->record_exists('course', array('id' => $id))) {
68 throw new backup_controller_exception('backup_check_course_not_exists', $id);
70 break;
71 default:
72 throw new backup_controller_exception('backup_check_incorrect_type', $type);
74 return true;
77 public static function check_user($userid) {
78 global $DB;
79 // userid must exist in user table
80 if (! $DB->record_exists('user', array('id' => $userid))) {
81 throw new backup_controller_exception('backup_check_user_not_exists', $userid);
83 return true;
86 public static function check_security($backup_controller, $apply) {
87 global $DB;
89 if (! $backup_controller instanceof backup_controller) {
90 throw new backup_controller_exception('backup_check_security_requires_backup_controller');
92 $backup_controller->log('checking plan security', backup::LOG_INFO);
94 // Some handy vars
95 $type = $backup_controller->get_type();
96 $mode = $backup_controller->get_mode();
97 $courseid = $backup_controller->get_courseid();
98 $coursectx= get_context_instance(CONTEXT_COURSE, $courseid);
99 $userid = $backup_controller->get_userid();
100 $id = $backup_controller->get_id(); // courseid / sectionid / cmid
102 // Note: all the checks along the function MUST be performed for $userid, that
103 // is the user who "requested" the course backup, not current $USER at all!!
105 // First of all, decide which caps/contexts are we going to check
106 // for common backups (general, automated...) based exclusively
107 // in the type (course, section, activity). And store them into
108 // one capability => context array structure
109 $typecapstocheck = array();
110 switch ($type) {
111 case backup::TYPE_1COURSE :
112 $DB->get_record('course', array('id' => $id), '*', MUST_EXIST); // course exists
113 $typecapstocheck['moodle/backup:backupcourse'] = $coursectx;
114 break;
115 case backup::TYPE_1SECTION :
116 $DB->get_record('course_sections', array('course' => $courseid, 'id' => $id), '*', MUST_EXIST); // sec exists
117 $typecapstocheck['moodle/backup:backupsection'] = $coursectx;
118 break;
119 case backup::TYPE_1ACTIVITY :
120 get_coursemodule_from_id(null, $id, $courseid, false, MUST_EXIST); // cm exists
121 $modulectx = get_context_instance(CONTEXT_MODULE, $id);
122 $typecapstocheck['moodle/backup:backupactivity'] = $modulectx;
123 break;
124 default :
125 throw new backup_controller_exception('backup_unknown_backup_type', $type);
128 // Now, if backup mode is hub or import, check userid has permissions for those modes
129 // other modes will perform common checks only (backupxxxx capabilities in $typecapstocheck)
130 switch ($mode) {
131 case backup::MODE_HUB:
132 if (!has_capability('moodle/backup:backuptargethub', $coursectx, $userid)) {
133 $a = new stdclass();
134 $a->userid = $userid;
135 $a->courseid = $courseid;
136 $a->capability = 'moodle/backup:backuptargethub';
137 throw new backup_controller_exception('backup_user_missing_capability', $a);
139 break;
140 case backup::MODE_IMPORT:
141 if (!has_capability('moodle/backup:backuptargetimport', $coursectx, $userid)) {
142 $a = new stdclass();
143 $a->userid = $userid;
144 $a->courseid = $courseid;
145 $a->capability = 'moodle/backup:backuptargetimport';
146 throw new backup_controller_exception('backup_user_missing_capability', $a);
148 break;
149 // Common backup (general, automated...), let's check all the $typecapstocheck
150 // capability => context pairs
151 default:
152 foreach ($typecapstocheck as $capability => $context) {
153 if (!has_capability($capability, $context, $userid)) {
154 $a = new stdclass();
155 $a->userid = $userid;
156 $a->courseid = $courseid;
157 $a->capability = $capability;
158 throw new backup_controller_exception('backup_user_missing_capability', $a);
163 // Now, enforce 'moodle/backup:userinfo' to 'users' setting, applying changes if allowed,
164 // else throwing exception
165 $userssetting = $backup_controller->get_plan()->get_setting('users');
166 $prevvalue = $userssetting->get_value();
167 $prevstatus = $userssetting->get_status();
168 $hasusercap = has_capability('moodle/backup:userinfo', $coursectx, $userid);
170 // If setting is enabled but user lacks permission
171 if (!$hasusercap && $prevvalue) { // If user has not the capability and setting is enabled
172 // Now analyse if we are allowed to apply changes or must stop with exception
173 if (!$apply) { // Cannot apply changes, throw exception
174 $a = new stdclass();
175 $a->setting = 'users';
176 $a->value = $prevvalue;
177 $a->capability = 'moodle/backup:userinfo';
178 throw new backup_controller_exception('backup_setting_value_wrong_for_capability', $a);
180 } else { // Can apply changes
181 $userssetting->set_value(false); // Set the value to false
182 $userssetting->set_status(base_setting::LOCKED_BY_PERMISSION);// Set the status to locked by perm
186 // Now, enforce 'moodle/backup:anonymise' to 'anonymise' setting, applying changes if allowed,
187 // else throwing exception
188 $anonsetting = $backup_controller->get_plan()->get_setting('anonymize');
189 $prevvalue = $anonsetting->get_value();
190 $prevstatus = $anonsetting->get_status();
191 $hasanoncap = has_capability('moodle/backup:anonymise', $coursectx, $userid);
193 // If setting is enabled but user lacks permission
194 if (!$hasanoncap && $prevvalue) { // If user has not the capability and setting is enabled
195 // Now analyse if we are allowed to apply changes or must stop with exception
196 if (!$apply) { // Cannot apply changes, throw exception
197 $a = new stdclass();
198 $a->setting = 'anonymize';
199 $a->value = $prevvalue;
200 $a->capability = 'moodle/backup:anonymise';
201 throw new backup_controller_exception('backup_setting_value_wrong_for_capability', $a);
203 } else { // Can apply changes
204 $anonsetting->set_value(false); // Set the value to false
205 $anonsetting->set_status(base_setting::LOCKED_BY_PERMISSION);// Set the status to locked by perm
209 // Now, if mode is HUB or IMPORT, and still we are including users in backup, turn them off
210 // Defaults processing should have handled this, but we need to be 100% sure
211 if ($mode == backup::MODE_IMPORT || $mode == backup::MODE_HUB) {
212 $userssetting = $backup_controller->get_plan()->get_setting('users');
213 if ($userssetting->get_value()) {
214 $userssetting->set_value(false); // Set the value to false
215 $userssetting->set_status(base_setting::LOCKED_BY_PERMISSION);// Set the status to locked by perm
219 // Check the user has the ability to configure the backup. If not then we need
220 // to lock all settings by permission so that no changes can be made.
221 $hasconfigcap = has_capability('moodle/backup:configure', $coursectx, $userid);
222 if (!$hasconfigcap) {
223 $settings = $backup_controller->get_plan()->get_settings();
224 foreach ($settings as $setting) {
225 if ($setting->get_name()=='filename') {
226 continue;
228 $setting->set_status(base_setting::LOCKED_BY_PERMISSION);
232 return true;