Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 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
namespace core_ai\privacy;
18
 
19
use core_privacy\local\metadata\collection;
20
use core_privacy\local\request\approved_contextlist;
21
use core_privacy\local\request\approved_userlist;
22
use core_privacy\local\request\contextlist;
23
use core_privacy\local\request\transform;
24
use core_privacy\local\request\userlist;
25
use core_privacy\local\request\writer;
26
 
27
/**
28
 * Privacy Subsystem for core_ai implementing null_provider.
29
 *
30
 * @package    core_ai
31
 * @copyright  2024 Matt Porritt <matt.porritt@moodle.com>
32
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 */
34
class provider implements
35
    \core_privacy\local\metadata\provider,
36
    \core_privacy\local\request\subsystem\provider,
37
    \core_privacy\local\request\core_userlist_provider {
38
 
39
    /**
40
     * Returns meta data about this system.
41
     *
42
     * @param collection $collection The initialised collection to add items to.
43
     * @return collection A listing of user data stored through this system.
44
     */
45
    public static function get_metadata(collection $collection): collection {
46
        $collection->add_database_table('ai_policy_register', [
47
            'userid' => 'privacy:metadata:ai_policy_register:userid',
48
            'contextid' => 'privacy:metadata:ai_policy_register:contextid',
49
            'timeaccepted' => 'privacy:metadata:ai_policy_register:timeaccepted',
50
        ], 'privacy:metadata:ai_policy_register');
51
        $collection->add_database_table('ai_action_register', [
52
            'actionname' => 'privacy:metadata:ai_action_register:actionname',
53
            'actionid' => 'privacy:metadata:ai_action_register:actionid',
54
            'success' => 'privacy:metadata:ai_action_register:success',
55
            'userid' => 'privacy:metadata:ai_action_register:userid',
56
            'provider' => 'privacy:metadata:ai_action_register:provider',
57
            'timecreated' => 'privacy:metadata:ai_action_register:timecreated',
58
            'timecompleted' => 'privacy:metadata:ai_action_register:timecompleted',
59
            'model' => 'privacy:metadata:ai_action_register:model',
60
        ], 'privacy:metadata:ai_action_register');
61
        $collection->add_database_table('ai_action_generate_image', [
62
            'prompt' => 'privacy:metadata:ai_action_generate_image:prompt',
63
            'numberimages' => 'privacy:metadata:ai_action_generate_image:numberimages',
64
            'quality' => 'privacy:metadata:ai_action_generate_image:quality',
65
            'aspectratio' => 'privacy:metadata:ai_action_generate_image:aspectratio',
66
            'style' => 'privacy:metadata:ai_action_generate_image:style',
67
            'sourceurl' => 'privacy:metadata:ai_action_generate_image:sourceurl',
68
            'revisedprompt' => 'privacy:metadata:ai_action_generate_image:revisedprompt',
69
        ], 'privacy:metadata:ai_action_generate_image');
70
        $collection->add_database_table('ai_action_generate_text', [
71
            'prompt' => 'privacy:metadata:ai_action_generate_text:prompt',
72
            'responseid' => 'privacy:metadata:ai_action_generate_text:responseid',
73
            'fingerprint' => 'privacy:metadata:ai_action_generate_text:fingerprint',
74
            'generatedcontent' => 'privacy:metadata:ai_action_generate_text:generatedcontent',
75
            'prompttokens' => 'privacy:metadata:ai_action_generate_text:prompttokens',
76
            'completiontoken' => 'privacy:metadata:ai_action_generate_text:completiontoken',
77
        ], 'privacy:metadata:ai_action_generate_text');
78
        $collection->add_database_table('ai_action_summarise_text', [
79
            'prompt' => 'privacy:metadata:ai_action_summarise_text:prompt',
80
            'responseid' => 'privacy:metadata:ai_action_summarise_text:responseid',
81
            'fingerprint' => 'privacy:metadata:ai_action_summarise_text:fingerprint',
82
            'generatedcontent' => 'privacy:metadata:ai_action_summarise_text:generatedcontent',
83
            'prompttokens' => 'privacy:metadata:ai_action_summarise_text:prompttokens',
84
            'completiontoken' => 'privacy:metadata:ai_action_summarise_text:completiontoken',
85
        ], 'privacy:metadata:ai_action_summarise_text');
86
        $collection->add_database_table('ai_action_explain_text', [
87
            'prompt' => 'privacy:metadata:ai_action_explain_text:prompt',
88
            'responseid' => 'privacy:metadata:ai_action_explain_text:responseid',
89
            'fingerprint' => 'privacy:metadata:ai_action_explain_text:fingerprint',
90
            'generatedcontent' => 'privacy:metadata:ai_action_explain_text:generatedcontent',
91
            'prompttokens' => 'privacy:metadata:ai_action_explain_text:prompttokens',
92
            'completiontoken' => 'privacy:metadata:ai_action_explain_text:completiontoken',
93
        ], 'privacy:metadata:ai_action_explain_text');
94
 
95
        return $collection;
96
    }
97
 
98
    /**
99
     * Get the list of contexts that contain user information for the specified user.
100
     *
101
     * @param int $userid The user to search.
102
     * @return  contextlist   $contextlist  The contextlist containing the list of contexts used in this plugin.
103
     */
104
    public static function get_contexts_for_userid(int $userid): contextlist {
105
        $contextlist = new contextlist();
106
 
107
        // AI policy.
108
        $sql = 'SELECT DISTINCT ctx.id
109
                  FROM {context} ctx
110
                  JOIN {ai_policy_register} apr
111
                    ON apr.contextid = ctx.id
112
                 WHERE apr.userid = :userid';
113
        $contextlist->add_from_sql($sql, ['userid' => $userid]);
114
 
115
        // AI action generate text.
116
        $sql = "SELECT DISTINCT ctx.id
117
                  FROM {context} ctx
118
                  JOIN {ai_action_register} aar
119
                    ON aar.contextid = ctx.id
120
                  JOIN {ai_action_generate_text} aagt
121
                    ON aagt.id = aar.actionid
122
                 WHERE aar.actionname = 'generate_text'
123
                       AND aar.userid = :userid";
124
        $contextlist->add_from_sql($sql, ['userid' => $userid]);
125
 
126
        // AI action generate image.
127
        $sql = "SELECT DISTINCT ctx.id
128
                  FROM {context} ctx
129
                  JOIN {ai_action_register} aar
130
                    ON aar.contextid = ctx.id
131
                  JOIN {ai_action_generate_image} aagi
132
                    ON aagi.id = aar.actionid
133
                 WHERE aar.actionname = 'generate_image'
134
                       AND aar.userid = :userid";
135
        $contextlist->add_from_sql($sql, ['userid' => $userid]);
136
 
137
        // AI action summarise text.
138
        $sql = "SELECT DISTINCT ctx.id
139
                  FROM {context} ctx
140
                  JOIN {ai_action_register} aar
141
                    ON aar.contextid = ctx.id
142
                  JOIN {ai_action_summarise_text} aast
143
                    ON aast.id = aar.actionid
144
                 WHERE aar.actionname = 'summarise_text'
145
                       AND aar.userid = :userid";
146
        $contextlist->add_from_sql($sql, ['userid' => $userid]);
147
 
148
        // AI action explain text.
149
        $sql = "SELECT DISTINCT ctx.id
150
                  FROM {context} ctx
151
                  JOIN {ai_action_register} aar
152
                    ON aar.contextid = ctx.id
153
                  JOIN {ai_action_explain_text} aaet
154
                    ON aaet.id = aar.actionid
155
                 WHERE aar.actionname = 'explain_text'
156
                       AND aar.userid = :userid";
157
        $contextlist->add_from_sql($sql, ['userid' => $userid]);
158
 
159
        return $contextlist;
160
    }
161
 
162
    /**
163
     * Export all user data for the specified user, in the specified contexts.
164
     *
165
     * @param approved_contextlist $contextlist The approved contexts to export information for.
166
     */
167
    public static function export_user_data(approved_contextlist $contextlist): void {
168
        global $DB;
169
        // AI policy.
170
        $userid = $contextlist->get_user()->id;
171
        [$contextsql, $contextparams] = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
172
 
173
        $sql = 'SELECT apr.timeaccepted, ctx.id AS contextid
174
                  FROM {context} ctx
175
                  JOIN {ai_policy_register} apr
176
                    ON apr.contextid = ctx.id
177
                 WHERE apr.userid = :userid
178
                       AND ctx.id ' . $contextsql;
179
        $params = [
180
            'userid' => $userid,
181
        ];
182
        $params += $contextparams;
183
        $policydetails = $DB->get_recordset_sql($sql, $params);
184
        foreach ($policydetails as $policydetail) {
185
            $subcontexts = [
186
                get_string('ai', 'core_ai'),
187
            ];
188
            $name = 'policy';
189
            $details = (object) [
190
                'contextid' => $policydetail->contextid,
191
                'timeaccepted' => transform::datetime($policydetail->timeaccepted),
192
            ];
193
            $context = \context::instance_by_id($policydetail->contextid);
194
            writer::with_context($context)->export_related_data($subcontexts, $name, $details);
195
        }
196
        $policydetails->close();
197
 
198
        // AI action generate text.
199
        $sql = "SELECT aar.actionname, aar.success, aar.provider, aar.timecreated, aar.timecompleted, aar.contextid,
200
                       aagt.prompt, aagt.responseid, aagt.fingerprint, aagt.generatedcontent,
201
                       aagt.prompttokens, aagt.completiontoken, aar.model
202
                  FROM {ai_action_register} aar
203
                  JOIN {ai_action_generate_text} aagt
204
                    ON aar.actionid = aagt.id
205
                  JOIN {context} ctx
206
                    ON aar.contextid = ctx.id
207
                 WHERE aar.actionname = 'generate_text'
208
                       AND aar.userid = :userid
209
                       AND ctx.id " . $contextsql;
210
        $params = [
211
            'userid' => $userid,
212
        ];
213
        $params += $contextparams;
214
        $textgeneratedetails = $DB->get_recordset_sql($sql, $params);
215
        foreach ($textgeneratedetails as $textgeneratedetail) {
216
            $subcontexts = [
217
                get_string('ai', 'core_ai'),
218
                get_string('action_generate_text', 'core_ai'),
219
                date('c', $textgeneratedetail->timecreated),
220
            ];
221
            $details = (object) [
222
                'actionname' => $textgeneratedetail->actionname,
223
                'contextid' => $textgeneratedetail->contextid,
224
                'prompt' => $textgeneratedetail->prompt,
225
                'responseid' => $textgeneratedetail->responseid,
226
                'fingerprint' => $textgeneratedetail->fingerprint,
227
                'generatedcontent' => $textgeneratedetail->generatedcontent,
228
                'prompttokens' => $textgeneratedetail->prompttokens,
229
                'completiontoken' => $textgeneratedetail->completiontoken,
230
                'model' => $textgeneratedetail->model,
231
                'success' => transform::yesno($textgeneratedetail->success),
232
                'provider' => $textgeneratedetail->provider,
233
                'timecreated' => transform::datetime($textgeneratedetail->timecreated),
234
                'timecompleted' => transform::datetime($textgeneratedetail->timecompleted),
235
            ];
236
            $name = 'action_generate_text';
237
            $context = \context::instance_by_id($textgeneratedetail->contextid);
238
            writer::with_context($context)->export_related_data($subcontexts, $name, $details);
239
        }
240
        $textgeneratedetails->close();
241
 
242
        // AI action generate image.
243
        $sql = "SELECT aar.actionname, aar.success, aar.provider, aar.timecreated, aar.timecompleted, aar.contextid,
244
                       aagi.prompt, aagi.numberimages, aagi.quality, aagi.aspectratio, aagi.style, aagi.sourceurl,
245
                       aagi.revisedprompt, aar.model
246
                  FROM {ai_action_register} aar
247
                  JOIN {ai_action_generate_image} aagi
248
                    ON aar.actionid = aagi.id
249
                  JOIN {context} ctx
250
                    ON aar.contextid = ctx.id
251
                 WHERE aar.actionname = 'generate_image'
252
                       AND aar.userid = :userid
253
                       AND ctx.id " . $contextsql;
254
        $params = [
255
            'userid' => $userid,
256
        ];
257
        $params += $contextparams;
258
        $imagegeneratedetails = $DB->get_recordset_sql($sql, $params);
259
        foreach ($imagegeneratedetails as $imagegeneratedetail) {
260
            $subcontexts = [
261
                get_string('ai', 'core_ai'),
262
                get_string('action_generate_image', 'core_ai'),
263
                date('c', $imagegeneratedetail->timecreated),
264
            ];
265
            $details = (object) [
266
                'actionname' => $imagegeneratedetail->actionname,
267
                'contextid' => $imagegeneratedetail->contextid,
268
                'prompt' => $imagegeneratedetail->prompt,
269
                'numberimages' => $imagegeneratedetail->numberimages,
270
                'quality' => $imagegeneratedetail->quality,
271
                'aspectratio' => $imagegeneratedetail->aspectratio,
272
                'style' => $imagegeneratedetail->style,
273
                'sourceurl' => $imagegeneratedetail->sourceurl,
274
                'revisedprompt' => $imagegeneratedetail->revisedprompt,
275
                'model' => $imagegeneratedetail->model,
276
                'success' => transform::yesno($imagegeneratedetail->success),
277
                'provider' => $imagegeneratedetail->provider,
278
                'timecreated' => transform::datetime($imagegeneratedetail->timecreated),
279
                'timecompleted' => transform::datetime($imagegeneratedetail->timecompleted),
280
            ];
281
            $name = 'action_generate_image';
282
            $context = \context::instance_by_id($imagegeneratedetail->contextid);
283
            writer::with_context($context)->export_related_data($subcontexts, $name, $details);
284
        }
285
        $imagegeneratedetails->close();
286
 
287
        // AI action summarise text.
288
        $sql = "SELECT aar.actionname, aar.success, aar.provider, aar.timecreated, aar.timecompleted, aar.contextid,
289
                       aast.prompt, aast.responseid, aast.fingerprint, aast.generatedcontent,
290
                       aast.prompttokens, aast.completiontoken, aar.model
291
                  FROM {ai_action_register} aar
292
                  JOIN {ai_action_summarise_text} aast
293
                    ON aar.actionid = aast.id
294
                  JOIN {context} ctx
295
                    ON aar.contextid = ctx.id
296
                 WHERE aar.actionname = 'summarise_text'
297
                       AND aar.userid = :userid
298
                       AND ctx.id " . $contextsql;
299
        $params = [
300
            'userid' => $userid,
301
        ];
302
        $params += $contextparams;
303
        $textsummarisedetails = $DB->get_recordset_sql($sql, $params);
304
        foreach ($textsummarisedetails as $textsummarisedetail) {
305
            $subcontexts = [
306
                get_string('ai', 'core_ai'),
307
                get_string('action_summarise_text', 'core_ai'),
308
                date('c', $textsummarisedetail->timecreated),
309
            ];
310
            $details = (object) [
311
                'actionname' => $textsummarisedetail->actionname,
312
                'contextid' => $textsummarisedetail->contextid,
313
                'prompt' => $textsummarisedetail->prompt,
314
                'responseid' => $textsummarisedetail->responseid,
315
                'fingerprint' => $textsummarisedetail->fingerprint,
316
                'generatedcontent' => $textsummarisedetail->generatedcontent,
317
                'prompttokens' => $textsummarisedetail->prompttokens,
318
                'completiontoken' => $textsummarisedetail->completiontoken,
319
                'model' => $textsummarisedetail->model,
320
                'success' => transform::yesno($textsummarisedetail->success),
321
                'provider' => $textsummarisedetail->provider,
322
                'timecreated' => transform::datetime($textsummarisedetail->timecreated),
323
                'timecompleted' => transform::datetime($textsummarisedetail->timecompleted),
324
            ];
325
            $name = 'action_summarise_text';
326
            $context = \context::instance_by_id($textsummarisedetail->contextid);
327
            writer::with_context($context)->export_related_data($subcontexts, $name, $details);
328
        }
329
        $textsummarisedetails->close();
330
 
331
        // AI action explain text.
332
        $sql = "SELECT aar.actionname, aar.success, aar.provider, aar.timecreated, aar.timecompleted, aar.contextid,
333
                       aaet.prompt, aaet.responseid, aaet.fingerprint, aaet.generatedcontent,
334
                       aaet.prompttokens, aaet.completiontoken, aar.model
335
                  FROM {ai_action_register} aar
336
                  JOIN {ai_action_explain_text} aaet
337
                    ON aar.actionid = aaet.id
338
                  JOIN {context} ctx
339
                    ON aar.contextid = ctx.id
340
                 WHERE aar.actionname = 'explain_text'
341
                       AND aar.userid = :userid
342
                       AND ctx.id " . $contextsql;
343
        $params = [
344
            'userid' => $userid,
345
        ];
346
        $params += $contextparams;
347
        $textexplaindetails = $DB->get_recordset_sql($sql, $params);
348
        foreach ($textexplaindetails as $textexplaindetail) {
349
            $subcontexts = [
350
                get_string('ai', 'core_ai'),
351
                get_string('action_explain_text', 'core_ai'),
352
                date('c', $textexplaindetail->timecreated),
353
            ];
354
            $details = (object) [
355
                'actionname' => $textexplaindetail->actionname,
356
                'contextid' => $textexplaindetail->contextid,
357
                'prompt' => $textexplaindetail->prompt,
358
                'responseid' => $textexplaindetail->responseid,
359
                'fingerprint' => $textexplaindetail->fingerprint,
360
                'generatedcontent' => $textexplaindetail->generatedcontent,
361
                'prompttokens' => $textexplaindetail->prompttokens,
362
                'completiontoken' => $textexplaindetail->completiontoken,
363
                'model' => $textexplaindetail->model,
364
                'success' => transform::yesno($textexplaindetail->success),
365
                'provider' => $textexplaindetail->provider,
366
                'timecreated' => transform::datetime($textexplaindetail->timecreated),
367
                'timecompleted' => transform::datetime($textexplaindetail->timecompleted),
368
            ];
369
            $name = 'action_explain_text';
370
            $context = \context::instance_by_id($textexplaindetail->contextid);
371
            writer::with_context($context)->export_related_data($subcontexts, $name, $details);
372
        }
373
        $textexplaindetails->close();
374
    }
375
 
376
    /**
377
     * Delete all data for all users in the specified context.
378
     *
379
     * @param \context $context The specific context to delete data for.
380
     */
381
    public static function delete_data_for_all_users_in_context(\context $context): void {
382
        global $DB;
383
 
384
        // Policy.
385
        $sql = 'SELECT DISTINCT apr.id
386
                  FROM {ai_policy_register} apr
387
                  JOIN {context} ctx
388
                    ON apr.contextid = ctx.id
389
                 WHERE ctx.id = :contextid';
390
        $params = [
391
            'contextid' => $context->id,
392
        ];
393
        $policydetails = $DB->get_records_sql($sql, $params);
394
        if ($policydetails) {
395
            $DB->delete_records_list('ai_policy_register', 'id', array_keys($policydetails));
396
        }
397
 
398
        // AI action generate text.
399
        $sql = "SELECT DISTINCT aagt.id
400
                  FROM {ai_action_register} aar
401
                  JOIN {ai_action_generate_text} aagt
402
                    ON aar.actionid = aagt.id
403
                  JOIN {context} ctx
404
                    ON aar.contextid = ctx.id
405
                 WHERE aar.actionname = 'generate_text'
406
                       AND ctx.id = :contextid";
407
        $params = [
408
            'contextid' => $context->id,
409
        ];
410
        $aagtids = $DB->get_records_sql_menu($sql, $params);
411
        if ($aagtids) {
412
            [$aagtidsql, $aagtidparams] = $DB->get_in_or_equal(array_keys($aagtids), SQL_PARAMS_NAMED);
413
            $sql = "UPDATE {ai_action_generate_text}
414
                   SET prompt = '',
415
                       responseid = '',
416
                       fingerprint = '',
417
                       generatedcontent = ''
418
                 WHERE id " . $aagtidsql;
419
            $DB->execute($sql, $aagtidparams);
420
        }
421
 
422
        // AI action generate image.
423
        $sql = "SELECT DISTINCT aagi.id
424
                  FROM {ai_action_register} aar
425
                  JOIN {ai_action_generate_image} aagi
426
                    ON aar.actionid = aagi.id
427
                  JOIN {context} ctx
428
                    ON aar.contextid = ctx.id
429
                 WHERE aar.actionname = 'generate_image'
430
                       AND ctx.id = :contextid";
431
        $params = [
432
            'contextid' => $context->id,
433
        ];
434
        $aagiids = $DB->get_records_sql_menu($sql, $params);
435
        if ($aagiids) {
436
            [$aagiidsql, $aagiidparams] = $DB->get_in_or_equal(array_keys($aagiids), SQL_PARAMS_NAMED);
437
            $sql = "UPDATE {ai_action_generate_image}
438
                   SET prompt = '',
439
                       sourceurl = '',
440
                       revisedprompt = ''
441
                 WHERE id " . $aagiidsql;
442
            $DB->execute($sql, $aagiidparams);
443
        }
444
 
445
        // AI action summarise text.
446
        $sql = "SELECT DISTINCT aast.id
447
                  FROM {ai_action_register} aar
448
                  JOIN {ai_action_summarise_text} aast
449
                    ON aar.actionid = aast.id
450
                  JOIN {context} ctx
451
                    ON aar.contextid = ctx.id
452
                 WHERE aar.actionname = 'summarise_text'
453
                       AND ctx.id = :contextid";
454
        $params = [
455
            'contextid' => $context->id,
456
        ];
457
        $aastids = $DB->get_records_sql_menu($sql, $params);
458
        if ($aastids) {
459
            [$aastidsql, $aastidparams] = $DB->get_in_or_equal(array_keys($aastids), SQL_PARAMS_NAMED);
460
            $sql = "UPDATE {ai_action_summarise_text}
461
                   SET prompt = '',
462
                       responseid = '',
463
                       fingerprint = '',
464
                       generatedcontent = ''
465
                 WHERE id " . $aastidsql;
466
            $DB->execute($sql, $aastidparams);
467
        }
468
 
469
        // AI action explain text.
470
        $sql = "SELECT DISTINCT aaet.id
471
                  FROM {ai_action_register} aar
472
                  JOIN {ai_action_explain_text} aaet
473
                    ON aar.actionid = aaet.id
474
                  JOIN {context} ctx
475
                    ON aar.contextid = ctx.id
476
                 WHERE aar.actionname = 'explain_text'
477
                       AND ctx.id = :contextid";
478
        $params = [
479
            'contextid' => $context->id,
480
        ];
481
        $aaetids = $DB->get_records_sql_menu($sql, $params);
482
        if ($aaetids) {
483
            [$aaetidsql, $aaetidparams] = $DB->get_in_or_equal(array_keys($aaetids), SQL_PARAMS_NAMED);
484
            $sql = "UPDATE {ai_action_explain_text}
485
                   SET prompt = '',
486
                       responseid = '',
487
                       fingerprint = '',
488
                       generatedcontent = ''
489
                 WHERE id " . $aaetidsql;
490
            $DB->execute($sql, $aaetidparams);
491
        }
492
    }
493
 
494
    /**
495
     * Delete all user data for the specified user, in the specified contexts.
496
     *
497
     * @param approved_contextlist $contextlist The approved contexts and user information to delete information for.
498
     */
499
    public static function delete_data_for_user(approved_contextlist $contextlist): void {
500
        global $DB;
501
 
502
        // Policy.
503
        $userid = $contextlist->get_user()->id;
504
        [$contextsql, $contextparams] = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED);
505
 
506
        $sql = "SELECT DISTINCT apr.id AS policyid
507
                  FROM {context} ctx
508
                  JOIN {ai_policy_register} apr
509
                    ON apr.contextid = ctx.id
510
                 WHERE apr.userid = :userid
511
                       AND ctx.id " . $contextsql;
512
        $params = [
513
            'userid' => $userid,
514
        ];
515
        $params += $contextparams;
516
        $policydetails = $DB->get_recordset_sql($sql, $params);
517
        $policyids = [];
518
        foreach ($policydetails as $policydetail) {
519
            $policyids[] = $policydetail->policyid;
520
        }
521
        $policydetails->close();
522
        $DB->delete_records_list('ai_policy_register', 'id', $policyids);
523
 
524
        // AI action generate text.
525
        $sql = "SELECT DISTINCT aagt.id AS textgenerateid
526
                  FROM {ai_action_register} aar
527
                  JOIN {ai_action_generate_text} aagt
528
                    ON aar.actionid = aagt.id
529
                  JOIN {context} ctx
530
                    ON aar.contextid = ctx.id
531
                 WHERE aar.actionname = 'generate_text'
532
                       AND aar.userid = :userid
533
                       AND ctx.id " . $contextsql;
534
        $textgeneratedetails = $DB->get_recordset_sql($sql, $params);
535
        $aagtids = [];
536
        foreach ($textgeneratedetails as $textgeneratedetail) {
537
            $aagtids[] = $textgeneratedetail->textgenerateid;
538
        }
539
        $textgeneratedetails->close();
540
        if ($aagtids) {
541
            [$aagtidsql, $aagtidparams] = $DB->get_in_or_equal($aagtids, SQL_PARAMS_NAMED);
542
            $sql = "UPDATE {ai_action_generate_text}
543
                   SET prompt = '',
544
                       responseid = '',
545
                       fingerprint = '',
546
                       generatedcontent = ''
547
                 WHERE id " . $aagtidsql;
548
            $DB->execute($sql, $aagtidparams);
549
        }
550
 
551
        // AI action generate image.
552
        $sql = "SELECT DISTINCT aagi.id AS imagegenerateid
553
                  FROM {ai_action_register} aar
554
                  JOIN {ai_action_generate_image} aagi
555
                    ON aar.actionid = aagi.id
556
                  JOIN {context} ctx
557
                    ON aar.contextid = ctx.id
558
                 WHERE aar.actionname = 'generate_image'
559
                       AND aar.userid = :userid
560
                       AND ctx.id " . $contextsql;
561
        $imagegeneratedetails = $DB->get_recordset_sql($sql, $params);
562
        $aagiids = [];
563
        foreach ($imagegeneratedetails as $imagegeneratedetail) {
564
            $aagiids[] = $imagegeneratedetail->imagegenerateid;
565
        }
566
        $imagegeneratedetails->close();
567
        if ($aagiids) {
568
            [$aagiidsql, $aagiidparams] = $DB->get_in_or_equal($aagiids, SQL_PARAMS_NAMED);
569
            $sql = "UPDATE {ai_action_generate_image}
570
                   SET prompt = '',
571
                       sourceurl = '',
572
                       revisedprompt = ''
573
                 WHERE id " . $aagiidsql;
574
            $DB->execute($sql, $aagiidparams);
575
        }
576
 
577
        // AI action summarise text.
578
        $sql = "SELECT DISTINCT aast.id AS textsummariseid
579
                  FROM {ai_action_register} aar
580
                  JOIN {ai_action_summarise_text} aast
581
                    ON aar.actionid = aast.id
582
                  JOIN {context} ctx
583
                    ON aar.contextid = ctx.id
584
                 WHERE aar.actionname = 'summarise_text'
585
                       AND aar.userid = :userid
586
                       AND ctx.id " . $contextsql;
587
        $textsummarisedetails = $DB->get_recordset_sql($sql, $params);
588
        $aastids = [];
589
        foreach ($textsummarisedetails as $textsummarisedetail) {
590
            $aastids[] = $textsummarisedetail->textsummariseid;
591
        }
592
        $textsummarisedetails->close();
593
        if ($aastids) {
594
            [$aastidsql, $aastidparams] = $DB->get_in_or_equal($aastids, SQL_PARAMS_NAMED);
595
            $sql = "UPDATE {ai_action_summarise_text}
596
                   SET prompt = '',
597
                       responseid = '',
598
                       fingerprint = '',
599
                       generatedcontent = ''
600
                 WHERE id " . $aastidsql;
601
            $DB->execute($sql, $aastidparams);
602
        }
603
 
604
        // AI action explain text.
605
        $sql = "SELECT DISTINCT aaet.id AS textexplainid
606
                  FROM {ai_action_register} aar
607
                  JOIN {ai_action_explain_text} aaet
608
                    ON aar.actionid = aaet.id
609
                  JOIN {context} ctx
610
                    ON aar.contextid = ctx.id
611
                 WHERE aar.actionname = 'explain_text'
612
                       AND aar.userid = :userid
613
                       AND ctx.id " . $contextsql;
614
        $textexplaindetails = $DB->get_recordset_sql($sql, $params);
615
        $aaetids = [];
616
        foreach ($textexplaindetails as $textexplaindetail) {
617
            $aaetids[] = $textexplaindetail->textexplainid;
618
        }
619
        $textexplaindetails->close();
620
        if ($aaetids) {
621
            [$aaetidsql, $aaetidparams] = $DB->get_in_or_equal($aaetids, SQL_PARAMS_NAMED);
622
            $sql = "UPDATE {ai_action_explain_text}
623
                   SET prompt = '',
624
                       responseid = '',
625
                       fingerprint = '',
626
                       generatedcontent = ''
627
                 WHERE id " . $aaetidsql;
628
            $DB->execute($sql, $aaetidparams);
629
        }
630
    }
