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 tiny_autosave;
18
 
19
use stdClass;
20
 
21
/**
22
 * Autosave Manager.
23
 *
24
 * @package   tiny_autosave
25
 * @copyright 2022 Andrew Lyons <andrew@nicols.co.uk>
26
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27
 */
28
class autosave_manager {
29
 
30
    /** @var int The contextid */
31
    protected $contextid;
32
 
33
    /** @var string The page hash reference */
34
    protected $pagehash;
35
 
36
    /** @var string The page instance reference */
37
    protected $pageinstance;
38
 
39
    /** @var string The elementid for this editor */
40
    protected $elementid;
41
 
42
    /** @var stdClass The user record */
43
    protected $user;
44
 
45
    /**
46
     * Constructor for the autosave manager.
47
     *
48
     * @param int $contextid The contextid of the session
49
     * @param string $pagehash The page hash
50
     * @param string $pageinstance The page instance
51
     * @param string $elementid The element id
52
     * @param null|stdClass $user The user object for the owner of the autosave
53
     */
54
    public function __construct(
55
        int $contextid,
56
        string $pagehash,
57
        string $pageinstance,
58
        string $elementid,
59
        ?stdClass $user = null
60
    ) {
61
        global $USER;
62
 
63
        $this->contextid = $contextid;
64
        $this->pagehash = $pagehash;
65
        $this->pageinstance = $pageinstance;
66
        $this->elementid = $elementid;
67
        $this->user = $user ?? $USER;
68
    }
69
 
70
    /**
71
     * Get the autosave record for this session.
72
     *
73
     * @return stdClass|null
74
     */
75
    public function get_autosave_record(): ?stdClass {
76
        global $DB;
77
 
78
        $record = $DB->get_record('tiny_autosave', [
79
            'contextid' => $this->contextid,
80
            'userid' => $this->user->id,
81
            'pagehash' => $this->pagehash,
82
            'elementid' => $this->elementid,
83
        ]);
84
 
85
        if (empty($record)) {
86
            return null;
87
        }
88
 
89
        return $record;
90
    }
91
 
92
    /**
93
     * Create an autosave record for the session.
94
     *
95
     * @param string $drafttext The draft text to save
96
     * @param null|int $draftid The draft file area if one is used
97
     * @return stdClass The autosave record
98
     */
99
    public function create_autosave_record(string $drafttext, ?int $draftid = null): stdClass {
100
        global $DB;
101
        $record = (object) [
102
            'userid' => $this->user->id,
103
            'contextid' => $this->contextid,
104
            'pagehash' => $this->pagehash,
105
            'pageinstance' => $this->pageinstance,
106
            'elementid' => $this->elementid,
107
            'drafttext' => $drafttext,
108
            'timemodified' => time(),
109
        ];
110
 
111
        if ($draftid) {
112
            $record->draftid = $draftid;
113
        }
114
 
115
        $record->id = $DB->insert_record('tiny_autosave', $record);
116
 
117
        return $record;
118
    }
119
 
120
    /**
121
     * Update the text of the autosave session.
122
     *
123
     * @param string $drafttext The text to save
124
     * @return stdClass The updated record
125
     */
126
    public function update_autosave_record(string $drafttext): stdClass {
127
        global $DB;
128
 
129
        $record = $this->get_autosave_record();
130
        if ($record) {
131
            $record->drafttext = $drafttext;
132
            $record->timemodified = time();
133
            $DB->update_record('tiny_autosave', $record);
134
 
135
            return $record;
136
        } else {
137
            return $this->create_autosave_record($drafttext);
138
        }
139
    }
140
 
141
    /**
142
     * Resume an autosave session, updating the draft file area if relevant.
143
     *
144
     * @param null|int $draftid The draft file area to update
145
     * @return stdClass The updated autosave record
146
     */
147
    public function resume_autosave_session(?int $draftid = null): stdClass {
148
        $record = $this->get_autosave_record();
149
        if (!$record) {
150
            return $this->create_autosave_record('', $draftid);
151
        }
152
 
153
        if ($this->is_autosave_stale($record)) {
154
            // If the autosave record it stale, remove it and create a new, blank, record.
155
            $this->remove_autosave_record();
156
 
157
            return $this->create_autosave_record('', $draftid);
158
        }
159
 
160
        if (empty($draftid)) {
161
            // There is no file area to handle, so just return the record without any further changes.
162
            return $record;
163
        }
164
 
165
        // This autosave is not stale, so update the draftid and move any files over to the new draft file area.
166
        return $this->update_draftid_for_record($record, $draftid);
167
    }
168
 
169
    /**
170
     * Check whether the autosave data is stale.
171
     *
172
     * Records are considered stale if either of the following conditions are true:
173
     * - The record is older than the stale period
174
     * - Any of the files in the draft area are newer than the autosave data itself
175
     *
176
     * @param stdClass $record The autosave record
177
     * @return bool Whether the record is stale
178
     */
179
    protected function is_autosave_stale(stdClass $record): bool {
180
        $timemodified = $record->timemodified;
181
        // TODO Create the UI for the stale period.
182
        $staleperiod = get_config('tiny_autosave', 'staleperiod');
183
        if (empty($staleperiod)) {
184
            $staleperiod = (4 * DAYSECS);
185
        }
186
 
187
        $stale = $timemodified < (time() - $staleperiod);
188
 
189
        if (empty($record->draftid)) {
190
            return $stale;
191
        }
192
 
193
        $fs = get_file_storage();
194
        $files = $fs->get_directory_files($record->contextid, 'user', 'draft', $record->draftid, '/', true, true);
195
 
196
        $lastfilemodified = 0;
197
        foreach ($files as $file) {
198
            if ($record->timemodified < $file->get_timemodified()) {
199
                $stale = true;
200
                break;
201
            }
202
        }
203
 
204
        return $stale;
205
    }
206
 
207
    /**
208
     * Move the files relating to the autosave session to a new draft file area.
209
     *
210
     * @param stdClass $record The autosave record
211
     * @param int $newdraftid The new draftid to move files to
212
     * @return stdClass The updated autosave record
213
     */
214
    protected function update_draftid_for_record(stdClass $record, int $newdraftid): stdClass {
215
        global $CFG, $DB;
216
 
217
        require_once("{$CFG->libdir}/filelib.php");
218
 
219
        // Copy all draft files from the old draft area.
220
        $usercontext = \context_user::instance($this->user->id);
221
 
222
        // This function copies all the files in one draft area, to another area (in this case it's
223
        // another draft area). It also rewrites the text to @@PLUGINFILE@@ links.
224
        $record->drafttext = file_save_draft_area_files(
225
            $record->draftid,
226
            $usercontext->id,
227
            'user',
228
            'draft',
229
            $newdraftid,
230
            [],
231
            $record->drafttext
232
        );
233
 
234
        // Final rewrite to the new draft area (convert the @@PLUGINFILES@@ again).
235
        $record->drafttext = file_rewrite_pluginfile_urls(
236
            $record->drafttext,
237
            'draftfile.php',
238
            $usercontext->id,
239
            'user',
240
            'draft',
241
            $newdraftid
242
        );
243
 
244
        $record->draftid = $newdraftid;
245
        $record->pageinstance = $this->pageinstance;
246
        $record->timemodified = time();
247
 
248
        $DB->update_record('tiny_autosave', $record);
249
 
250
        return $record;
251
    }
252
 
253
    /**
254
     * Remove the autosave record.
255
     */
256
    public function remove_autosave_record(): void {
257
        global $DB;
258
 
259
        $DB->delete_records('tiny_autosave', [
260
            'contextid' => $this->contextid,
261
            'userid' => $this->user->id,
262
            'pagehash' => $this->pagehash,
263
            'elementid' => $this->elementid,
264
        ]);
265
    }
266
 
267
}