1<?php 2 3use dokuwiki\Extension\Plugin; 4 5/** 6 * DokuWiki Plugin struct (Helper Component) 7 * 8 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 9 * @author Szymon Olewniczak <dokuwiki@cosmocode.de> 10 */ 11class helper_plugin_watchcycle extends Plugin 12{ 13 public const MAINTAINERS_RAW = 0; 14 public const MAINTAINERS_FLAT = 1; 15 public const MAINTAINERS_EXPANDED = 2; 16 17 /** 18 * Create HTML for an icon showing the maintenance status of the provided pageid 19 * 20 * @param string $pageid the full pageid 21 * 22 * @return string span with inline svg icon and classes 23 */ 24 public function getSearchResultIconHTML($pageid) 25 { 26 /* @var \DokuWiki_Auth_Plugin $auth */ 27 global $auth; 28 if ($auth === null) return ''; 29 30 /* @var \helper_plugin_watchcycle $helper */ 31 $helper = plugin_load('helper', 'watchcycle'); 32 $watchcycle = p_get_metadata($pageid, 'plugin watchcycle'); 33 if (!$watchcycle) { 34 return ''; 35 } 36 37 $days_ago = $helper->daysAgo($watchcycle['last_maintainer_rev']); 38 39 $check_needed = false; 40 if ($days_ago > $watchcycle['cycle']) { 41 $check_needed = true; 42 } 43 44 $all = $this->getMaintainers($watchcycle['maintainer']); 45 $title = $this->getLang('maintained by') . implode(', ', array_keys($all)) . ' '; 46 47 if ($watchcycle['changes'] === -1) { 48 $title .= $this->getLang('never checked'); 49 } else { 50 $title .= sprintf($this->getLang('last check'), $days_ago); 51 } 52 53 $class = ['plugin__watchcycle_searchresult_icon']; 54 if ($check_needed) { 55 $class[] = 'check_needed'; 56 $title .= ' (' . $this->getLang('check needed') . ')'; 57 } 58 $icon = '<span class="' . implode(' ', $class) . '" title="' . $title . '">'; 59 $icon .= inlineSVG(DOKU_PLUGIN . 'watchcycle/admin.svg'); 60 $icon .= '</span>'; 61 return $icon; 62 } 63 64 /** 65 * @param $time 66 * @param $now 67 * 68 * @return int 69 */ 70 public function daysAgo($time, $now = false) 71 { 72 if (!$now) { 73 $now = time(); 74 } 75 76 $diff = ($now - $time) / (60 * 60 * 24); 77 return (int)$diff; 78 } 79 80 81 /** 82 * Returns true if the maintainer definition matches existing users and groups 83 * 84 * @param string $def 85 * @return bool 86 */ 87 public function validateMaintainerString($def) 88 { 89 /* @var DokuWiki_Auth_Plugin $auth */ 90 global $auth; 91 if ($auth === null) return false; // no valid auth setup 92 93 $all = explode(',', $def); 94 foreach ($all as $item) { 95 $item = trim($item); 96 if (strpos($item, '@') !== false) { 97 // check if group exists 98 if (empty($auth->retrieveUsers(0, 1, ['grps' => ltrim($item, '@')]))) { 99 return false; 100 } 101 } elseif ($auth->getUserData($item) === false) { 102 return false; 103 } 104 } 105 return true; 106 } 107 108 /** 109 * Returns a parsed representation of the maintainer string 110 * 111 * keys are the user and group names, value is either: 112 * 113 * - the user data array 114 * - null for groups 115 * - false for unknown users 116 * 117 * @param string $def maintainer definition as given in the syntax 118 * @return array 119 */ 120 public function getMaintainers($def) 121 { 122 /* @var DokuWiki_Auth_Plugin $auth */ 123 global $auth; 124 125 $found = []; 126 if ($auth === null) return $found; 127 128 $all = explode(',', $def); 129 foreach ($all as $item) { 130 $item = trim($item); 131 if ($item[0] === '@') { 132 $found[$item] = null; // no detail info on groups 133 } else { 134 $found[$item] = $auth->getUserData($item); 135 } 136 } 137 138 return $found; 139 } 140 141 /** 142 * @param string $def maintainer definition as given in the syntax 143 * @return string[] list of email addresses to inform 144 */ 145 public function getMaintainerMails($def) 146 { 147 /* @var \dokuwiki\Extension\AuthPlugin $auth */ 148 global $auth; 149 $auth ??= auth_setup(); 150 if (!$auth) return []; 151 152 $data = $this->getMaintainers($def); 153 $mails = []; 154 foreach ($data as $name => $info) { 155 if (is_array($info)) { 156 $mails[] = $info['mail']; 157 } elseif ($name[0] === '@' && $auth->canDo('getUsers')) { 158 $members = $auth->retrieveUsers(0, 0, ['grps' => ltrim($name, '@')]); 159 foreach ($members as $user) { 160 $mails[] = $user['mail']; 161 } 162 } 163 } 164 165 return array_values(array_unique($mails)); 166 } 167 168 /** 169 * @param string $user 170 * @param string $def 171 * @return bool 172 */ 173 public function isMaintainer($user, $def) 174 { 175 /* @var DokuWiki_Auth_Plugin $auth */ 176 global $auth; 177 if ($auth === null) return false; 178 if ($user === '') return false; 179 $userData = $auth->getUserData($user); 180 181 $all = explode(',', $def); 182 foreach ($all as $item) { 183 $item = trim($item); 184 if (strpos($item, '@') !== false && in_array(ltrim($item, '@'), $userData['grps'])) { 185 return true; 186 } elseif ($item === $user) { 187 return true; 188 } 189 } 190 191 return false; 192 } 193 194 /** 195 * Inform all maintainers that the page needs checking 196 * 197 * @param string $def defined maintainers 198 * @param string $page that needs checking 199 */ 200 public function informMaintainer($def, $page) 201 { 202 $mails = $this->getMaintainerMails($def); 203 foreach ($mails as $mail) { 204 $this->sendMail($mail, $page); 205 } 206 } 207 208 /** 209 * Sends an email 210 * 211 * @param array $mail 212 * @param string $page 213 */ 214 protected function sendMail($mail, $page) 215 { 216 $mailer = new Mailer(); 217 $mailer->to($mail); 218 $mailer->subject($this->getLang('mail subject')); 219 220 $text = sprintf($this->getLang('mail body'), $page); 221 $link = '<a href="' . wl($page, '', true) . '">' . $page . '</a>'; 222 $html = sprintf($this->getLang('mail body'), $link); 223 $mailer->setBody($text, null, null, $html); 224 225 if (!$mailer->send()) { 226 msg($this->getLang('error mail'), -1); 227 } 228 } 229 230 /** 231 * Puts users and groups into a flat array; useful for simple string output 232 * @param array $all 233 * @return array 234 */ 235 protected function flattenMaintainers($all) 236 { 237 if (empty($all['users'])) { 238 return $all; 239 } 240 241 $users = array_map(static fn($user) => $user['name'], $all['users']); 242 243 return array_merge($users, $all['groups']); 244 } 245 246 /** 247 * Expands groups into users; useful for email notification 248 * 249 * @param array $all 250 * @return array 251 */ 252 protected function expandMaintainers($all) 253 { 254 if (empty($all['groups'])) { 255 return $all; 256 } 257 258 /* @var DokuWiki_Auth_Plugin $auth */ 259 global $auth; 260 if ($auth === null) return []; 261 262 $members = []; 263 foreach ($all['groups'] as $group) { 264 $members = array_merge($members, $auth->retrieveUsers(0, 0, ['grps' => ltrim($group, '@')])); 265 } 266 267 // merge eliminates any duplicates since we use string keys 268 return array_merge($all['users'], $members); 269 } 270} 271