631
 
632
    /**
633
     * Get the list of users who have data within a context.
634
     *
635
     * @param userlist $userlist The userlist containing the list of users who have data in this context/plugin combination.
636
     */
637
    public static function get_users_in_context(userlist $userlist): void {
638
        $context = $userlist->get_context();
639
 
640
        // AI policy.
641
        $sql = 'SELECT DISTINCT apr.userid
642
                  FROM {context} ctx
643
                  JOIN {ai_policy_register} apr
644
                    ON apr.contextid = ctx.id
645
                 WHERE apr.contextid = :contextid';
646
        $userlist->add_from_sql('userid', $sql, ['contextid' => $context->id]);
647
 
648
        // AI action generate text.
649
        $sql = "SELECT DISTINCT aar.userid
650
                  FROM {context} ctx
651
                  JOIN {ai_action_register} aar
652
                    ON aar.contextid = ctx.id
653
                  JOIN {ai_action_generate_text} aagt
654
                    ON aagt.id = aar.actionid
655
                 WHERE aar.actionname = 'generate_text'
656
                       AND aar.contextid = :contextid";
657
        $userlist->add_from_sql('userid', $sql, ['contextid' => $context->id]);
658
 
659
        // AI action generate image.
660
        $sql = "SELECT DISTINCT aar.userid
661
                  FROM {context} ctx
662
                  JOIN {ai_action_register} aar
663
                    ON aar.contextid = ctx.id
664
                  JOIN {ai_action_generate_image} aagi
665
                    ON aagi.id = aar.actionid
666
                 WHERE aar.actionname = 'generate_image'
667
                       AND aar.contextid = :contextid";
668
        $userlist->add_from_sql('userid', $sql, ['contextid' => $context->id]);
669
 
670
        // AI action summarise text.
671
        $sql = "SELECT DISTINCT aar.userid
672
                  FROM {context} ctx
673
                  JOIN {ai_action_register} aar
674
                    ON aar.contextid = ctx.id
675
                  JOIN {ai_action_summarise_text} aast
676
                    ON aast.id = aar.actionid
677
                 WHERE aar.actionname = 'summarise_text'
678
                       AND aar.contextid = :contextid";
679
        $userlist->add_from_sql('userid', $sql, ['contextid' => $context->id]);
680
 
681
        // AI action explain text.
682
        $sql = "SELECT DISTINCT aar.userid
683
                  FROM {context} ctx
684
                  JOIN {ai_action_register} aar
685
                    ON aar.contextid = ctx.id
686
                  JOIN {ai_action_explain_text} aaet
687
                    ON aaet.id = aar.actionid
688
                 WHERE aar.actionname = 'explain_text'
689
                       AND aar.contextid = :contextid";
690
        $userlist->add_from_sql('userid', $sql, ['contextid' => $context->id]);
691
    }
