1<?php 2 3// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps 4 5use dokuwiki\Extension\SyntaxPlugin; 6 7/** 8 * DokuWiki Plugin watchcycle (Syntax Component) 9 * 10 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 11 * @author Szymon Olewniczak <dokuwiki@cosmocode.de> 12 */ 13 14class syntax_plugin_watchcycle extends SyntaxPlugin 15{ 16 /** 17 * @return string Syntax mode type 18 */ 19 public function getType() 20 { 21 return 'disabled'; 22 } 23 24 /** 25 * @return int Sort order - Low numbers go before high numbers 26 */ 27 public function getSort() 28 { 29 return 100; 30 } 31 32 /** 33 * Connect lookup pattern to lexer. 34 * 35 * @param string $mode Parser mode 36 */ 37 public function connectTo($mode) 38 { 39 $this->Lexer->addSpecialPattern('~~WATCHCYCLE.*?~~', $mode, 'plugin_watchcycle'); 40 } 41 42 /** 43 * Handle matches of the watchcycle syntax. We assume that maintainer name doesn't contain semicolons. 44 * 45 * @param string $match The match of the syntax 46 * @param int $state The state of the handler 47 * @param int $pos The position in the document 48 * @param Doku_Handler $handler The handler 49 * 50 * @return bool|array Data for the renderer 51 */ 52 public function handle($match, $state, $pos, Doku_Handler $handler) 53 { 54 /* @var DokuWiki_Auth_Plugin $auth */ 55 global $auth; 56 57 if (!plugin_load('helper', 'sqlite')) { 58 msg($this->getLang('error sqlite missing'), -1); 59 return false; 60 } 61 if (!preg_match('/~~WATCHCYCLE:[^:]+:\d+~~/', $match)) { 62 msg('watchcycle: invalid syntax', -1); 63 return false; 64 } 65 66 $match = substr($match, strlen('~~WATCHCYCLE:'), strlen($match) - 2); 67 68 [$maintainer, $cycle] = array_map('trim', explode(':', $match)); 69 70 /* @var \helper_plugin_watchcycle $helper */ 71 $helper = plugin_load('helper', 'watchcycle'); 72 if ($helper->validateMaintainerString($maintainer) === false) { 73 msg($this->getLang('error invalid maintainers'), -1); 74 return false; 75 } 76 77 $data = ['maintainer' => $maintainer, 'cycle' => (int)$cycle]; 78 79 return $data; 80 } 81 82 /** 83 * Render xhtml output or metadata 84 * 85 * @param string $mode Renderer mode (supported modes: xhtml) 86 * @param Doku_Renderer $renderer The renderer 87 * @param array $data The data from the handler() function 88 * 89 * @return bool If rendering was successful. 90 */ 91 92 public function render($mode, Doku_Renderer $renderer, $data) 93 { 94 if (!$data) { 95 return false; 96 } 97 98 $method = "render_$mode"; 99 if (method_exists($this, $method)) { 100 call_user_func([$this, $method], $renderer, $data); 101 return true; 102 } 103 return false; 104 } 105 106 /** 107 * Render metadata 108 * 109 * @param Doku_Renderer $renderer The renderer 110 * @param array $data The data from the handler() function 111 */ 112 public function render_metadata(Doku_Renderer $renderer, $data) 113 { 114 $plugin_name = $this->getPluginName(); 115 116 $renderer->meta['plugin'][$plugin_name] = $data; 117 } 118 119 /** 120 * Render xhtml 121 * 122 * @param Doku_Renderer $renderer The renderer 123 * @param array $data The data from the handler() function 124 */ 125 public function render_xhtml(Doku_Renderer $renderer, $data) 126 { 127 global $ID; 128 /** @var \DokuWiki_Auth_Plugin $auth */ 129 global $auth; 130 131 /* @var \helper_plugin_watchcycle $helper */ 132 $helper = plugin_load('helper', 'watchcycle'); 133 134 $watchcycle = p_get_metadata($ID, 'plugin watchcycle'); 135 136 $days_ago = $helper->daysAgo($watchcycle['last_maintainer_rev']); 137 138 $check_needed = false; 139 if ($days_ago > $watchcycle['cycle']) { 140 $check_needed = true; 141 } 142 143 $class = ''; 144 if ($check_needed) { 145 $class = 'class="check_needed"'; 146 } 147 $renderer->doc .= '<div id="plugin__watchcycle" ' . $class . '>' . NL; 148 $renderer->doc .= '<div class="column">'; 149 $renderer->doc .= inlineSVG(DOKU_PLUGIN . 'watchcycle/admin.svg'); 150 $renderer->doc .= '</div>'; 151 152 $renderer->doc .= '<div class="column">'; 153 $renderer->doc .= $this->getMaintainerHtml($watchcycle['maintainer']); 154 155 156 if ($watchcycle['changes'] == -1) { 157 $renderer->doc .= $this->getLang('never checked'); 158 $renderer->doc .= ' (' . $this->getLang('check needed') . ')' . '<br />' . NL; 159 } else { 160 $renderer->doc .= sprintf($this->getLang('last check'), $days_ago); 161 if ($check_needed) { 162 $renderer->doc .= ' (' . $this->getLang('check needed') . ')'; 163 } 164 $renderer->doc .= '<br />' . NL; 165 166 $urlParameters = ['rev' => $watchcycle['last_maintainer_rev'], 'do' => 'diff']; 167 $changes_lang = $this->getLang('change ' . ($watchcycle['changes'] == 1 ? 'singular' : 'plural')); 168 $changes_link = $watchcycle['changes'] . ' ' . $changes_lang; 169 $changes_link = '<a href="' . wl($ID, $urlParameters) . '">' . $changes_link . '</a>'; 170 $renderer->doc .= sprintf($this->getLang('since last check'), $changes_link) . '<br />' . NL; 171 } 172 173 $renderer->doc .= '</div>'; 174 175 $renderer->doc .= '</div>'; 176 } 177 178 /** 179 * Returns a formatted maintainers string with mailto links. 180 * 181 * @param string $def 182 * @return string 183 */ 184 protected function getMaintainerHtml($def) 185 { 186 /* @var \helper_plugin_watchcycle $helper */ 187 $helper = plugin_load('helper', 'watchcycle'); 188 189 $all = $helper->getMaintainers($def); 190 $flat = []; 191 foreach ($all as $name => $info) { 192 if (is_array($info)) { 193 $flat[] = $this->email($info['mail'], $info['name']); 194 } elseif ($info === null) { 195 $flat[] = $name; 196 } 197 } 198 199 return sprintf($this->getLang('maintained by'), implode(', ', $flat)) . '<br />' . NL; 200 } 201} 202 203// vim:ts=4:sw=4:et: 204