xref: /plugin/ireadit/action/migration.php (revision cd2b00adb478e89bc6f39b8d09ab6fdf5ba8f8a4)
1<?php
2/**
3 * DokuWiki Plugin bez (Action Component)
4 *
5 */
6
7// must be run within Dokuwiki
8
9if (!defined('DOKU_INC')) die();
10
11/**
12 * Class action_plugin_bez_migration
13 *
14 * Handle migrations that need more than just SQL
15 */
16class action_plugin_ireadit_migration extends DokuWiki_Action_Plugin
17{
18    /**
19     * @inheritDoc
20     */
21    public function register(Doku_Event_Handler $controller)
22    {
23        $controller->register_hook('PLUGIN_SQLITE_DATABASE_UPGRADE', 'AFTER', $this, 'handle_migrations');
24    }
25
26    /**
27     * Call our custom migrations when defined
28     *
29     * @param Doku_Event $event
30     * @param $param
31     */
32    public function handle_migrations(Doku_Event $event, $param)
33    {
34        if ($event->data['sqlite']->getAdapter()->getDbname() !== 'ireadit') {
35            return;
36        }
37        $to = $event->data['to'];
38
39        if (is_callable([$this, "migration$to"])) {
40            $event->result = call_user_func([$this, "migration$to"], $event->data);
41        }
42    }
43
44    /**
45     * Convenience function to run an INSERT ... ON CONFLICT IGNORE operation
46     *
47     * The function takes a key-value array with the column names in the key and the actual value in the value,
48     * build the appropriate query and executes it.
49     *
50     * @param string $table the table the entry should be saved to (will not be escaped)
51     * @param array $entry A simple key-value pair array (only values will be escaped)
52     * @return bool|SQLiteResult
53     */
54    protected function insertOrIgnore(helper_plugin_sqlite $sqlite, $table, $entry) {
55        $keys = join(',', array_keys($entry));
56        $vals = join(',', array_fill(0,count($entry),'?'));
57
58        $sql = "INSERT OR IGNORE INTO $table ($keys) VALUES ($vals)";
59        return $sqlite->query($sql, array_values($entry));
60    }
61
62    protected function migration5($data)
63    {
64        /** @var DokuWiki_Auth_Plugin */
65        global $auth;
66
67        /** @var helper_plugin_sqlite $sqlite */
68        $sqlite = $data['sqlite'];
69        $db = $sqlite->getAdapter()->getDb();
70
71        /** @var helper_plugin_ireadit $helper */
72        $helper = plugin_load('helper', 'ireadit');
73
74        //remove old rows
75        $sqlite->query('DELETE FROM ireadit WHERE timestamp IS NULL');
76
77        $res = $sqlite->query('SELECT page,meta FROM meta');
78        while ($row = $sqlite->res_fetch_assoc($res)) {
79            $page = $row['page'];
80            $meta = json_decode($row['meta'], true);
81            $user_set = $helper->users_set($meta);
82            $last_change_date = p_get_metadata($page, 'last_change date');
83
84            $users = $auth->retrieveUsers();
85            foreach ($users as $user => $info) {
86                $res2 = $sqlite->query('SELECT user FROM ireadit WHERE page=? AND rev=? AND user=?', $page, $last_change_date, $user);
87                $existsAlready = $sqlite->res2single($res2);
88                if (!$existsAlready && in_array($user, $user_set)) {
89                    $sqlite->storeEntry('ireadit', [
90                        'page' => $page,
91                        'rev' => $last_change_date,
92                        'user' => $user
93                    ]);
94                }
95            }
96        }
97    }
98
99    protected function migration3($data)
100    {
101        global $conf;
102
103        /** @var helper_plugin_sqlite $sqlite */
104        $sqlite = $data['sqlite'];
105        $db = $sqlite->getAdapter()->getDb();
106
107        $res = $sqlite->query('SELECT page,meta FROM meta');
108        while ($row = $sqlite->res_fetch_assoc($res)) {
109            $last_change_date = p_get_metadata($row['page'], 'last_change date');
110            $sqlite->storeEntry('meta2', [
111                'page' => $row['page'],
112                'meta' => $row['meta'],
113                'last_change_date' => $last_change_date
114            ]);
115        }
116        $sqlite->query('DROP TABLE meta');
117        $sqlite->query('ALTER TABLE meta2 RENAME TO meta');
118    }
119
120    protected function migration2($data)
121    {
122        global $conf;
123
124        /** @var helper_plugin_sqlite $sqlite */
125        $sqlite = $data['sqlite'];
126        $db = $sqlite->getAdapter()->getDb();
127
128        /* @var \helper_plugin_ireadit $helper */
129        $helper = plugin_load('helper', 'ireadit');
130
131
132        $datadir = $conf['datadir'];
133        if (substr($datadir, -1) != '/') {
134            $datadir .= '/';
135        }
136
137        $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($datadir));
138        $pages = [];
139        foreach ($rii as $file) {
140            if ($file->isDir()){
141                continue;
142            }
143
144            //remove start path and extension
145            $page = substr($file->getPathname(), strlen($datadir), -4);
146            $pages[] = str_replace('/', ':', $page);
147        }
148
149        $db->beginTransaction();
150
151        foreach ($pages as $page) {
152            //import historic data
153            $meta = p_get_metadata($page, 'plugin ireadit');
154            if (!$meta) continue;
155
156            $sqlite->storeEntry('meta', [
157                'page' => $page,
158                'meta' => json_encode($meta)
159            ]);
160        }
161        $db->commit();
162
163
164    }
165
166    protected function migration1($data)
167    {
168        global $conf;
169
170        /** @var helper_plugin_sqlite $sqlite */
171        $sqlite = $data['sqlite'];
172        $db = $sqlite->getAdapter()->getDb();
173
174        /* @var \helper_plugin_ireadit $helper */
175        $helper = plugin_load('helper', 'ireadit');
176
177
178        $datadir = $conf['datadir'];
179        if (substr($datadir, -1) != '/') {
180            $datadir .= '/';
181        }
182
183        $rii = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($datadir));
184        $pages = [];
185        foreach ($rii as $file) {
186            if ($file->isDir()){
187                continue;
188            }
189
190            //remove start path and extension
191            $page = substr($file->getPathname(), strlen($datadir), -4);
192            $pages[] = str_replace('/', ':', $page);
193        }
194        $db->beginTransaction();
195
196        foreach ($pages as $page) {
197            //import historic data
198            $meta = p_get_metadata($page, 'plugin_ireadit');
199            if (!$meta) continue; //no metadata or new metadata format
200
201            foreach ($meta as $rev => $data) {
202                if ($rev === '' || count($data) == 0) continue;
203                foreach ($data as $user_read) {
204                    $sqlite->storeEntry('ireadit', [
205                        'page' => $page,
206                        'rev' => $rev,
207                        'user' => $user_read['client'],
208                        'timestamp' => date('c', $user_read['time'])
209                    ]);
210                }
211            }
212
213            //import current data
214            $content = file_get_contents($datadir . str_replace(':', '/', $page) . '.txt');
215            $status = preg_match('/~~IREADIT.*~~/', $content, $matches);
216            //no ireadit on page
217            if ($status !== 1) continue;
218
219            $match = trim(substr($matches[0], strlen('~~IREADIT'), -2));
220            $splits = preg_split('/\s+/', $match, -1, PREG_SPLIT_NO_EMPTY);
221
222            $users = [];
223            $groups = [];
224            foreach ($splits as $split) {
225                if ($split[0] == '@') {
226                    $group = substr($split, 1);
227                    $groups[] = $group;
228                } else {
229                    $users[] = $split;
230                }
231            }
232
233            $usersToInsert = $helper->users_set($users, $groups);
234
235            if ($usersToInsert) {
236                $last_change_date = p_get_metadata($page, 'last_change date');
237                foreach ($usersToInsert as $user) {
238                    $this->insertOrIgnore($sqlite,'ireadit', [
239                        'page' => $page,
240                        'rev' => $last_change_date,
241                        'user' => $user
242                    ]);
243                }
244            }
245
246        }
247        $db->commit();
248
249        return true;
250    }
251}
252