692
 
693
    /**
694
     * Delete multiple users within a single context.
695
     *
696
     * @param approved_userlist $userlist The approved context and user information to delete information for.
697
     */
698
    public static function delete_data_for_users(approved_userlist $userlist) {
699
        global $DB;
700
        $context = $userlist->get_context();
701
        $userids = $userlist->get_userids();
702
 
703
        [$useridssql, $useridsparams] = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
704
 
705
        $params = [
706
            'contextid' => $context->id,
707
        ];
708
        $params += $useridsparams;
709
 
710
        // Policy.
711
        $sql = "SELECT DISTINCT apr.id
712
                  FROM {ai_policy_register} apr
713
                  JOIN {context} ctx
714
                    ON apr.contextid = ctx.id
715
                 WHERE ctx.id = :contextid
716
                       AND apr.userid " . $useridssql;
717
        $policydetails = $DB->get_records_sql($sql, $params);
718
        if ($policydetails) {
719
            $DB->delete_records_list('ai_policy_register', 'id', array_keys($policydetails));
720
        }
721
 
722
        // AI action generate text.
723
        $sql = "SELECT DISTINCT aagt.id
724
                  FROM {ai_action_register} aar
725
                  JOIN {ai_action_generate_text} aagt
726
                    ON aar.actionid = aagt.id
727
                  JOIN {context} ctx
728
                    ON aar.contextid = ctx.id
729
                 WHERE aar.actionname = 'generate_text'
730
                       AND ctx.id = :contextid
731
                       AND aar.userid " . $useridssql;
732
        $aagtids = $DB->get_records_sql_menu($sql, $params);
733
        if ($aagtids) {
734
            [$aagtidsql, $aagtidparams] = $DB->get_in_or_equal(array_keys($aagtids), SQL_PARAMS_NAMED);
735
            $sql = "UPDATE {ai_action_generate_text}
736
                   SET prompt = '',
737
                       responseid = '',
738
                       fingerprint = '',
739
                       generatedcontent = ''
740
                 WHERE id " . $aagtidsql;
741
            $DB->execute($sql, $aagtidparams);
742
        }
743
 
744
        // AI action generate image.
745
        $sql = "SELECT DISTINCT aagi.id
746
                  FROM {ai_action_register} aar
747
                  JOIN {ai_action_generate_image} aagi
748
                    ON aar.actionid = aagi.id
749
                  JOIN {context} ctx
750
                    ON aar.contextid = ctx.id
751
                 WHERE aar.actionname = 'generate_image'
752
                       AND ctx.id = :contextid
753
                       AND aar.userid " . $useridssql;
754
        $aagiids = $DB->get_records_sql_menu($sql, $params);
755
        if ($aagiids) {
756
            [$aagiidsql, $aagiidparams] = $DB->get_in_or_equal(array_keys($aagiids), SQL_PARAMS_NAMED);
757
            $sql = "UPDATE {ai_action_generate_image}
758
                   SET prompt = '',
759
                       sourceurl = '',
760
                       revisedprompt = ''
761
                 WHERE id " . $aagiidsql;
762
            $DB->execute($sql, $aagiidparams);
763
        }
764
 
765
        // AI action summarise text.
766
        $sql = "SELECT DISTINCT aast.id
767
                  FROM {ai_action_register} aar
768
                  JOIN {ai_action_summarise_text} aast
769
                    ON aar.actionid = aast.id
770
                  JOIN {context} ctx
771
                    ON aar.contextid = ctx.id
772
                 WHERE aar.actionname = 'summarise_text'
773
                       AND ctx.id = :contextid
774
                       AND aar.userid " . $useridssql;
775
        $aastids = $DB->get_records_sql_menu($sql, $params);
776
        if ($aastids) {
777
            [$aastidsql, $aastidparams] = $DB->get_in_or_equal(array_keys($aastids), SQL_PARAMS_NAMED);
778
            $sql = "UPDATE {ai_action_summarise_text}
779
                   SET prompt = '',
780
                       responseid = '',
781
                       fingerprint = '',
782
                       generatedcontent = ''
783
                 WHERE id " . $aastidsql;
784
            $DB->execute($sql, $aastidparams);
785
        }
786
 
787
        // AI action explain text.
788
        $sql = "SELECT DISTINCT aaet.id
789
                  FROM {ai_action_register} aar
790
                  JOIN {ai_action_explain_text} aaet
791
                    ON aar.actionid = aaet.id
792
                  JOIN {context} ctx
793
                    ON aar.contextid = ctx.id
794
                 WHERE aar.actionname = 'explain_text'
795
                       AND ctx.id = :contextid
796
                       AND aar.userid " . $useridssql;
797
        $aaetids = $DB->get_records_sql_menu($sql, $params);
798
        if ($aaetids) {
799
            [$aaetidsql, $aaetidparams] = $DB->get_in_or_equal(array_keys($aaetids), SQL_PARAMS_NAMED);
800
            $sql = "UPDATE {ai_action_explain_text}
801
                   SET prompt = '',
802
                       responseid = '',
803
                       fingerprint = '',
804
                       generatedcontent = ''
805
                 WHERE id " . $aaetidsql;
806
            $DB->execute($sql, $aaetidparams);
807
        }
808
    }
809
}