Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
/**
18
 * 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;
11 efrain 159
                // Complete requests are expired if the expiry time is a positive value, and has elapsed.
1 efrain 160
                case api::DATAREQUEST_STATUS_DOWNLOAD_READY:
11 efrain 161
                    $expiryseconds = (int) get_config('tool_dataprivacy', 'privacyrequestexpiry');
1 efrain 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
 
11 efrain 182
        // Complete requests are expired if the expiry time is a positive value, and has elapsed.
183
        $expiryseconds = (int) get_config('tool_dataprivacy', 'privacyrequestexpiry');
184
        if ($expiryseconds <= 0) {
185
            return [];
186
        }
187
 
1 efrain 188
        $expirytime = strtotime("-{$expiryseconds} second");
189
        $table = self::TABLE;
190
        $sqlwhere = 'type = :export_type AND status = :completestatus AND timemodified <= :expirytime';
191
        $params = array(
192
            'export_type' => api::DATAREQUEST_TYPE_EXPORT,
193
            'completestatus' => api::DATAREQUEST_STATUS_DOWNLOAD_READY,
194
            'expirytime' => $expirytime,
195
        );
196
        $sort = 'id';
197
        $fields = 'id, userid';
198
 
199
        // Filter by user ID if specified.
200
        if ($userid > 0) {
201
            $sqlwhere .= ' AND (userid = :userid OR requestedby = :requestedby)';
202
            $params['userid'] = $userid;
203
            $params['requestedby'] = $userid;
204
        }
205
 
206
        return $DB->get_records_select_menu($table, $sqlwhere, $params, $sort, $fields, 0, 2000);
207
    }
208
 
209
    /**
210
     * Expire a given set of data requests.
211
     * Update request status and delete the files.
212
     *
213
     * @param array $expiredrequests [requestid => userid]
214
     *
215
     * @return void
216
     */
217
    public static function expire($expiredrequests) {
218
        global $DB;
219
 
220
        $ids = array_keys($expiredrequests);
221
 
222
        if (count($ids) > 0) {
223
            list($insql, $inparams) = $DB->get_in_or_equal($ids);
224
            $initialparams = array(api::DATAREQUEST_STATUS_EXPIRED, time());
225
            $params = array_merge($initialparams, $inparams);
226
 
227
            $update = "UPDATE {" . self::TABLE . "}
228
                          SET status = ?, timemodified = ?
229
                        WHERE id $insql";
230
 
231
            if ($DB->execute($update, $params)) {
232
                $fs = get_file_storage();
233
 
234
                foreach ($expiredrequests as $id => $userid) {
235
                    $usercontext = \context_user::instance($userid);
236
                    $fs->delete_area_files($usercontext->id, 'tool_dataprivacy', 'export', $id);
237
                }
238
            }
239
        }
240
    }
241
 
242
    /**
243
     * Whether this request is in a state appropriate for reset/resubmission.
244
     *
245
     * Note: This does not check whether any other completed requests exist for this user.
246
     *
247
     * @return  bool
248
     */
249
    public function is_resettable(): bool {
250
        if (api::DATAREQUEST_TYPE_OTHERS == $this->get('type')) {
251
            // It is not possible to reset 'other' reqeusts.
252
            return false;
253
        }
254
 
255
        $resettable = [
256
            api::DATAREQUEST_STATUS_APPROVED => true,
257
            api::DATAREQUEST_STATUS_REJECTED => true,
258
        ];
259
 
260
        return isset($resettable[$this->get('status')]);
261
    }
262
 
263
    /**
264
     * Whether this request is 'active'.
265
     *
266
     * @return  bool
267
     */
268
    public function is_active(): bool {
269
        $active = [
270
            api::DATAREQUEST_STATUS_APPROVED => true,
271
        ];
272
 
273
        return isset($active[$this->get('status')]);
274
    }
275
 
276
    /**
277
     * Reject this request and resubmit it as a fresh request.
278
     *
279
     * Note: This does not check whether any other completed requests exist for this user.
280
     *
281
     * @return  self
282
     */
283
    public function resubmit_request(): data_request {
284
        if ($this->is_active()) {
285
            $this->set('status', api::DATAREQUEST_STATUS_REJECTED)->save();
286
        }
287
 
288
        if (!$this->is_resettable()) {
289
            throw new \moodle_exception('cannotreset', 'tool_dataprivacy');
290
        }
291
 
292
        $currentdata = $this->to_record();
293
        unset($currentdata->id);
294
 
295
        // Clone the original request, but do not notify.
296
        $clone = api::create_data_request(
297
                $this->get('userid'),
298
                $this->get('type'),
299
                $this->get('comments'),
300
                $this->get('creationmethod'),
301
                false
302
            );
303
        $clone->set('comments', $this->get('comments'));
304
        $clone->set('dpo', $this->get('dpo'));
305
        $clone->set('requestedby', $this->get('requestedby'));
306
        $clone->save();
307
 
308
        return $clone;
309
    }
310
}