xref: /plugin/approve/helper/db.php (revision 4e9ce638a9a0f294b89bf81c62e7f6e786fe33f1)
14474ed8aSSzymon Olewniczak<?php
24474ed8aSSzymon Olewniczak
3e72eb5b8SSzymon Olewniczakuse dokuwiki\Extension\AuthPlugin;
4e72eb5b8SSzymon Olewniczakuse dokuwiki\Extension\Plugin;
5e72eb5b8SSzymon Olewniczakuse dokuwiki\plugin\sqlite\SQLiteDB;
64474ed8aSSzymon Olewniczak
7b59355cdSSzymon Olewniczakclass helper_plugin_approve_db extends Plugin
84474ed8aSSzymon Olewniczak{
9e72eb5b8SSzymon Olewniczak    protected $db;
104474ed8aSSzymon Olewniczak
11e72eb5b8SSzymon Olewniczak    protected $no_apr_namespaces_array;
12e72eb5b8SSzymon Olewniczak
134474ed8aSSzymon Olewniczak    public function __construct()
144474ed8aSSzymon Olewniczak    {
15e72eb5b8SSzymon Olewniczak        $this->db = new SQLiteDB('approve', DOKU_PLUGIN . 'approve/db/');
16e72eb5b8SSzymon Olewniczak        $no_apr_namespaces = $this->getConf('no_apr_namespaces');
17e72eb5b8SSzymon Olewniczak        $this->no_apr_namespaces_array  = array_map(function ($namespace) {
18e72eb5b8SSzymon Olewniczak            return ltrim($namespace, ':');
19e72eb5b8SSzymon Olewniczak        }, preg_split('/\s+/', $no_apr_namespaces,-1,PREG_SPLIT_NO_EMPTY));
20e72eb5b8SSzymon Olewniczak        $this->initNoApproveNamespaces();
214474ed8aSSzymon Olewniczak    }
224474ed8aSSzymon Olewniczak
23e72eb5b8SSzymon Olewniczak    public function getDbFile(): string
244474ed8aSSzymon Olewniczak    {
25e72eb5b8SSzymon Olewniczak        return $this->db->getDbFile();
264474ed8aSSzymon Olewniczak    }
274474ed8aSSzymon Olewniczak
28e72eb5b8SSzymon Olewniczak    protected function initNoApproveNamespaces(): void
29e72eb5b8SSzymon Olewniczak    {
30e72eb5b8SSzymon Olewniczak        $config_key = 'no_apr_namespaces';
31e72eb5b8SSzymon Olewniczak        $db_value = $this->getDbConf($config_key);
32e72eb5b8SSzymon Olewniczak        $config_value = $this->getConf('no_apr_namespaces');
33e72eb5b8SSzymon Olewniczak        if ($db_value !== $config_value) { // $db_value might be null. In this case run the commit anyway.
34e72eb5b8SSzymon Olewniczak            $this->db->getPdo()->beginTransaction();
35e72eb5b8SSzymon Olewniczak            $this->setDbConf($config_key, $config_value);
36e72eb5b8SSzymon Olewniczak            $pages_meta = $this->getPagesMetadata();
37e72eb5b8SSzymon Olewniczak            foreach ($pages_meta as $page_meta) {
38e72eb5b8SSzymon Olewniczak                $page_id = $page_meta['page'];
39e72eb5b8SSzymon Olewniczak                $hidden = (int) $this->pageInHiddenNamespace($page_id);
40e72eb5b8SSzymon Olewniczak                $this->setPageHiddenStatus($page_id, $hidden);
414474ed8aSSzymon Olewniczak            }
42e72eb5b8SSzymon Olewniczak            $this->db->getPdo()->commit();
434474ed8aSSzymon Olewniczak        }
44e72eb5b8SSzymon Olewniczak    }
454474ed8aSSzymon Olewniczak
46e72eb5b8SSzymon Olewniczak    public function getPagesMetadata(): array
47e72eb5b8SSzymon Olewniczak    {
48e72eb5b8SSzymon Olewniczak        $sql = 'SELECT page, approver, hidden FROM page';
49e72eb5b8SSzymon Olewniczak        return $this->db->queryAll($sql);
504474ed8aSSzymon Olewniczak    }
51e72eb5b8SSzymon Olewniczak
52e72eb5b8SSzymon Olewniczak    public function getPageMetadata(string $page_id): ?array
53e72eb5b8SSzymon Olewniczak    {
54e72eb5b8SSzymon Olewniczak        $sql = 'SELECT approver FROM page WHERE page=? AND hidden != 1';
55e72eb5b8SSzymon Olewniczak        return $this->db->queryRecord($sql, $page_id);
564474ed8aSSzymon Olewniczak    }
57e72eb5b8SSzymon Olewniczak
58e72eb5b8SSzymon Olewniczak    public function getDbConf(string $key): ?string
59e72eb5b8SSzymon Olewniczak    {
60e72eb5b8SSzymon Olewniczak        $sql = 'SELECT value FROM config WHERE key=?';
61e72eb5b8SSzymon Olewniczak        return $this->db->queryValue($sql, $key);
62e72eb5b8SSzymon Olewniczak    }
63e72eb5b8SSzymon Olewniczak
64e72eb5b8SSzymon Olewniczak    public function setDbConf(string $key, string $value): void
65e72eb5b8SSzymon Olewniczak    {
66e72eb5b8SSzymon Olewniczak        $this->db->saveRecord('config', ['key' => $key, 'value' => $value]);
674474ed8aSSzymon Olewniczak    }
684474ed8aSSzymon Olewniczak
694474ed8aSSzymon Olewniczak    /**
70e72eb5b8SSzymon Olewniczak     * @param string $page_id
71e72eb5b8SSzymon Olewniczak     * @param int $hidden Must be int since SQLite doesn't suport bool type.
72e72eb5b8SSzymon Olewniczak     * @return void
734474ed8aSSzymon Olewniczak     */
74e72eb5b8SSzymon Olewniczak    public function setPageHiddenStatus(string $page_id, int $hidden): void
75e72eb5b8SSzymon Olewniczak    {
76e72eb5b8SSzymon Olewniczak        $sql = 'UPDATE page SET hidden=? WHERE page=?';
77e72eb5b8SSzymon Olewniczak        $this->db->query($sql, $hidden, $page_id);
78e72eb5b8SSzymon Olewniczak    }
79e72eb5b8SSzymon Olewniczak
80e72eb5b8SSzymon Olewniczak    public function updatePagesAssignments(): void
81e72eb5b8SSzymon Olewniczak    {
82e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->beginTransaction();
83e72eb5b8SSzymon Olewniczak
84e72eb5b8SSzymon Olewniczak        // clean current settings
85e72eb5b8SSzymon Olewniczak        $this->db->query('DELETE FROM page');
86e72eb5b8SSzymon Olewniczak
87e72eb5b8SSzymon Olewniczak        $wikiPages = $this->getWikiPages();
88e72eb5b8SSzymon Olewniczak        foreach ($wikiPages as $id) {
89e72eb5b8SSzymon Olewniczak            // update revision information
90e72eb5b8SSzymon Olewniczak            $this->updatePage($id);
91e72eb5b8SSzymon Olewniczak        }
92e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->commit();
93e72eb5b8SSzymon Olewniczak    }
94e72eb5b8SSzymon Olewniczak
95e72eb5b8SSzymon Olewniczak    public function getWikiPages(): array
964474ed8aSSzymon Olewniczak    {
974474ed8aSSzymon Olewniczak        global $conf;
98e72eb5b8SSzymon Olewniczak
99e72eb5b8SSzymon Olewniczak        $datadir = realpath($conf['datadir']);  // path without ending "/"
100e72eb5b8SSzymon Olewniczak        $directory = new RecursiveDirectoryIterator($datadir, FilesystemIterator::SKIP_DOTS);
101e72eb5b8SSzymon Olewniczak        $iterator = new RecursiveIteratorIterator($directory);
102e72eb5b8SSzymon Olewniczak
103e72eb5b8SSzymon Olewniczak        $pages = [];
104e72eb5b8SSzymon Olewniczak        /** @var SplFileInfo $fileinfo */
105e72eb5b8SSzymon Olewniczak        foreach ($iterator as $fileinfo) {
106e72eb5b8SSzymon Olewniczak            if (!$fileinfo->isFile()) continue;
107e72eb5b8SSzymon Olewniczak
108e72eb5b8SSzymon Olewniczak            $path = $fileinfo->getRealPath(); // it should return "/" both on windows and linux
109e72eb5b8SSzymon Olewniczak            // remove dir part
110e72eb5b8SSzymon Olewniczak            $path = substr($path, strlen($datadir));
111e72eb5b8SSzymon Olewniczak            // make file a dokuwiki path
112e72eb5b8SSzymon Olewniczak            $id = pathID($path);
113e72eb5b8SSzymon Olewniczak            $pages[] = $id;
1144474ed8aSSzymon Olewniczak        }
115e72eb5b8SSzymon Olewniczak
116e72eb5b8SSzymon Olewniczak        return $pages;
1174474ed8aSSzymon Olewniczak    }
118e72eb5b8SSzymon Olewniczak
119e72eb5b8SSzymon Olewniczak    public function weightedAssignments(): array
120e72eb5b8SSzymon Olewniczak    {
121e72eb5b8SSzymon Olewniczak        $assignments = $this->db->queryAll('SELECT id, namespace, approver FROM maintainer');
122e72eb5b8SSzymon Olewniczak
123e72eb5b8SSzymon Olewniczak        $weighted_assignments = [];
124e72eb5b8SSzymon Olewniczak        foreach ($assignments as $assignment) {
125e72eb5b8SSzymon Olewniczak            $ns = $assignment['namespace'];
126e72eb5b8SSzymon Olewniczak            // more general namespaces are overridden by more specific ones.
127e72eb5b8SSzymon Olewniczak            if (substr($ns, -1) == '*') {
128e72eb5b8SSzymon Olewniczak                $weight = substr_count($ns, ':');
129e72eb5b8SSzymon Olewniczak            } else {
130e72eb5b8SSzymon Olewniczak                $weight = PHP_INT_MAX;
131e72eb5b8SSzymon Olewniczak            }
132e72eb5b8SSzymon Olewniczak
133e72eb5b8SSzymon Olewniczak            $assignment['weight'] = $weight;
134e72eb5b8SSzymon Olewniczak            $weighted_assignments[] = $assignment;
135e72eb5b8SSzymon Olewniczak        }
136e72eb5b8SSzymon Olewniczak        array_multisort(array_column($weighted_assignments, 'weight'), $weighted_assignments);
137e72eb5b8SSzymon Olewniczak
138e72eb5b8SSzymon Olewniczak        return $weighted_assignments;
1394474ed8aSSzymon Olewniczak    }
1404474ed8aSSzymon Olewniczak
1414474ed8aSSzymon Olewniczak    /**
142e72eb5b8SSzymon Olewniczak     * Returns approver or null if page is not in $weighted_assignments.
143e72eb5b8SSzymon Olewniczak     * Approver can be empty string.
1444474ed8aSSzymon Olewniczak     *
145e72eb5b8SSzymon Olewniczak     * @param string $page_id
146e72eb5b8SSzymon Olewniczak     * @param array $weighted_assignments
147e72eb5b8SSzymon Olewniczak     * @return string
1484474ed8aSSzymon Olewniczak     */
149e72eb5b8SSzymon Olewniczak    public function getPageAssignment(string $page_id, array $weighted_assignments): ?string
1504474ed8aSSzymon Olewniczak    {
151e72eb5b8SSzymon Olewniczak        $page_approver = null;
152e72eb5b8SSzymon Olewniczak        foreach ($weighted_assignments as $assignment) {
153e72eb5b8SSzymon Olewniczak            $ns = ltrim($assignment['namespace'], ':');
154e72eb5b8SSzymon Olewniczak            $approver = $assignment['approver'];
155e72eb5b8SSzymon Olewniczak            if (substr($ns, -2) == '**') {
156e72eb5b8SSzymon Olewniczak                //remove '**'
157e72eb5b8SSzymon Olewniczak                $ns = substr($ns, 0, -2);
158e72eb5b8SSzymon Olewniczak                if (substr($page_id, 0, strlen($ns)) == $ns) {
159e72eb5b8SSzymon Olewniczak                    $page_approver = $approver;
1604474ed8aSSzymon Olewniczak                }
161e72eb5b8SSzymon Olewniczak            } elseif (substr($ns, -1) == '*') {
162e72eb5b8SSzymon Olewniczak                //remove '*'
163e72eb5b8SSzymon Olewniczak                $ns = substr($ns, 0, -1);
164e72eb5b8SSzymon Olewniczak                $noNS = substr($page_id, strlen($ns));
165e72eb5b8SSzymon Olewniczak                if (strpos($noNS, ':') === FALSE &&
166e72eb5b8SSzymon Olewniczak                    substr($page_id, 0, strlen($ns)) == $ns) {
167e72eb5b8SSzymon Olewniczak                    $page_approver = $approver;
1684474ed8aSSzymon Olewniczak                }
169e72eb5b8SSzymon Olewniczak            } elseif($page_id == $ns) {
170e72eb5b8SSzymon Olewniczak                $page_approver = $approver;
1714474ed8aSSzymon Olewniczak            }
1724474ed8aSSzymon Olewniczak        }
173e72eb5b8SSzymon Olewniczak        return $page_approver;
174e72eb5b8SSzymon Olewniczak    }
1754474ed8aSSzymon Olewniczak
176e72eb5b8SSzymon Olewniczak    public function pageInHiddenNamespace(string $page_id): bool
177e72eb5b8SSzymon Olewniczak    {
178e72eb5b8SSzymon Olewniczak        $page_id = ltrim($page_id, ':');
179e72eb5b8SSzymon Olewniczak        foreach ($this->no_apr_namespaces_array as $namespace) {
180e72eb5b8SSzymon Olewniczak            if (substr($page_id, 0, strlen($namespace)) == $namespace) {
181e72eb5b8SSzymon Olewniczak                return true;
182e72eb5b8SSzymon Olewniczak            }
183e72eb5b8SSzymon Olewniczak        }
184e72eb5b8SSzymon Olewniczak        return false;
185e72eb5b8SSzymon Olewniczak    }
186e72eb5b8SSzymon Olewniczak
187e72eb5b8SSzymon Olewniczak    public function getPages(string $user='', array $states=['approved', 'draft', 'ready_for_approval'],
188e72eb5b8SSzymon Olewniczak                             string $namespace='', string $filter=''): array
189e72eb5b8SSzymon Olewniczak    {
190e72eb5b8SSzymon Olewniczak        /* @var AuthPlugin $auth */
191e72eb5b8SSzymon Olewniczak        global $auth;
192e72eb5b8SSzymon Olewniczak
193e72eb5b8SSzymon Olewniczak        $sql = 'SELECT page.page AS id, page.approver, revision.rev, revision.approved, revision.approved_by,
194e72eb5b8SSzymon Olewniczak                    revision.ready_for_approval, revision.ready_for_approval_by,
195e72eb5b8SSzymon Olewniczak                    LENGTH(page.page) - LENGTH(REPLACE(page.page, \':\', \'\')) AS colons
196e72eb5b8SSzymon Olewniczak                    FROM page INNER JOIN revision ON page.page = revision.page
197e72eb5b8SSzymon Olewniczak                    WHERE page.hidden = 0 AND revision.current=1 AND page.page GLOB ? AND page.page REGEXP ?
198e72eb5b8SSzymon Olewniczak                    ORDER BY colons, page.page';
199e72eb5b8SSzymon Olewniczak        $pages = $this->db->queryAll($sql, $namespace.'*', $filter);
200e72eb5b8SSzymon Olewniczak
201e72eb5b8SSzymon Olewniczak        // add status to the page
202e72eb5b8SSzymon Olewniczak        $pages = array_map([$this, 'setPageStatus'], $pages);
203e72eb5b8SSzymon Olewniczak
204e72eb5b8SSzymon Olewniczak        if ($user !== '') {
205e72eb5b8SSzymon Olewniczak            $user_data = $auth->getUserData($user);
206e72eb5b8SSzymon Olewniczak            $user_groups = $user_data['grps'];
207e72eb5b8SSzymon Olewniczak            $pages = array_filter($pages, function ($page) use ($user, $user_groups) {
208e72eb5b8SSzymon Olewniczak                return $page['approver'][0] == '@' && in_array(substr($page['approver'], 1), $user_groups) ||
209e72eb5b8SSzymon Olewniczak                    $page['approver'] == $user;
210e72eb5b8SSzymon Olewniczak            });
211e72eb5b8SSzymon Olewniczak        }
212e72eb5b8SSzymon Olewniczak
213e72eb5b8SSzymon Olewniczak        // filter by status
214e72eb5b8SSzymon Olewniczak        $pages = array_filter($pages, function ($page) use ($states) {
215e72eb5b8SSzymon Olewniczak            return in_array($page['status'], $states);
216e72eb5b8SSzymon Olewniczak        });
217e72eb5b8SSzymon Olewniczak
218e72eb5b8SSzymon Olewniczak        return $pages;
219e72eb5b8SSzymon Olewniczak    }
220e72eb5b8SSzymon Olewniczak
221e72eb5b8SSzymon Olewniczak    public function getPageRevisions(string $page_id): array {
222e72eb5b8SSzymon Olewniczak        $sql = 'SELECT page AS id, rev, approved, approved_by, ready_for_approval, ready_for_approval_by
223e72eb5b8SSzymon Olewniczak                        FROM revision WHERE page=?';
224e72eb5b8SSzymon Olewniczak        $revisions = $this->db->queryAll($sql, $page_id);
225e72eb5b8SSzymon Olewniczak        // add status to the page
226e72eb5b8SSzymon Olewniczak        $revisions = array_map([$this, 'setPageStatus'], $revisions);
227e72eb5b8SSzymon Olewniczak
228e72eb5b8SSzymon Olewniczak        return $revisions;
229e72eb5b8SSzymon Olewniczak    }
230e72eb5b8SSzymon Olewniczak
231e72eb5b8SSzymon Olewniczak    public function getPageRevision(string $page_id, int $rev): ?array
232e72eb5b8SSzymon Olewniczak    {
233e72eb5b8SSzymon Olewniczak        $sql = 'SELECT ready_for_approval, ready_for_approval_by, approved, approved_by, version
234e72eb5b8SSzymon Olewniczak                                FROM revision WHERE page=? AND rev=?';
235e72eb5b8SSzymon Olewniczak        $page = $this->db->queryRecord($sql, $page_id, $rev);
236e72eb5b8SSzymon Olewniczak
237e72eb5b8SSzymon Olewniczak        if ($page == null) {
238e72eb5b8SSzymon Olewniczak            $page = [
239e72eb5b8SSzymon Olewniczak                'ready_for_approval' => null,
240e72eb5b8SSzymon Olewniczak                'ready_for_approval_by' => null,
241e72eb5b8SSzymon Olewniczak                'approved' => null,
242e72eb5b8SSzymon Olewniczak                'approved_by' => null
243e72eb5b8SSzymon Olewniczak            ];
244e72eb5b8SSzymon Olewniczak        }
245e72eb5b8SSzymon Olewniczak        $page['id'] = $page_id;
246e72eb5b8SSzymon Olewniczak        $page['rev'] = $rev;
247e72eb5b8SSzymon Olewniczak        $page = $this->setPageStatus($page);
248e72eb5b8SSzymon Olewniczak
249e72eb5b8SSzymon Olewniczak        return $page;
250e72eb5b8SSzymon Olewniczak    }
251e72eb5b8SSzymon Olewniczak
252e72eb5b8SSzymon Olewniczak    protected function setPageStatus(array $page): array
253e72eb5b8SSzymon Olewniczak    {
254e72eb5b8SSzymon Olewniczak        if ($page['approved'] !== null) {
255e72eb5b8SSzymon Olewniczak            $page['status'] = 'approved';
256e72eb5b8SSzymon Olewniczak        } elseif ($page['ready_for_approval'] !== null) {
257e72eb5b8SSzymon Olewniczak            $page['status'] = 'ready_for_approval';
258e72eb5b8SSzymon Olewniczak        } else {
259e72eb5b8SSzymon Olewniczak            $page['status'] = 'draft';
260e72eb5b8SSzymon Olewniczak        }
261e72eb5b8SSzymon Olewniczak        return $page;
262e72eb5b8SSzymon Olewniczak    }
263e72eb5b8SSzymon Olewniczak
264e72eb5b8SSzymon Olewniczak    public function moveRevisionHistory(string $old_page_id, string $new_page_id): void
265e72eb5b8SSzymon Olewniczak    {
266e72eb5b8SSzymon Olewniczak        $this->db->exec('UPDATE revision SET page=? WHERE page=?', $new_page_id, $old_page_id);
267e72eb5b8SSzymon Olewniczak    }
268e72eb5b8SSzymon Olewniczak
269e72eb5b8SSzymon Olewniczak    public function getLastDbRev(string $page_id, ?string $status=null): ?int
270e72eb5b8SSzymon Olewniczak    {
271e72eb5b8SSzymon Olewniczak        if ($status == 'approved') {
272e72eb5b8SSzymon Olewniczak            $sql = 'SELECT rev FROM revision WHERE page=? AND approved IS NOT NULL ORDER BY rev DESC LIMIT 1';
273e72eb5b8SSzymon Olewniczak            return $this->db->queryValue($sql, $page_id);
274e72eb5b8SSzymon Olewniczak        } elseif ($status == 'ready_for_approval') {
275e72eb5b8SSzymon Olewniczak            $sql = 'SELECT rev FROM revision WHERE page=? AND ready_for_approval IS NOT NULL ORDER BY rev DESC LIMIT 1';
276e72eb5b8SSzymon Olewniczak            return $this->db->queryValue($sql, $page_id);
277e72eb5b8SSzymon Olewniczak        }
278e72eb5b8SSzymon Olewniczak        $sql = 'SELECT rev FROM revision WHERE page=? AND current=1';
279e72eb5b8SSzymon Olewniczak        return $this->db->queryValue($sql, $page_id);
280e72eb5b8SSzymon Olewniczak    }
281e72eb5b8SSzymon Olewniczak
282e72eb5b8SSzymon Olewniczak    public function setApprovedStatus(string $page_id): void
283e72eb5b8SSzymon Olewniczak    {
284e72eb5b8SSzymon Olewniczak        global $INFO;
285e72eb5b8SSzymon Olewniczak
286e72eb5b8SSzymon Olewniczak        // approved IS NULL prevents from overriding already approved page
287e72eb5b8SSzymon Olewniczak        $sql = 'UPDATE revision SET approved=?, approved_by=?,
288e72eb5b8SSzymon Olewniczak                    version=(SELECT IFNULL(MAX(version), 0) FROM revision WHERE page=?) + 1
289e72eb5b8SSzymon Olewniczak                WHERE page=? AND current=1 AND approved IS NULL';
290e72eb5b8SSzymon Olewniczak        $this->db->exec($sql, date('c'), $INFO['client'], $page_id, $page_id);
291e72eb5b8SSzymon Olewniczak    }
292e72eb5b8SSzymon Olewniczak
293e72eb5b8SSzymon Olewniczak    public function setReadyForApprovalStatus(string $page_id): void
294e72eb5b8SSzymon Olewniczak    {
295e72eb5b8SSzymon Olewniczak        global $INFO;
296e72eb5b8SSzymon Olewniczak
297e72eb5b8SSzymon Olewniczak        // approved IS NULL prevents from overriding already approved page
298e72eb5b8SSzymon Olewniczak        $sql = 'UPDATE revision SET ready_for_approval=?, ready_for_approval_by=?
299e72eb5b8SSzymon Olewniczak                WHERE page=? AND current=1 AND ready_for_approval IS NULL';
300e72eb5b8SSzymon Olewniczak        $this->db->exec($sql, date('c'), $INFO['client'], $page_id);
301e72eb5b8SSzymon Olewniczak    }
302e72eb5b8SSzymon Olewniczak
303e72eb5b8SSzymon Olewniczak    protected function deletePage($page_id): void
304e72eb5b8SSzymon Olewniczak    {
305e72eb5b8SSzymon Olewniczak        // delete information about availability of a page but keep the history
306e72eb5b8SSzymon Olewniczak        $this->db->exec('DELETE FROM page WHERE page=?', $page_id);
307e72eb5b8SSzymon Olewniczak        $this->db->exec('DELETE FROM revision WHERE page=? AND approved IS NULL AND ready_for_approval IS NULL'
308e72eb5b8SSzymon Olewniczak            , $page_id);
309e72eb5b8SSzymon Olewniczak        $this->db->exec('UPDATE revision SET current=0 WHERE page=? AND current=1', $page_id);
310e72eb5b8SSzymon Olewniczak    }
311e72eb5b8SSzymon Olewniczak
312e72eb5b8SSzymon Olewniczak    public function handlePageDelete(string $page_id): void
313e72eb5b8SSzymon Olewniczak    {
314e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->beginTransaction();
315e72eb5b8SSzymon Olewniczak        $this->deletePage($page_id);
316e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->commit();
317e72eb5b8SSzymon Olewniczak    }
318e72eb5b8SSzymon Olewniczak
319e72eb5b8SSzymon Olewniczak    protected function updatePage(string $page_id): void
320e72eb5b8SSzymon Olewniczak    {
321e72eb5b8SSzymon Olewniczak        // delete all unimportant revisions
322e72eb5b8SSzymon Olewniczak        $this->db->exec('DELETE FROM revision WHERE page=? AND approved IS NULL AND ready_for_approval IS NULL'
323e72eb5b8SSzymon Olewniczak            , $page_id);
324e72eb5b8SSzymon Olewniczak
325e72eb5b8SSzymon Olewniczak        $weighted_assignments = $this->weightedAssignments();
326e72eb5b8SSzymon Olewniczak        $approver = $this->getPageAssignment($page_id, $weighted_assignments);
327e72eb5b8SSzymon Olewniczak        if ($approver !== null) {
328e72eb5b8SSzymon Olewniczak            $data = [
329e72eb5b8SSzymon Olewniczak                'page' => $page_id,
330e72eb5b8SSzymon Olewniczak                'hidden' => (int) $this->pageInHiddenNamespace($page_id),
331e72eb5b8SSzymon Olewniczak                'approver' => $approver
332e72eb5b8SSzymon Olewniczak            ];
333*4e9ce638SSzymon Olewniczak            $this->db->saveRecord('page', $data);  // insert or replace
334e72eb5b8SSzymon Olewniczak        }
335e72eb5b8SSzymon Olewniczak
336e72eb5b8SSzymon Olewniczak        $last_change_date = @filemtime(wikiFN($page_id));
337*4e9ce638SSzymon Olewniczak        // record for current revision exists
338*4e9ce638SSzymon Olewniczak        $sql = 'SELECT 1 FROM revision WHERE page=? AND rev=?';
339*4e9ce638SSzymon Olewniczak        $exists = $this->db->queryValue($sql, $page_id, $last_change_date);
340*4e9ce638SSzymon Olewniczak        if ($exists === null) {
341*4e9ce638SSzymon Olewniczak            // mark previous revision as old. this may be already deleted by DELETE
342*4e9ce638SSzymon Olewniczak            $this->db->exec('UPDATE revision SET current=0 WHERE page=? AND current=1', $page_id);
343*4e9ce638SSzymon Olewniczak            // create new record
344e72eb5b8SSzymon Olewniczak            $this->db->saveRecord('revision', [
345e72eb5b8SSzymon Olewniczak                'page' => $page_id,
346e72eb5b8SSzymon Olewniczak                'rev' => $last_change_date,
347e72eb5b8SSzymon Olewniczak                'current' => 1
348e72eb5b8SSzymon Olewniczak            ]);
349e72eb5b8SSzymon Olewniczak        }
350e72eb5b8SSzymon Olewniczak
351*4e9ce638SSzymon Olewniczak    }
352*4e9ce638SSzymon Olewniczak
353e72eb5b8SSzymon Olewniczak    public function handlePageEdit(string $page_id): void
354e72eb5b8SSzymon Olewniczak    {
355e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->beginTransaction();
356e72eb5b8SSzymon Olewniczak        $this->updatePage($page_id);
357e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->commit();
358e72eb5b8SSzymon Olewniczak    }
359e72eb5b8SSzymon Olewniczak
360e72eb5b8SSzymon Olewniczak    public function deleteMaintainer(int $maintainer_id): void
361e72eb5b8SSzymon Olewniczak    {
362e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->beginTransaction();
363e72eb5b8SSzymon Olewniczak        $this->db->exec('DELETE FROM maintainer WHERE id=?', $maintainer_id);
364e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->commit();
365e72eb5b8SSzymon Olewniczak    }
366e72eb5b8SSzymon Olewniczak
367e72eb5b8SSzymon Olewniczak    public function addMaintainer(string $namespace, string $approver): void
368e72eb5b8SSzymon Olewniczak    {
369e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->beginTransaction();
370e72eb5b8SSzymon Olewniczak        $this->db->saveRecord('maintainer', [
371e72eb5b8SSzymon Olewniczak            'namespace' => $namespace,
372e72eb5b8SSzymon Olewniczak            'approver' => $approver
373e72eb5b8SSzymon Olewniczak        ]);
374e72eb5b8SSzymon Olewniczak        $this->db->getPdo()->commit();
375e72eb5b8SSzymon Olewniczak    }
376b59355cdSSzymon Olewniczak
377b59355cdSSzymon Olewniczak    public function getMaintainers(): ?array
378b59355cdSSzymon Olewniczak    {
379b59355cdSSzymon Olewniczak        $sql = 'SELECT id, namespace, approver FROM maintainer ORDER BY namespace';
380b59355cdSSzymon Olewniczak        return $this->db->queryAll($sql);
381b59355cdSSzymon Olewniczak    }
382e72eb5b8SSzymon Olewniczak}
383