xref: /plugin/approve/action/migration.php (revision 4474ed8a8edd55319eb6dd1e4e69fdb09925ebf0)
1*4474ed8aSSzymon Olewniczak<?php
2*4474ed8aSSzymon Olewniczak/**
3*4474ed8aSSzymon Olewniczak * DokuWiki Plugin bez (Action Component)
4*4474ed8aSSzymon Olewniczak *
5*4474ed8aSSzymon Olewniczak */
6*4474ed8aSSzymon Olewniczak
7*4474ed8aSSzymon Olewniczak// must be run within Dokuwiki
8*4474ed8aSSzymon Olewniczak
9*4474ed8aSSzymon Olewniczakuse dokuwiki\plugin\approve\meta\ApproveConst;
10*4474ed8aSSzymon Olewniczak
11*4474ed8aSSzymon Olewniczakif (!defined('DOKU_INC')) die();
12*4474ed8aSSzymon Olewniczak
13*4474ed8aSSzymon Olewniczak/**
14*4474ed8aSSzymon Olewniczak * Class action_plugin_bez_migration
15*4474ed8aSSzymon Olewniczak *
16*4474ed8aSSzymon Olewniczak * Handle migrations that need more than just SQL
17*4474ed8aSSzymon Olewniczak */
18*4474ed8aSSzymon Olewniczakclass action_plugin_approve_migration extends DokuWiki_Action_Plugin
19*4474ed8aSSzymon Olewniczak{
20*4474ed8aSSzymon Olewniczak    /**
21*4474ed8aSSzymon Olewniczak     * @inheritDoc
22*4474ed8aSSzymon Olewniczak     */
23*4474ed8aSSzymon Olewniczak    public function register(Doku_Event_Handler $controller)
24*4474ed8aSSzymon Olewniczak    {
25*4474ed8aSSzymon Olewniczak        $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'AFTER', $this, 'handle_migrations');
26*4474ed8aSSzymon Olewniczak    }
27*4474ed8aSSzymon Olewniczak
28*4474ed8aSSzymon Olewniczak    /**
29*4474ed8aSSzymon Olewniczak     * Call our custom migrations when defined
30*4474ed8aSSzymon Olewniczak     *
31*4474ed8aSSzymon Olewniczak     * @param Doku_Event $event
32*4474ed8aSSzymon Olewniczak     * @param $param
33*4474ed8aSSzymon Olewniczak     */
34*4474ed8aSSzymon Olewniczak    public function handle_migrations(Doku_Event $event, $param)
35*4474ed8aSSzymon Olewniczak    {
36*4474ed8aSSzymon Olewniczak        if ($event->data['sqlite']->getAdapter()->getDbname() !== 'approve') {
37*4474ed8aSSzymon Olewniczak            return;
38*4474ed8aSSzymon Olewniczak        }
39*4474ed8aSSzymon Olewniczak        $to = $event->data['to'];
40*4474ed8aSSzymon Olewniczak
41*4474ed8aSSzymon Olewniczak        if (is_callable([$this, "migration$to"])) {
42*4474ed8aSSzymon Olewniczak            $event->result = call_user_func([$this, "migration$to"], $event->data);
43*4474ed8aSSzymon Olewniczak        }
44*4474ed8aSSzymon Olewniczak    }
45*4474ed8aSSzymon Olewniczak
46*4474ed8aSSzymon Olewniczak    /**
47*4474ed8aSSzymon Olewniczak     * Convenience function to run an INSERT ... ON CONFLICT IGNORE operation
48*4474ed8aSSzymon Olewniczak     *
49*4474ed8aSSzymon Olewniczak     * The function takes a key-value array with the column names in the key and the actual value in the value,
50*4474ed8aSSzymon Olewniczak     * build the appropriate query and executes it.
51*4474ed8aSSzymon Olewniczak     *
52*4474ed8aSSzymon Olewniczak     * @param string $table the table the entry should be saved to (will not be escaped)
53*4474ed8aSSzymon Olewniczak     * @param array $entry A simple key-value pair array (only values will be escaped)
54*4474ed8aSSzymon Olewniczak     * @return bool|SQLiteResult
55*4474ed8aSSzymon Olewniczak     */
56*4474ed8aSSzymon Olewniczak    protected function insertOrIgnore(helper_plugin_sqlite $sqlite, $table, $entry) {
57*4474ed8aSSzymon Olewniczak        $keys = join(',', array_keys($entry));
58*4474ed8aSSzymon Olewniczak        $vals = join(',', array_fill(0,count($entry),'?'));
59*4474ed8aSSzymon Olewniczak
60*4474ed8aSSzymon Olewniczak        $sql = "INSERT OR IGNORE INTO $table ($keys) VALUES ($vals)";
61*4474ed8aSSzymon Olewniczak        return $sqlite->query($sql, array_values($entry));
62*4474ed8aSSzymon Olewniczak    }
63*4474ed8aSSzymon Olewniczak
64*4474ed8aSSzymon Olewniczak    protected function migration1($data)
65*4474ed8aSSzymon Olewniczak    {
66*4474ed8aSSzymon Olewniczak        global $conf;
67*4474ed8aSSzymon Olewniczak
68*4474ed8aSSzymon Olewniczak        /** @var helper_plugin_sqlite $sqlite */
69*4474ed8aSSzymon Olewniczak        $sqlite = $data['sqlite'];
70*4474ed8aSSzymon Olewniczak        $db = $sqlite->getAdapter()->getDb();
71*4474ed8aSSzymon Olewniczak
72*4474ed8aSSzymon Olewniczak
73*4474ed8aSSzymon Olewniczak        $datadir = $conf['datadir'];
74*4474ed8aSSzymon Olewniczak        if (substr($datadir, -1) != '/') {
75*4474ed8aSSzymon Olewniczak            $datadir .= '/';
76*4474ed8aSSzymon Olewniczak        }
77*4474ed8aSSzymon Olewniczak
78*4474ed8aSSzymon Olewniczak        $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($datadir));
79*4474ed8aSSzymon Olewniczak        $pages = [];
80*4474ed8aSSzymon Olewniczak        foreach ($rii as $file) {
81*4474ed8aSSzymon Olewniczak            if ($file->isDir()){
82*4474ed8aSSzymon Olewniczak                continue;
83*4474ed8aSSzymon Olewniczak            }
84*4474ed8aSSzymon Olewniczak
85*4474ed8aSSzymon Olewniczak            //remove start path and extension
86*4474ed8aSSzymon Olewniczak            $page = substr($file->getPathname(), strlen($datadir), -4);
87*4474ed8aSSzymon Olewniczak            $pages[] = str_replace('/', ':', $page);
88*4474ed8aSSzymon Olewniczak        }
89*4474ed8aSSzymon Olewniczak
90*4474ed8aSSzymon Olewniczak        $db->beginTransaction();
91*4474ed8aSSzymon Olewniczak
92*4474ed8aSSzymon Olewniczak        $apr_namespaces = preg_split('/\s+/', $this->getConf('apr_namespaces'),
93*4474ed8aSSzymon Olewniczak            -1,PREG_SPLIT_NO_EMPTY);
94*4474ed8aSSzymon Olewniczak
95*4474ed8aSSzymon Olewniczak        if (!$apr_namespaces) {
96*4474ed8aSSzymon Olewniczak            $sqlite->storeEntry('maintainer',[
97*4474ed8aSSzymon Olewniczak                'namespace' => '**'
98*4474ed8aSSzymon Olewniczak            ]);
99*4474ed8aSSzymon Olewniczak        } else {
100*4474ed8aSSzymon Olewniczak            foreach ($apr_namespaces as $namespace) {
101*4474ed8aSSzymon Olewniczak                $namespace = rtrim($namespace, ':');
102*4474ed8aSSzymon Olewniczak                $namespace .= ':**';
103*4474ed8aSSzymon Olewniczak                $sqlite->storeEntry('maintainer',[
104*4474ed8aSSzymon Olewniczak                    'namespace' => $namespace
105*4474ed8aSSzymon Olewniczak                ]);
106*4474ed8aSSzymon Olewniczak            }
107*4474ed8aSSzymon Olewniczak        }
108*4474ed8aSSzymon Olewniczak
109*4474ed8aSSzymon Olewniczak        //store config
110*4474ed8aSSzymon Olewniczak        $no_apr_namespaces = $this->getConf('no_apr_namespaces');
111*4474ed8aSSzymon Olewniczak        $sqlite->storeEntry('config',[
112*4474ed8aSSzymon Olewniczak            'key' => 'no_apr_namespaces',
113*4474ed8aSSzymon Olewniczak            'value' => $no_apr_namespaces
114*4474ed8aSSzymon Olewniczak        ]);
115*4474ed8aSSzymon Olewniczak
116*4474ed8aSSzymon Olewniczak        $no_apr_namespaces_list = preg_split('/\s+/', $no_apr_namespaces,-1,
117*4474ed8aSSzymon Olewniczak            PREG_SPLIT_NO_EMPTY);
118*4474ed8aSSzymon Olewniczak        $no_apr_namespaces_list = array_map(function ($namespace) {
119*4474ed8aSSzymon Olewniczak            return trim($namespace, ':');
120*4474ed8aSSzymon Olewniczak        }, $no_apr_namespaces_list);
121*4474ed8aSSzymon Olewniczak
122*4474ed8aSSzymon Olewniczak        foreach ($pages as $page) {
123*4474ed8aSSzymon Olewniczak            //import historic data
124*4474ed8aSSzymon Olewniczak            $versions = p_get_metadata($page, ApproveConst::METADATA_VERSIONS_KEY);
125*4474ed8aSSzymon Olewniczak            if (!$versions) {
126*4474ed8aSSzymon Olewniczak                $versions = $this->render_metadata_for_approved_page($page);
127*4474ed8aSSzymon Olewniczak            }
128*4474ed8aSSzymon Olewniczak
129*4474ed8aSSzymon Olewniczak//            $last_change_date = p_get_metadata($page, 'last_change date');
130*4474ed8aSSzymon Olewniczak            $last_change_date = @filemtime(wikiFN($page));
131*4474ed8aSSzymon Olewniczak            $last_version = $versions[0];
132*4474ed8aSSzymon Olewniczak
133*4474ed8aSSzymon Olewniczak            //remove current versions to not process it here
134*4474ed8aSSzymon Olewniczak            unset($versions[0]);
135*4474ed8aSSzymon Olewniczak            unset($versions[$last_change_date]);
136*4474ed8aSSzymon Olewniczak
137*4474ed8aSSzymon Olewniczak            foreach ($versions as $rev => $version) {
138*4474ed8aSSzymon Olewniczak                $data = [
139*4474ed8aSSzymon Olewniczak                    'page' => $page,
140*4474ed8aSSzymon Olewniczak                    'rev' => $rev,
141*4474ed8aSSzymon Olewniczak                    'approved' => date('c', $rev),
142*4474ed8aSSzymon Olewniczak                    'version' => $version
143*4474ed8aSSzymon Olewniczak                ];
144*4474ed8aSSzymon Olewniczak                $sqlite->storeEntry('revision', $data);
145*4474ed8aSSzymon Olewniczak            }
146*4474ed8aSSzymon Olewniczak
147*4474ed8aSSzymon Olewniczak            //process current data
148*4474ed8aSSzymon Olewniczak            $summary = p_get_metadata($page, 'last_change sum');
149*4474ed8aSSzymon Olewniczak            $data = [
150*4474ed8aSSzymon Olewniczak                'page' => $page,
151*4474ed8aSSzymon Olewniczak                'rev' => $last_change_date,
152*4474ed8aSSzymon Olewniczak                'current' => 1
153*4474ed8aSSzymon Olewniczak            ];
154*4474ed8aSSzymon Olewniczak            if ($this->getConf('ready_for_approval') &&
155*4474ed8aSSzymon Olewniczak                $summary == $this->getConf('sum ready for approval')) {
156*4474ed8aSSzymon Olewniczak                $data['ready_for_approval'] = date('c', $last_change_date);
157*4474ed8aSSzymon Olewniczak            } elseif($summary == $this->getConf('sum approved')) {
158*4474ed8aSSzymon Olewniczak                $data['approved'] = date('c', $last_change_date);
159*4474ed8aSSzymon Olewniczak                $data['version'] = $last_version;
160*4474ed8aSSzymon Olewniczak            }
161*4474ed8aSSzymon Olewniczak            $sqlite->storeEntry('revision', $data);
162*4474ed8aSSzymon Olewniczak
163*4474ed8aSSzymon Olewniczak
164*4474ed8aSSzymon Olewniczak            //empty apr_namespaces - all match
165*4474ed8aSSzymon Olewniczak            if (!$apr_namespaces) {
166*4474ed8aSSzymon Olewniczak                $in_apr_namespace = true;
167*4474ed8aSSzymon Olewniczak            } else {
168*4474ed8aSSzymon Olewniczak                $in_apr_namespace = false;
169*4474ed8aSSzymon Olewniczak                foreach ($apr_namespaces as $namespace) {
170*4474ed8aSSzymon Olewniczak                    if (substr($page, 0, strlen($namespace)) == $namespace) {
171*4474ed8aSSzymon Olewniczak                        $in_apr_namespace = true;
172*4474ed8aSSzymon Olewniczak                        break;
173*4474ed8aSSzymon Olewniczak                    }
174*4474ed8aSSzymon Olewniczak                }
175*4474ed8aSSzymon Olewniczak            }
176*4474ed8aSSzymon Olewniczak
177*4474ed8aSSzymon Olewniczak            if ($in_apr_namespace) {
178*4474ed8aSSzymon Olewniczak                $hidden = '0';
179*4474ed8aSSzymon Olewniczak                foreach ($no_apr_namespaces_list as $namespace) {
180*4474ed8aSSzymon Olewniczak                    if (substr($page, 0, strlen($namespace)) == $namespace) {
181*4474ed8aSSzymon Olewniczak                        $hidden = '1';
182*4474ed8aSSzymon Olewniczak                        break;
183*4474ed8aSSzymon Olewniczak                    }
184*4474ed8aSSzymon Olewniczak                }
185*4474ed8aSSzymon Olewniczak                $sqlite->storeEntry('page', [
186*4474ed8aSSzymon Olewniczak                    'page' => $page,
187*4474ed8aSSzymon Olewniczak                    'hidden' => $hidden
188*4474ed8aSSzymon Olewniczak                ]);
189*4474ed8aSSzymon Olewniczak            }
190*4474ed8aSSzymon Olewniczak        }
191*4474ed8aSSzymon Olewniczak
192*4474ed8aSSzymon Olewniczak
193*4474ed8aSSzymon Olewniczak        $db->commit();
194*4474ed8aSSzymon Olewniczak
195*4474ed8aSSzymon Olewniczak        return true;
196*4474ed8aSSzymon Olewniczak    }
197*4474ed8aSSzymon Olewniczak
198*4474ed8aSSzymon Olewniczak    /**
199*4474ed8aSSzymon Olewniczak     * Calculate current version
200*4474ed8aSSzymon Olewniczak     *
201*4474ed8aSSzymon Olewniczak     * @param $id
202*4474ed8aSSzymon Olewniczak     * @return array
203*4474ed8aSSzymon Olewniczak     */
204*4474ed8aSSzymon Olewniczak    protected function render_metadata_for_approved_page($id, $currev=false) {
205*4474ed8aSSzymon Olewniczak        if (!$currev) $currev = @filemtime(wikiFN($id));
206*4474ed8aSSzymon Olewniczak
207*4474ed8aSSzymon Olewniczak        $version = $this->approved($id);
208*4474ed8aSSzymon Olewniczak        //version for current page
209*4474ed8aSSzymon Olewniczak        $curver = $version + 1;
210*4474ed8aSSzymon Olewniczak        $versions = array(0 => $curver, $currev => $curver);
211*4474ed8aSSzymon Olewniczak
212*4474ed8aSSzymon Olewniczak        $changelog = new PageChangeLog($id);
213*4474ed8aSSzymon Olewniczak        $first = 0;
214*4474ed8aSSzymon Olewniczak        $num = 100;
215*4474ed8aSSzymon Olewniczak        while (count($revs = $changelog->getRevisions($first, $num)) > 0) {
216*4474ed8aSSzymon Olewniczak            foreach ($revs as $rev) {
217*4474ed8aSSzymon Olewniczak                $revInfo = $changelog->getRevisionInfo($rev);
218*4474ed8aSSzymon Olewniczak                if ($revInfo['sum'] == $this->getConf('sum approved')) {
219*4474ed8aSSzymon Olewniczak                    $versions[$rev] = $version;
220*4474ed8aSSzymon Olewniczak                    $version -= 1;
221*4474ed8aSSzymon Olewniczak                }
222*4474ed8aSSzymon Olewniczak            }
223*4474ed8aSSzymon Olewniczak            $first += $num;
224*4474ed8aSSzymon Olewniczak        }
225*4474ed8aSSzymon Olewniczak
226*4474ed8aSSzymon Olewniczak//        p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions));
227*4474ed8aSSzymon Olewniczak
228*4474ed8aSSzymon Olewniczak        return $versions;
229*4474ed8aSSzymon Olewniczak    }
230*4474ed8aSSzymon Olewniczak
231*4474ed8aSSzymon Olewniczak    /**
232*4474ed8aSSzymon Olewniczak     * Get the number of approved pages
233*4474ed8aSSzymon Olewniczak     * @param $id
234*4474ed8aSSzymon Olewniczak     * @return int
235*4474ed8aSSzymon Olewniczak     */
236*4474ed8aSSzymon Olewniczak    protected function approved($id) {
237*4474ed8aSSzymon Olewniczak        $count = 0;
238*4474ed8aSSzymon Olewniczak
239*4474ed8aSSzymon Olewniczak        $changelog = new PageChangeLog($id);
240*4474ed8aSSzymon Olewniczak        $first = 0;
241*4474ed8aSSzymon Olewniczak        $num = 100;
242*4474ed8aSSzymon Olewniczak        while (count($revs = $changelog->getRevisions($first, $num)) > 0) {
243*4474ed8aSSzymon Olewniczak            foreach ($revs as $rev) {
244*4474ed8aSSzymon Olewniczak                $revInfo = $changelog->getRevisionInfo($rev);
245*4474ed8aSSzymon Olewniczak                if ($revInfo['sum'] == $this->getConf('sum approved')) {
246*4474ed8aSSzymon Olewniczak                    $count += 1;
247*4474ed8aSSzymon Olewniczak                }
248*4474ed8aSSzymon Olewniczak            }
249*4474ed8aSSzymon Olewniczak            $first += $num;
250*4474ed8aSSzymon Olewniczak        }
251*4474ed8aSSzymon Olewniczak
252*4474ed8aSSzymon Olewniczak        return $count;
253*4474ed8aSSzymon Olewniczak    }
254*4474ed8aSSzymon Olewniczak}
255