Skip to content

Commit 106a252

Browse files
sh-csgPhMemmel
authored andcommitted
MBS-10543: Backup and restore (#2)
1 parent 1d4d307 commit 106a252

File tree

4 files changed

+367
-0
lines changed

4 files changed

+367
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
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+
defined('MOODLE_INTERNAL') || die();
18+
19+
require_once($CFG->dirroot . '/mod/aichat/backup/moodle2/backup_aichat_stepslib.php');
20+
21+
/**
22+
* Backup class for mod_aichat
23+
*
24+
* @package mod_aichat
25+
* @copyright 2026 ISB Bayern
26+
* @author Stefan Hanauska <stefan.hanauska@csg-in.de>
27+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28+
*/
29+
class backup_aichat_activity_task extends backup_activity_task {
30+
/**
31+
* Does nothing.
32+
*
33+
* @return void
34+
*/
35+
protected function define_my_settings() {
36+
}
37+
38+
/**
39+
* Add step.
40+
*
41+
* @return void
42+
*/
43+
protected function define_my_steps() {
44+
$this->add_step(new backup_aichat_structure_step('aichat', 'aichat.xml'));
45+
}
46+
47+
/**
48+
* This plugin has no fileareas yet.
49+
*
50+
* @return array
51+
*/
52+
public function get_fileareas() {
53+
return [];
54+
}
55+
56+
/**
57+
* Returns the unchanged parameter.
58+
*
59+
* @param string $content
60+
* @return string
61+
*/
62+
public static function encode_content_links($content) {
63+
global $CFG;
64+
65+
$base = preg_quote($CFG->wwwroot, '/');
66+
67+
$search = '/(' . $base . '\/mod\/aichat\/view.php\?id=)([0-9]+)/';
68+
$content = preg_replace($search, '$@AICHATVIEWBYID*$2@$', $content);
69+
70+
return $content;
71+
}
72+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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+
* Backup steps for mod_aichat.
19+
*
20+
* @package mod_aichat
21+
* @copyright 2026 ISB Bayern
22+
* @author Stefan Hanauska <stefan.hanauska@csg-in.de>
23+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24+
*/
25+
class backup_aichat_structure_step extends backup_activity_structure_step {
26+
/**
27+
* Define structure.
28+
*/
29+
protected function define_structure() {
30+
$userinfo = $this->get_setting_value('users');
31+
32+
// Wrapper without any attributes.
33+
$aichat = new backup_nested_element('aichat', ['id'], ['course', 'name', 'intro', 'introformat', 'timemodified']);
34+
35+
$personas = new backup_nested_element('personas');
36+
$personacolumns = ['name', 'prompt', 'userinfo', 'type', 'timecreated', 'timemodified'];
37+
if ($userinfo) {
38+
$personacolumns[] = 'userid';
39+
}
40+
$persona = new backup_nested_element('persona', ['id'], $personacolumns);
41+
42+
$personasselected = new backup_nested_element('personas_selected');
43+
$personaselected = new backup_nested_element('persona_selected', ['id'], ['personasid', 'contextid']);
44+
45+
$chatoptions = new backup_nested_element('chat_options');
46+
$chatoption = new backup_nested_element('chat_option', ['id'], ['name', 'value', 'contextid']);
47+
48+
// Prepare the structure.
49+
$wrapper = $this->prepare_activity_structure($aichat);
50+
51+
$aichat->add_child($personas);
52+
$personas->add_child($persona);
53+
54+
$aichat->add_child($personasselected);
55+
$personasselected->add_child($personaselected);
56+
57+
$aichat->add_child($chatoptions);
58+
$chatoptions->add_child($chatoption);
59+
60+
// Define sources.
61+
$aichat->set_source_table('aichat', ['id' => backup::VAR_ACTIVITYID]);
62+
$persona->set_source_sql(
63+
'
64+
SELECT p.id, p.' . implode(', p.', $personacolumns) . '
65+
FROM {block_ai_chat_personas} p, {block_ai_chat_personas_selected} ps
66+
WHERE p.id = ps.personasid
67+
AND ps.contextid = ?',
68+
[backup::VAR_CONTEXTID]
69+
);
70+
$personaselected->set_source_table('block_ai_chat_personas_selected', ['contextid' => backup::VAR_CONTEXTID]);
71+
$chatoption->set_source_table('block_ai_chat_options', ['contextid' => backup::VAR_CONTEXTID]);
72+
73+
$aichat->annotate_files('mod_aichat', 'intro', null);
74+
75+
return $wrapper;
76+
}
77+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
defined('MOODLE_INTERNAL') || die();
18+
19+
require_once($CFG->dirroot . '/mod/aichat/backup/moodle2/restore_aichat_stepslib.php');
20+
21+
/**
22+
* Restore class for mod_aichat
23+
*
24+
* @package mod_aichat
25+
* @copyright 2026 ISB Bayern
26+
* @author Stefan Hanauska <stefan.hanauska@csg-in.de>
27+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28+
*/
29+
class restore_aichat_activity_task extends restore_activity_task {
30+
/**
31+
* Does nothing.
32+
*
33+
* @return void
34+
*/
35+
protected function define_my_settings() {
36+
}
37+
38+
/**
39+
* Does nothing.
40+
*
41+
* @return void
42+
*/
43+
protected function define_my_steps() {
44+
$this->add_step(new restore_aichat_structure_step('aichat', 'aichat.xml'));
45+
}
46+
47+
/**
48+
* This plugin has no fileareas yet.
49+
*
50+
* @return array
51+
*/
52+
public function get_fileareas() {
53+
return [];
54+
}
55+
56+
/**
57+
* Encode links only in intro field.
58+
*
59+
* @return array
60+
*/
61+
public static function define_decode_contents() {
62+
$contents = [];
63+
64+
$contents[] = new restore_decode_content('aichat', ['intro'], 'aichat');
65+
66+
return $contents;
67+
}
68+
69+
/**
70+
* Encode links to view page.
71+
*
72+
* @return array
73+
*/
74+
public static function define_decode_rules() {
75+
$rules = [];
76+
$rules[] = new restore_decode_rule('AICHATVIEWBYID', '/mod/aichat/view.php?id=$1', 'course_module');
77+
78+
return $rules;
79+
}
80+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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+
use block_ai_chat\local\persona;
18+
19+
/**
20+
* Restore steps for mod_aichat.
21+
*
22+
* @package mod_aichat
23+
* @copyright 2026 ISB Bayern
24+
* @author Stefan Hanauska <stefan.hanauska@csg-in.de>
25+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26+
*/
27+
class restore_aichat_structure_step extends restore_activity_structure_step {
28+
/**
29+
* Define structure.
30+
*/
31+
protected function define_structure() {
32+
$paths = [];
33+
$paths[] = new restore_path_element('aichat', '/activity/aichat');
34+
$paths[] = new restore_path_element('persona', '/activity/aichat/personas/persona');
35+
$paths[] = new restore_path_element('persona_selected', '/activity/aichat/personas_selected/persona_selected');
36+
$paths[] = new restore_path_element('chat_option', '/activity/aichat/chat_options/chat_option');
37+
38+
return $this->prepare_activity_structure($paths);
39+
}
40+
41+
/**
42+
* Process an aichat element. Nothing to do here yet as there is no data to restore.
43+
*
44+
* @param array $data
45+
*/
46+
protected function process_aichat($data) {
47+
global $DB;
48+
$data = (object)$data;
49+
$oldid = $data->id;
50+
$data->course = $this->get_courseid();
51+
$newid = $DB->insert_record('aichat', $data);
52+
$this->set_mapping('aichat', $oldid, $newid);
53+
$this->apply_activity_instance($newid);
54+
}
55+
56+
/**
57+
* Extra actions to take once restore is complete.
58+
*/
59+
protected function after_execute(): void {
60+
$this->add_related_files('mod_aichat', 'intro', null);
61+
}
62+
63+
/**
64+
* Process a persona element.
65+
*
66+
* @param array $data
67+
*/
68+
protected function process_persona($data) {
69+
global $DB;
70+
71+
$userinfo = $this->get_setting_value('users');
72+
73+
// If no userinfo, map to current user.
74+
if (!$userinfo) {
75+
$data['userid'] = $this->task->get_userid();
76+
} else {
77+
$data['userid'] = $this->get_mappingid('user', $data['userid']);
78+
}
79+
80+
$search = [
81+
'name' => $data['name'],
82+
'prompt' => $data['prompt'],
83+
'type' => $data['type'],
84+
'userinfo' => $data['userinfo'],
85+
];
86+
87+
$where = 'name = :name AND type = :type';
88+
89+
if ($data['type'] != persona::TYPE_TEMPLATE) {
90+
// For user-specific personas, add userid to search.
91+
$search['userid'] = $data['userid'];
92+
$where .= ' AND userid = :userid';
93+
}
94+
95+
$where .= ' AND ' . $DB->sql_compare_text('prompt') . ' = ' . $DB->sql_compare_text(':prompt');
96+
$where .= ' AND ' . $DB->sql_compare_text('userinfo') . ' = ' . $DB->sql_compare_text(':userinfo');
97+
98+
$persona = $DB->get_record_select('block_ai_chat_personas', $where, $search, 'id', IGNORE_MULTIPLE | IGNORE_MISSING);
99+
if ($persona) {
100+
// Persona already exists, map to existing record.
101+
$this->set_mapping('block_ai_chat_personas', $data['id'], $persona->id);
102+
return;
103+
}
104+
$data = (object)$data;
105+
// Restored personas are always of type user.
106+
$data->type = persona::TYPE_USER;
107+
$oldid = $data->id;
108+
$data->userid = $this->task->get_userid();
109+
110+
$newid = $DB->insert_record('block_ai_chat_personas', $data);
111+
$this->set_mapping('block_ai_chat_personas', $oldid, $newid);
112+
}
113+
114+
/**
115+
* Process a persona_selected element.
116+
*
117+
* @param array $data
118+
*/
119+
protected function process_persona_selected($data) {
120+
global $DB;
121+
$data = (object)$data;
122+
$data->contextid = $this->task->get_contextid();
123+
$data->personasid = $this->get_mappingid('block_ai_chat_personas', $data->personasid);
124+
$DB->insert_record('block_ai_chat_personas_selected', $data);
125+
}
126+
127+
/**
128+
* Process a chat_option element.
129+
*
130+
* @param array $data
131+
*/
132+
protected function process_chat_option($data) {
133+
global $DB;
134+
$data = (object)$data;
135+
$data->contextid = $this->task->get_contextid();
136+
$DB->insert_record('block_ai_chat_options', $data);
137+
}
138+
}

0 commit comments

Comments
 (0)