1<?php
2// must be run within DokuWiki
3if (!defined('DOKU_INC')) die();
4
5/**
6 * All DokuWiki plugins to extend the parser/rendering mechanism
7 * need to inherit from this class
8 */
9class action_plugin_ireadit_ireadit extends DokuWiki_Action_Plugin
10{
11    public function register(Doku_Event_Handler $controller)
12    {
13        $controller->register_hook('TPL_CONTENT_DISPLAY', 'AFTER', $this, 'render_list');
14        $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_ireadit_action');
15        $controller->register_hook('PARSER_METADATA_RENDER', 'AFTER', $this, 'updatre_ireadit_metadata');
16        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handle_pagesave_after');
17    }
18
19    public function render_list()
20    {
21        global $INFO, $ACT, $auth;
22
23        if ($ACT != 'show') return;
24        if (!p_get_metadata($INFO['id'], 'plugin ireadit')) return;
25
26        try {
27            /** @var \helper_plugin_ireadit_db $db_helper */
28            $db_helper = plugin_load('helper', 'ireadit_db');
29            $sqlite = $db_helper->getDB();
30        } catch (Exception $e) {
31            msg($e->getMessage(), -1);
32            return;
33        }
34
35        echo '<div';
36        if ($this->getConf('print') == 0) {
37            echo' class="no-print"';
38        }
39        echo '>';
40
41        $last_change_date = p_get_metadata($INFO['id'], 'last_change date');
42
43        if ($INFO['rev'] == 0) {
44            $res = $sqlite->query('SELECT page FROM ireadit WHERE page = ?
45                                                AND rev = ?
46                                                AND timestamp IS NULL
47                                                AND user = ?', $INFO['id'],
48                                                    $last_change_date, $INFO['client']);
49            if ($sqlite->res2single($res)) {
50                echo '<a href="' . wl($INFO['id'], ['do' => 'ireadit']) . '">' . $this->getLang('ireadit') . '</a>';
51            }
52        }
53
54        $rev = !$INFO['rev'] ? $last_change_date : $INFO['rev'];
55        $res = $sqlite->query('SELECT user, timestamp FROM ireadit
56                                        WHERE page = ?
57                                        AND timestamp IS NOT NULL
58                                        AND rev = ?
59                                        ORDER BY timestamp', $INFO['id'], $rev);
60
61        $readers = $sqlite->res2arr($res);
62        if (count($readers) > 0) {
63            echo '<h3>' . $this->getLang('readit_header') . '</h3>';
64            echo '<ul>';
65            foreach ($readers as $reader) {
66                $udata = $auth->getUserData($reader['user'], false);
67                $name = $udata ? $udata['name'] : $reader['user'];
68                $time = strtotime($reader['timestamp']);
69                echo '<li>' . $name . ' - ' . date('d/m/Y H:i', $time) . '</li>';
70            }
71            echo '</ul>';
72        }
73
74
75        echo '</div>';
76    }
77
78    public function handle_ireadit_action(Doku_Event $event)
79    {
80        global $INFO, $ACT;
81        if ($event->data != 'ireadit') return;
82        $ACT = 'show';
83        if (!$INFO['client']) return;
84
85        try {
86            /** @var \helper_plugin_ireadit_db $db_helper */
87            $db_helper = plugin_load('helper', 'ireadit_db');
88            $sqlite = $db_helper->getDB();
89        } catch (Exception $e) {
90            msg($e->getMessage(), -1);
91            return;
92        }
93
94        $last_change_date = p_get_metadata($INFO['id'], 'last_change date');
95
96        //check if user can "ireadit" the page and didn't "ireadit" already
97        $res = $sqlite->query('SELECT page FROM ireadit
98                                            WHERE page = ?
99                                            AND rev = ?
100                                            AND timestamp IS NULL
101                                            AND user = ?',
102                                        $INFO['id'], $last_change_date, $INFO['client']);
103        if (!$sqlite->res2single($res)) return;
104
105        $sqlite->query('UPDATE ireadit SET timestamp=? WHERE page=? AND rev=? AND user=?',
106            date('c'), $INFO['id'], $last_change_date, $INFO['client']);
107    }
108
109    public function updatre_ireadit_metadata(Doku_Event $event)
110    {
111        try {
112            /** @var \helper_plugin_ireadit_db $db_helper */
113            $db_helper = plugin_load('helper', 'ireadit_db');
114            $sqlite = $db_helper->getDB();
115        } catch (Exception $e) {
116            msg($e->getMessage(), -1);
117            return;
118        }
119
120        $page = $event->data['current']['last_change']['id'];
121        $last_change_date = $event->data['current']['last_change']['date'];
122
123        //don't use ireadit here
124        if (!isset($event->data['current']['plugin']['ireadit'])) {
125            //remove some old data
126            $sqlite->query('DELETE FROM ireadit WHERE page=? AND timestamp IS NULL', $page);
127            $sqlite->query('DELETE FROM meta WHERE page=?', $page);
128            return;
129        }
130        $ireadit = $event->data['current']['plugin']['ireadit'];
131
132        //check if new revision exists
133        $res = $sqlite->query('SELECT page FROM ireadit WHERE page = ? AND rev = ?',
134            $page, $last_change_date);
135
136        //revision already in table
137        if ($sqlite->res2single($res)) return;
138
139        /* @var \helper_plugin_ireadit $helper */
140        $helper = plugin_load('helper', 'ireadit');
141
142        //remove old "ireaders"
143        $sqlite->query('DELETE FROM ireadit WHERE page=? AND timestamp IS NULL', $page);
144        //update metadata
145        $sqlite->query('REPLACE INTO meta(page,meta,last_change_date) VALUES (?,?,?)',
146            $page, json_encode($ireadit), $last_change_date);
147
148        if ($this->getConf('minor_edit_keeps_readers') &&
149            $event->data['current']['last_change']['type'] == 'e') {
150            $res = $sqlite->query('SELECT user, timestamp FROM ireadit
151                                    WHERE rev=(SELECT MAX(rev) FROM ireadit WHERE page=?)
152                                      AND page=? AND timestamp IS NOT NULL', $page, $page);
153            $prevReaders = [];
154            while ($row = $sqlite->res_fetch_assoc($res)) {
155                $user = $row['user'];
156                $timestamp = $row['timestamp'];
157                $prevReaders[$user] = $timestamp;
158            }
159        }
160
161        $newUsers = $helper->users_set($ireadit['users'], $ireadit['groups']);
162        //insert new users
163        foreach ($newUsers as $user => $info) {
164            if (isset($prevReaders[$user])) {
165                $sqlite->query('INSERT OR IGNORE INTO ireadit (page, rev, user, timestamp)
166                            VALUES (?,?,?,?)', $page, $last_change_date, $user, $prevReaders[$user]);
167            } else {
168                $sqlite->query('INSERT OR IGNORE INTO ireadit (page, rev, user) VALUES (?,?,?)',
169                    $page, $last_change_date, $user);
170            }
171        }
172    }
173
174    /**
175     *
176     * @param Doku_Event $event  event object by reference
177     * @return void
178     */
179    public function handle_pagesave_after(Doku_Event $event)
180    {
181        //no content was changed
182        if (!$event->data['contentChanged']) return;
183
184        if ($event->data['changeType'] == DOKU_CHANGE_TYPE_DELETE) {
185            try {
186                /** @var \helper_plugin_ireadit_db $db_helper */
187                $db_helper = plugin_load('helper', 'ireadit_db');
188                $sqlite = $db_helper->getDB();
189            } catch (Exception $e) {
190                msg($e->getMessage(), -1);
191                return;
192            }
193
194            $sqlite->query('DELETE FROM ireadit WHERE page=? AND timestamp IS NULL', $event->data['id']);
195            $sqlite->query('DELETE FROM meta WHERE page=?', $event->data['id']);
196        }
197    }
198}
199