Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
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 * Class for loading/storing data requests from the DB. 19 * 20 * @package tool_dataprivacy 21 * @copyright 2018 Jun Pataleta 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace tool_dataprivacy; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 use lang_string; 30 use core\persistent; 31 32 /** 33 * Class for loading/storing data requests from the DB. 34 * 35 * @copyright 2018 Jun Pataleta 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class data_request extends persistent { 39 40 /** The table name this persistent object maps to. */ 41 const TABLE = 'tool_dataprivacy_request'; 42 43 /** Data request created manually. */ 44 const DATAREQUEST_CREATION_MANUAL = 0; 45 46 /** Data request created automatically. */ 47 const DATAREQUEST_CREATION_AUTO = 1; 48 49 /** 50 * Return the definition of the properties of this model. 51 * 52 * @return array 53 */ 54 protected static function define_properties() { 55 return [ 56 'type' => [ 57 'choices' => [ 58 api::DATAREQUEST_TYPE_EXPORT, 59 api::DATAREQUEST_TYPE_DELETE, 60 api::DATAREQUEST_TYPE_OTHERS, 61 ], 62 'type' => PARAM_INT 63 ], 64 'comments' => [ 65 'type' => PARAM_TEXT, 66 'message' => new lang_string('errorinvalidrequestcomments', 'tool_dataprivacy'), 67 'default' => '' 68 ], 69 'commentsformat' => [ 70 'choices' => [ 71 FORMAT_HTML, 72 FORMAT_MOODLE, 73 FORMAT_PLAIN, 74 FORMAT_MARKDOWN 75 ], 76 'type' => PARAM_INT, 77 'default' => FORMAT_PLAIN 78 ], 79 'userid' => [ 80 'default' => function() { 81 global $USER; 82 return $USER->id; 83 }, 84 'type' => PARAM_INT 85 ], 86 'requestedby' => [ 87 'default' => 0, 88 'type' => PARAM_INT 89 ], 90 'status' => [ 91 'default' => api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 92 'choices' => [ 93 api::DATAREQUEST_STATUS_PENDING, 94 api::DATAREQUEST_STATUS_PREPROCESSING, 95 api::DATAREQUEST_STATUS_AWAITING_APPROVAL, 96 api::DATAREQUEST_STATUS_APPROVED, 97 api::DATAREQUEST_STATUS_PROCESSING, 98 api::DATAREQUEST_STATUS_COMPLETE, 99 api::DATAREQUEST_STATUS_CANCELLED, 100 api::DATAREQUEST_STATUS_REJECTED, 101 api::DATAREQUEST_STATUS_DOWNLOAD_READY, 102 api::DATAREQUEST_STATUS_EXPIRED, 103 api::DATAREQUEST_STATUS_DELETED, 104 ], 105 'type' => PARAM_INT 106 ], 107 'dpo' => [ 108 'default' => 0, 109 'type' => PARAM_INT, 110 'null' => NULL_ALLOWED 111 ], 112 'dpocomment' => [ 113 'default' => '', 114 'type' => PARAM_TEXT, 115 'null' => NULL_ALLOWED 116 ], 117 'dpocommentformat' => [ 118 'choices' => [ 119 FORMAT_HTML, 120 FORMAT_MOODLE, 121 FORMAT_PLAIN, 122 FORMAT_MARKDOWN 123 ], 124 'type' => PARAM_INT, 125 'default' => FORMAT_PLAIN 126 ], 127 'systemapproved' => [ 128 'default' => false, 129 'type' => PARAM_BOOL, 130 ], 131 'creationmethod' => [ 132 'default' => self::DATAREQUEST_CREATION_MANUAL, 133 'choices' => [ 134 self::DATAREQUEST_CREATION_MANUAL, 135 self::DATAREQUEST_CREATION_AUTO 136 ], 137 'type' => PARAM_INT 138 ], 139 ]; 140 } 141 142 /** 143 * Determines whether a completed data export request has expired. 144 * The response will be valid regardless of the expiry scheduled task having run. 145 * 146 * @param data_request $request the data request object whose expiry will be checked. 147 * @return bool true if the request has expired. 148 */ 149 public static function is_expired(data_request $request) { 150 $result = false; 151 152 // Only export requests expire. 153 if ($request->get('type') == api::DATAREQUEST_TYPE_EXPORT) { 154 switch ($request->get('status')) { 155 // Expired requests are obviously expired. 156 case api::DATAREQUEST_STATUS_EXPIRED: 157 $result = true; 158 break; 159 // Complete requests are expired if the expiry time has elapsed. 160 case api::DATAREQUEST_STATUS_DOWNLOAD_READY: 161 $expiryseconds = get_config('tool_dataprivacy', 'privacyrequestexpiry'); 162 if ($expiryseconds > 0 && time() >= ($request->get('timemodified') + $expiryseconds)) { 163 $result = true; 164 } 165 break; 166 } 167 } 168 169 return $result; 170 } 171 172 /** 173 * Fetch completed data requests which are due to expire. 174 * 175 * @param int $userid Optional user ID to filter by. 176 * 177 * @return array Details of completed requests which are due to expire. 178 */ 179 public static function get_expired_requests($userid = 0) { 180 global $DB; 181 182 $expiryseconds = get_config('tool_dataprivacy', 'privacyrequestexpiry'); 183 $expirytime = strtotime("-{$expiryseconds} second"); 184 $table = self::TABLE; 185 $sqlwhere = 'type = :export_type AND status = :completestatus AND timemodified <= :expirytime'; 186 $params = array( 187 'export_type' => api::DATAREQUEST_TYPE_EXPORT, 188 'completestatus' => api::DATAREQUEST_STATUS_DOWNLOAD_READY, 189 'expirytime' => $expirytime, 190 ); 191 $sort = 'id'; 192 $fields = 'id, userid'; 193 194 // Filter by user ID if specified. 195 if ($userid > 0) { 196 $sqlwhere .= ' AND (userid = :userid OR requestedby = :requestedby)'; 197 $params['userid'] = $userid; 198 $params['requestedby'] = $userid; 199 } 200 201 return $DB->get_records_select_menu($table, $sqlwhere, $params, $sort, $fields, 0, 2000); 202 } 203 204 /** 205 * Expire a given set of data requests. 206 * Update request status and delete the files. 207 * 208 * @param array $expiredrequests [requestid => userid] 209 * 210 * @return void 211 */ 212 public static function expire($expiredrequests) { 213 global $DB; 214 215 $ids = array_keys($expiredrequests); 216 217 if (count($ids) > 0) { 218 list($insql, $inparams) = $DB->get_in_or_equal($ids); 219 $initialparams = array(api::DATAREQUEST_STATUS_EXPIRED, time()); 220 $params = array_merge($initialparams, $inparams); 221 222 $update = "UPDATE {" . self::TABLE . "} 223 SET status = ?, timemodified = ? 224 WHERE id $insql"; 225 226 if ($DB->execute($update, $params)) { 227 $fs = get_file_storage(); 228 229 foreach ($expiredrequests as $id => $userid) { 230 $usercontext = \context_user::instance($userid); 231 $fs->delete_area_files($usercontext->id, 'tool_dataprivacy', 'export', $id); 232 } 233 } 234 } 235 } 236 237 /** 238 * Whether this request is in a state appropriate for reset/resubmission. 239 * 240 * Note: This does not check whether any other completed requests exist for this user. 241 * 242 * @return bool 243 */ 244 public function is_resettable() : bool { 245 if (api::DATAREQUEST_TYPE_OTHERS == $this->get('type')) { 246 // It is not possible to reset 'other' reqeusts. 247 return false; 248 } 249 250 $resettable = [ 251 api::DATAREQUEST_STATUS_APPROVED => true, 252 api::DATAREQUEST_STATUS_REJECTED => true, 253 ]; 254 255 return isset($resettable[$this->get('status')]); 256 } 257 258 /** 259 * Whether this request is 'active'. 260 * 261 * @return bool 262 */ 263 public function is_active() : bool { 264 $active = [ 265 api::DATAREQUEST_STATUS_APPROVED => true, 266 ]; 267 268 return isset($active[$this->get('status')]); 269 } 270 271 /** 272 * Reject this request and resubmit it as a fresh request. 273 * 274 * Note: This does not check whether any other completed requests exist for this user. 275 * 276 * @return self 277 */ 278 public function resubmit_request() : data_request { 279 if ($this->is_active()) { 280 $this->set('status', api::DATAREQUEST_STATUS_REJECTED)->save(); 281 } 282 283 if (!$this->is_resettable()) { 284 throw new \moodle_exception('cannotreset', 'tool_dataprivacy'); 285 } 286 287 $currentdata = $this->to_record(); 288 unset($currentdata->id); 289 290 // Clone the original request, but do not notify. 291 $clone = api::create_data_request( 292 $this->get('userid'), 293 $this->get('type'), 294 $this->get('comments'), 295 $this->get('creationmethod'), 296 false 297 ); 298 $clone->set('comments', $this->get('comments')); 299 $clone->set('dpo', $this->get('dpo')); 300 $clone->set('requestedby', $this->get('requestedby')); 301 $clone->save(); 302 303 return $clone; 304 } 305 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body