1<?php 2/** 3 * DokuWiki Plugin tos (Action Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Andreas Gohr <dokuwiki@cosmocode.de> 7 */ 8 9class action_plugin_tos extends DokuWiki_Action_Plugin 10{ 11 12 const FORMFIELD = 'plugin__tos_accept'; 13 14 /** 15 * @inheritDoc 16 */ 17 public function register(Doku_Event_Handler $controller) 18 { 19 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'checkTosAccept'); 20 $controller->register_hook('TPL_ACT_UNKNOWN', 'BEFORE', $this, 'showTos'); 21 } 22 23 /** 24 * Check if the TOCs have been accepted and update the state if needed 25 * 26 * @param Doku_Event $event event object by reference 27 * @param mixed $param 28 * @return void 29 */ 30 public function checkTosAccept(Doku_Event $event, $param) 31 { 32 global $INPUT; 33 global $INFO; 34 $user = $INPUT->server->str('REMOTE_USER'); 35 if ($user === '') return; 36 $act = act_clean($event->data); 37 if ($act === 'logout') return; 38 if ($INFO['ismanager']) return; 39 40 // if user accepted the TOCs right now, no further checks needed 41 if ($INPUT->bool(self::FORMFIELD)) { 42 $this->userTosState($user, true); 43 $event->data = 'redirect'; 44 return; 45 } 46 47 // ensure newest TOCs have been accepted before 48 $newest = $this->newestTOS(); 49 if (!$newest) return; // we don't have a valid TOS, yet 50 $accepted = $this->userTosState($user); 51 if ($accepted >= $newest) return; 52 53 $event->data = 'plugin_tos'; 54 } 55 56 /** 57 * Display the TOS and ask to accept 58 * 59 * @param Doku_Event $event event object by reference 60 * @param mixed $param 61 * @return void 62 */ 63 public function showTos(Doku_Event $event, $param) 64 { 65 global $ID; 66 global $INPUT; 67 68 if ($event->data !== 'plugin_tos') return; 69 $event->preventDefault(); 70 71 echo '<div class="plugin-tos">'; 72 echo $this->locale_xhtml('intro'); 73 74 $accepted = $this->userTosState($INPUT->server->str('REMOTE_USER')); 75 if ($accepted) { 76 echo '<label for="plugin__tos_showdiff">'; 77 echo sprintf($this->getLang('showdiff'), dformat($accepted, '%f')); 78 echo '</label>'; 79 echo '<input type="checkbox" id="plugin__tos_showdiff">'; 80 echo $this->diffTos($accepted); 81 } 82 83 echo '<div class="tos-content">'; 84 echo p_wiki_xhtml($this->getConf('tos')); 85 echo '</div>'; 86 87 echo '<ul class="tos-form">'; 88 echo '<li class="tos-nope"><a href="' . wl($ID, 89 ['do' => 'logout', 'sectok'=>getSecurityToken()]) . '">' . $this->getLang('nope') . '</a></li>'; 90 echo '<li class="tos-accept"><a href="' . wl($ID, 91 [self::FORMFIELD => '1']) . '">' . $this->getLang('accept') . '</a></li>'; 92 echo '</ul>'; 93 94 echo '</div>'; 95 } 96 97 /** 98 * Get the most recent, non-minor revision of the TOS page 99 * 100 * @return int 101 */ 102 protected function newestTOS() 103 { 104 $state = $this->sessionState(); 105 if ($state) return $state; 106 107 $changes = new \dokuwiki\ChangeLog\PageChangeLog($this->getConf('tos')); 108 if (!$changes->hasRevisions()) return 0; 109 110 $start = -1; // also check current revision 111 while ($revisions = $changes->getRevisions($start, 25)) { 112 $start += count($revisions); 113 foreach ($revisions as $rev) { 114 $info = $changes->getRevisionInfo($rev); 115 if ($info['type'] === 'E' || $info['type'] === 'C') { 116 return $this->sessionState($rev); 117 } 118 } 119 } 120 121 return 0; 122 } 123 124 /** 125 * Check and optionally update the last TOS-Acceptance 126 * 127 * @param string $user the user to check/update 128 * @param bool $accept set true is the user accepted the TOS right now 129 * @return int the last acceptance of the TOS 130 */ 131 protected function userTosState($user, $accept = false) 132 { 133 $tosfile = getCacheName($user, '.tos'); 134 135 if ($accept) { 136 io_makeFileDir($tosfile); 137 io_saveFile($tosfile, $user); 138 } 139 140 return (int)@filemtime($tosfile); 141 } 142 143 /** 144 * Read or write the current TOS time to the session 145 * 146 * @param int $set 147 * @return int 0 when no info is available 148 */ 149 protected function sessionState($set = 0) 150 { 151 if (!$this->getConf('usesession')) return $set; 152 153 if ($set) { 154 session_start(); 155 $_SESSION[self::FORMFIELD] = $set; 156 session_write_close(); 157 } 158 159 if (isset($_SESSION[self::FORMFIELD])) { 160 return $_SESSION[self::FORMFIELD]; 161 } 162 return 0; 163 } 164 165 /** 166 * Create a inline diff of changes since the last accept 167 * 168 * @param int $lastaccept when the TOS was last accepted 169 * @return string 170 */ 171 protected function diffTos($lastaccept) 172 { 173 $change = new \dokuwiki\ChangeLog\PageChangeLog($this->getConf('tos')); 174 $oldrev = $change->getLastRevisionAt($lastaccept); 175 $old = rawWiki($this->getConf('tos'), $oldrev); 176 $new = rawWiki($this->getConf('tos')); 177 $diff = new Diff(explode("\n", $old), explode("\n", $new)); 178 $formatter = new InlineDiffFormatter(); 179 180 $html = '<div class="table tos-diff">'; 181 $html .= '<table class="diff diff_inline">'; 182 $html .= html_insert_softbreaks($formatter->format($diff)); 183 $html .= '</table>'; 184 $html .= '</div>'; 185 186 return $html; 187 } 188 189} 190 191