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