Proyectos de Subversion Moodle

Rev

| 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
namespace mod_bigbluebuttonbn\task;
18
 
19
use core\task\adhoc_task;
20
use core\task\manager;
21
use Matrix\Exception;
22
use mod_bigbluebuttonbn\instance;
23
use mod_bigbluebuttonbn\local\proxy\recording_proxy;
24
use mod_bigbluebuttonbn\logger;
25
use mod_bigbluebuttonbn\recording;
26
use moodle_exception;
27
 
28
/**
29
 * Class containing the scheduled task for converting recordings for the BigBlueButton version 2.5 in Moodle 4.0.
30
 *
31
 * @package   mod_bigbluebuttonbn
32
 * @copyright 2021 Jesus Federico, Blindside Networks Inc <jesus at blindsidenetworks dot com>
33
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
34
 */
35
class upgrade_recordings_task extends adhoc_task {
36
    /**
37
     * Run the migration task.
38
     */
39
    public function execute() {
40
        $info = $this->get_custom_data();
41
        $meetingid = $info->meetingid;
42
        $isimported = $info->isimported ?? 0;
43
        $this->process_bigbluebuttonbn_logs($meetingid, $isimported);
44
    }
45
 
46
    /**
47
     * Process all bigbluebuttonbn logs looking for entries which should be converted to meetings.
48
     *
49
     * @param string $meetingid
50
     * @param bool $isimported
51
     * @return bool Whether any more logs are waiting to be processed
52
     * @throws \dml_exception
53
     * @throws moodle_exception
54
     */
55
    protected function process_bigbluebuttonbn_logs(string $meetingid, bool $isimported): bool {
56
        global $DB;
57
 
58
        $classname = static::class;
59
        mtrace("Executing {$classname} for meeting {$meetingid}...");
60
 
61
        // Fetch the logs queued for upgrade.
62
        mtrace("Fetching logs for conversion");
63
        // Each log is ordered by timecreated.
64
        [$select, $params] = $this->get_sql_query_for_logs($meetingid, $isimported);
65
        $logsrs = $DB->get_recordset_select('bigbluebuttonbn_logs',
66
            $select,
67
            $params,
68
            'timecreated DESC',
69
            'id, meetingid, timecreated, log');
70
 
71
        if (!$logsrs->valid()) {
72
            mtrace("No logs were found for conversion.");
73
            // No more logs. Stop queueing.
74
            return false;
75
        }
76
        // Retrieve recordings from the servers for this meeting.
77
        $recordings = recording_proxy::fetch_recording_by_meeting_id([$meetingid]);
78
        // Sort recordings by meetingId, then startTime.
79
        uasort($recordings, function($a, $b) {
80
            return $b['startTime'] - $a['startTime'];
81
        });
82
 
83
        // Create an instance of bigbluebuttonbn_recording per valid recording.
84
        mtrace("Creating new recording records...");
85
        $recordingcount = 0;
86
        foreach ($recordings as $recordingid => $recording) {
87
            $importeddata = $isimported ? '' : json_encode($recording);
88
            try {
89
                $instance = instance::get_from_meetingid($recording['meetingID']);
90
            } catch (Exception $e) {
91
                mtrace("Unable to parse meetingID " . $e->getMessage());
92
                continue;
93
            }
94
 
95
            if ($instance) {
96
                $newrecording = [
97
                    'courseid' => $instance->get_course_id(),
98
                    'bigbluebuttonbnid' => $instance->get_instance_id(),
99
                    'groupid' => $instance->get_group_id(), // The groupid should be taken from the meetingID.
100
                    'recordingid' => $recordingid,
101
                    'status' => recording::RECORDING_STATUS_PROCESSED,
102
                ];
103
            } else {
104
                mtrace("Unable to find an activity for {$recording['meetingID']}. This recording is headless.");
105
                // This instance does not exist any more.
106
                // Use the data in the log instead of the instance.
107
                $meetingdata = instance::parse_meetingid($recording['meetingID']);
108
                $newrecording = [
109
                    'courseid' => $meetingdata['courseid'],
110
                    'bigbluebuttonbnid' => $meetingdata['instanceid'],
111
                    'groupid' => 0,
112
                    'recordingid' => $recordingid,
113
                    'status' => recording::RECORDING_STATUS_PROCESSED,
114
                ];
115
 
116
                if (array_key_exists('groupid', $meetingdata)) {
117
                    $newrecording['groupid'] = $meetingdata['groupid'];
118
                }
119
            }
120
 
121
            if ($DB->record_exists('bigbluebuttonbn_recordings', $newrecording)) {
122
                mtrace("A recording already exists for {$recording['recordID']}. Skipping.");
123
                // A recording matching these characteristics alreay exists.
124
                continue;
125
            }
126
            // Recording has not been imported, check if we still have more logs.
127
            // We try to guess which logs matches which recordings are they are classed in the same order.
128
            // But  this is just an attempt.
129
            $log = null;
130
            if ($logsrs->valid()) {
131
                $log = $logsrs->current();
132
                $logsrs->next();
133
            }
134
            $timecreated = empty($log) ? time() : $log->timecreated;
135
            $newrecording['imported'] = $isimported;
136
            $newrecording['headless'] = 0;
137
            $newrecording['importeddata'] = $importeddata;
138
            $newrecording['timecreated'] = $newrecording['timemodified'] = $timecreated;
139
 
140
            // If we could not match with a log, we still create the recording.
141
            $DB->insert_record('bigbluebuttonbn_recordings', $newrecording);
142
            $recordingcount++;
143
        }
144
        mtrace("Migrated {$recordingcount} recordings.");
145
        // Now deactivate logs by marking all of them as migrated.
146
        // Reason for this is that we don't want to run another migration here and we don't know
147
        // which logs matches which recordings.
148
        $DB->set_field_select('bigbluebuttonbn_logs', 'log',
149
            $isimported ? logger::EVENT_IMPORT_MIGRATED : logger::EVENT_CREATE_MIGRATED,
150
            $select,
151
            $params
152
        );
153
        $logsrs->close();
154
        return true;
155
    }
156
 
157
    /**
158
     * Get the query (records_select) for the logs to convert.
159
     *
160
     * Each log is ordered by timecreated.
161
     *
162
     * @param string $meetingid
163
     * @param bool $isimported
164
     * @return array
165
     */
166
    protected function get_sql_query_for_logs(string $meetingid, bool $isimported): array {
167
        global $DB;
168
        if ($isimported) {
169
            return [
170
                'log = :logmatch AND meetingid = :meetingid',
171
                ['logmatch' => logger::EVENT_IMPORT, 'meetingid' => $meetingid],
172
            ];
173
        }
174
        return [
175
            'log = :logmatch AND meetingid = :meetingid AND ' . $DB->sql_like('meta', ':match'),
176
            [
177
                'logmatch' => logger::EVENT_CREATE,
178
                'match' => '%true%',
179
                'meetingid' => $meetingid
180
            ],
181
        ];
182
    }
183
 
184
    /**
185
     * Schedule all upgrading tasks.
186
     *
187
     * @param bool $importedrecordings
188
     * @return void
189
     * @throws \dml_exception
190
     */
191
    public static function schedule_upgrade_per_meeting($importedrecordings = false) {
192
        global $DB;
193
        $meetingids = $DB->get_fieldset_sql(
194
            'SELECT DISTINCT meetingid FROM {bigbluebuttonbn_logs} WHERE log = :createorimport',
195
            ['createorimport' => $importedrecordings ? logger::EVENT_IMPORT : logger::EVENT_CREATE]
196
        );
197
        foreach ($meetingids as $mid) {
198
            $createdrecordingtask = new static();
199
            $createdrecordingtask->set_custom_data((object) ['meetingid' => $mid, 'isimported' => $importedrecordings]);
200
            manager::queue_adhoc_task($createdrecordingtask);
201
        }
202
    }
203
}