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