xref: /plugin/acknowledge/helper.php (revision 863b6e48d8bcae5b9535687407c12b2133192a65)
1<?php
2/**
3 * DokuWiki Plugin acknowledge (Helper Component)
4 *
5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
6 * @author  Andreas Gohr, Anna Dabrowska <dokuwiki@cosmocode.de>
7 */
8
9class helper_plugin_acknowledge extends DokuWiki_Plugin
10{
11
12    /**
13     * @return helper_plugin_sqlite|null
14     */
15    public function getDB()
16    {
17        /** @var \helper_plugin_sqlite $sqlite */
18        $sqlite = plugin_load('helper', 'sqlite');
19        if ($sqlite === null) {
20            msg($this->getLang('error sqlite plugin missing'), -1);
21            return null;
22        }
23        if (!$sqlite->init('acknowledgement', __DIR__ . '/db')) {
24            return null;
25        }
26
27        $this->registerUDF($sqlite);
28
29        return $sqlite;
30    }
31
32    /**
33     * Register user defined functions
34     *
35     * @param helper_plugin_sqlite $sqlite
36     */
37    protected function registerUDF($sqlite)
38    {
39        $sqlite->create_function('AUTH_ISMEMBER', [$this, 'auth_isMember'], -1);
40    }
41
42    /**
43     * Wrapper function for auth_isMember which accepts groups as string
44     *
45     * @param string $memberList
46     * @param string $user
47     * @param string $groups
48     * @return bool
49     */
50    public function auth_isMember($memberList, $user, $groups)
51    {
52        return auth_isMember($memberList, $user, explode('///', $groups));
53    }
54
55    /**
56     * Delete a page
57     *
58     * Cascades to delete all assigned data, etc.
59     *
60     * @param string $page Page ID
61     */
62    public function removePage($page)
63    {
64        $sqlite = $this->getDB();
65        if (!$sqlite) return;
66
67        $sql = "DELETE FROM pages WHERE page = ?";
68        $sqlite->query($sql, $page);
69    }
70
71    /**
72     * Update last modified date of page if content has changed
73     *
74     * @param string $page Page ID
75     * @param int $lastmod timestamp of last non-minor change
76     */
77    public function storePageDate($page, $lastmod, $newContent)
78    {
79        $changelog = new \dokuwiki\ChangeLog\PageChangeLog($page);
80        $revs = $changelog->getRevisions(0, 1);
81
82        // compare content
83        $oldContent = str_replace(NL, '', io_readFile(wikiFN($page, $revs[0])));
84        $newContent = str_replace(NL, '', $newContent);
85        if ($oldContent === $newContent) return;
86
87        $sqlite = $this->getDB();
88        if (!$sqlite) return;
89
90        $sql = "REPLACE INTO pages (page, lastmod) VALUES (?,?)";
91        $sqlite->query($sql, $page, $lastmod);
92    }
93
94    /**
95     * @param string $page Page ID
96     * @param string $assignees comma separated list of users and groups
97     */
98    public function setAssignees($page, $assignees)
99    {
100        $sqlite = $this->getDB();
101        if (!$sqlite) return;
102
103        $sql = "REPLACE INTO assignments ('page', 'assignee') VALUES (?,?)";
104        $sqlite->query($sql, $page, $assignees);
105    }
106
107    /**
108     * Clears assignments for a page
109     *
110     * @param string $page Page ID
111     */
112    public function clearAssignments($page)
113    {
114        $sqlite = $this->getDB();
115        if (!$sqlite) return;
116
117        $sql = "DELETE FROM assignments WHERE page = ?";
118        $sqlite->query($sql, $page);
119    }
120
121    /**
122     * Is the given user one of the assignees for this page
123     *
124     * @param string $page Page ID
125     * @param string $user user name to check
126     * @param string[] $groups groups this user is in
127     * @return bool
128     */
129    public function isUserAssigned($page, $user, $groups)
130    {
131        $sqlite = $this->getDB();
132        if (!$sqlite) return false;
133
134        $sql = "SELECT assignee FROM assignments WHERE page = ?";
135        $result = $sqlite->query($sql, $page);
136        $assignees = (string)$sqlite->res2single($result);
137        $sqlite->res_close($result);
138
139        return auth_isMember($assignees, $user, $groups);
140    }
141
142    /**
143     * Has the given user acknowledged the given page?
144     *
145     * @param string $page
146     * @param string $user
147     * @return bool|int timestamp of acknowledgement or false
148     */
149    public function hasUserAcknowledged($page, $user)
150    {
151        $sqlite = $this->getDB();
152        if (!$sqlite) return false;
153
154        $sql = "SELECT ack
155                  FROM acks A, pages B
156                 WHERE A.page = B.page
157                   AND A.page = ?
158                   AND A.user = ?
159                   AND A.ack >= B.lastmod";
160
161        $result = $sqlite->query($sql, $page, $user);
162        $acktime = $sqlite->res2single($result);
163        $sqlite->res_close($result);
164
165        return $acktime ? (int)$acktime : false;
166    }
167
168    /**
169     * Timestamp of the latest acknowledgment of the given page
170     * by the given user
171     *
172     * @param string $page
173     * @param string $user
174     * @return bool|string
175     */
176    public function getLatestUserAcknowledgement($page, $user)
177    {
178        $sqlite = $this->getDB();
179        if (!$sqlite) return false;
180
181        $sql = "SELECT MAX(ack)
182                  FROM acks
183                 WHERE page = ?
184                   AND user = ?";
185
186        $result = $sqlite->query($sql, $page, $user);
187        $latestAck = $sqlite->res2single($result);
188        $sqlite->res_close($result);
189
190        return $latestAck;
191    }
192
193    /**
194     * Save user's acknowledgement for a given page
195     *
196     * @param string $page
197     * @param string $user
198     * @return bool
199     */
200    public function saveAcknowledgement($page, $user)
201    {
202        $sqlite = $this->getDB();
203        if (!$sqlite) return false;
204
205        $sql = "INSERT INTO acks (page, user, ack) VALUES (?,?, strftime('%s','now'))";
206
207        $result = $sqlite->query($sql, $page, $user);
208        $sqlite->res_close($result);
209        return true;
210
211    }
212
213    /**
214     * Fetch all assignments for a given user, with additional page information,
215     * filtering already granted acknowledgements.
216     *
217     * @param string $user
218     * @param array $groups
219     * @return array|bool
220     */
221    public function getUserAssignments($user, $groups)
222    {
223        $sqlite = $this->getDB();
224        if (!$sqlite) return false;
225
226        $sql = "SELECT A.page, A.assignee, B.lastmod, C.user, C.ack FROM assignments A
227                JOIN pages B
228                ON A.page = B.page
229                LEFT JOIN acks C
230                ON A.page = C.page AND ( (C.user = ? AND C.ack > B.lastmod) )
231                WHERE AUTH_ISMEMBER(A.assignee, ? , ?)
232                AND ack IS NULL";
233
234        $result = $sqlite->query($sql, $user, $user, implode('///', $groups));
235        $assignments = $sqlite->res2arr($result);
236        $sqlite->res_close($result);
237
238        return $assignments;
239    }
240
241    /**
242     * Get all pages a user needs to acknowledge and the last acknowledge date
243     *
244     * @param string $user
245     * @param array $groups
246     * @return array|bool
247     */
248    public function getUserAcknowledgements($user, $groups)
249    {
250        $sqlite = $this->getDB();
251        if (!$sqlite) return false;
252
253        $sql = "SELECT A.page, A.assignee, B.lastmod, C.user, MAX(C.ack) AS ack
254                  FROM assignments A
255                  JOIN pages B
256                    ON A.page = B.page
257             LEFT JOIN acks C
258                    ON A.page = C.page AND C.user = ?
259                 WHERE AUTH_ISMEMBER(A.assignee, ? , ?)
260            GROUP BY A.page
261            ORDER BY A.page
262            ";
263
264        $result = $sqlite->query($sql, $user, $user, implode('///', $groups));
265        $assignments = $sqlite->res2arr($result);
266        $sqlite->res_close($result);
267
268        return $assignments;
269    }
270
271    /**
272     * Returns all acknowledgements
273     *
274     * @param int $limit maximum number of results
275     * @return array|bool
276     */
277    public function getAcknowledgements($limit = 100)
278    {
279        $sqlite = $this->getDB();
280        if (!$sqlite) return false;
281
282        $sql = '
283            SELECT page, user, max(ack) AS ack
284              FROM acks
285          GROUP BY user,page
286          ORDER BY ack DESC
287             LIMIT ?
288              ';
289        $result = $sqlite->query($sql, $limit);
290        $acknowledgements = $sqlite->res2arr($result);
291        $sqlite->res_close($result);
292
293        return $acknowledgements;
294    }
295}
296
297