1<?php 2/** 3 * 4 * Plugin timetrack 5 * 6 * @package dokuwiki\plugin\timetrack 7 * @author peterfromearth <coder@peterfromearth.de> 8 */ 9// must be run within Dokuwiki 10if(!defined('DOKU_INC')) die(); 11 12/** 13 * Class action_plugin_data 14 */ 15class action_plugin_timetrack extends DokuWiki_Action_Plugin { 16 17 /** 18 * will hold the data helper plugin 19 * @var helper_plugin_timetrack 20 */ 21 var $tthlp = null; 22 23 /** 24 * Constructor. Load helper plugin 25 */ 26 function __construct(){ 27 $this->tthlp = plugin_load('helper', 'timetrack'); 28 29 } 30 31 /** 32 * Registers a callback function for a given event 33 */ 34 function register(Doku_Event_Handler $controller) { 35 $controller->register_hook('TEMPLATE_PAGETOOLS_DISPLAY', 'BEFORE', $this, 'add_menu_item'); 36 $controller->register_hook('MENU_ITEMS_ASSEMBLY', 'AFTER', $this, 'add_menu_item_new'); 37 38 $controller->register_hook('TPL_ACTION_GET', 'BEFORE', $this, 'define_action'); 39 $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, 'ajax'); 40// $controller->register_hook('PARSER_CACHE_USE', 'BEFORE', $this, 'checkCacheBefore'); 41 $controller->register_hook('PARSER_CACHE_USE', 'AFTER', $this, 'checkCacheAfter'); 42 } 43 44 45 public function checkCacheAfter(Doku_Event $event, $param) { 46 /* @var $cache cache_renderer */ 47 $cache = $event->data; 48 if($cache->mode !== 'xhtml') return; 49 if(p_get_metadata($cache->page,'plugin_timetrack update_time') < $this->tthlp->getMaxUpdateTime($cache->page)) 50 $event->result = false; 51 } 52 53 /** 54 * Add an item to sitetools 55 * Can use `tpl_action()` because dokuwiki accepts 'youraction' by the define_action() handler below. 56 * 57 * @param Doku_Event $event 58 * @param $param 59 */ 60 public function add_menu_item(Doku_Event $event, $param) { 61 global $lang; 62 global $ID; 63 if(!$this->tthlp->isPageTracked($ID) && !$this->tthlp->isUserInDb()) return true; 64 65 $lang['btn_plugin_timetrack'] = $this->getLang('timetrack'); 66 67 $event->data['items']['plugin_timetrack'] = tpl_action('plugin_timetrack', true, 'li', true); 68 } 69 70 public function add_menu_item_new(Doku_Event $event, $param) { 71 global $lang; 72 global $ID; 73 if(!$this->tthlp->isPageTracked($ID) && !$this->tthlp->isUserInDb()) return true; 74 75 $lang['btn_plugin_timetrack'] = $this->getLang('timetrack'); 76 77 $event->data['items'][] = new \dokuwiki\plugin\timetrack\MenuItem(); 78 } 79 80 /** 81 * Accepts the 'youraction' action, while using the default action link properties. 82 * Entries of $event->data can be modified eventually. 83 * 84 * @param Doku_Event $event 85 * @param $param 86 */ 87 public function define_action(Doku_Event $event, $param) { 88 if ($event->data['type'] != 'plugin_timetrack') { 89 return; 90 } 91 92 $event->preventDefault(); 93 } 94 95 public function ajax(Doku_Event $event, $param) { 96 global $INPUT; 97 sleep(1); 98 99 if ($event->data !== 'plugin_timetrack') { 100 return; 101 } 102 $event->stopPropagation(); 103 $event->preventDefault(); 104 105 $result = array(); 106 107 if(!checkSecurityToken()) { 108 $result['dialog'] = 'security token false'; 109 110 $json = new JSON($result); 111 echo $json->encode($result); 112 exit; 113 } 114 115 116 $cmd = $INPUT->str('cmd'); 117 if(!cmd) $cmd = 'current'; 118 119 $pageid = cleanID($INPUT->str('pageid')); 120 121 //if current page is not tracked or readable, do not show current action 122 if($cmd === 'current' && (auth_quickaclcheck($pageid) < AUTH_READ || !$this->tthlp->isPageTracked($pageid))) { 123 $cmd = 'overview'; 124 } 125 126 $yearweek = null; 127 if($INPUT->has('data') && isset($INPUT->arr('data')['yearweek'])) { 128 $yearweek = $INPUT->arr('data')['yearweek']; 129 } else if($INPUT->has('yearweek')) { 130 $yearweek = $INPUT->str('yearweek'); 131 } 132 133 $daterange = $this->tthlp->getDateRangeByYearWeek($yearweek); 134 $errors = array(); 135 if($cmd === 'current') { 136 $project_ids = $this->tthlp->getProjectIdsByPageId($pageid); 137 $dbUserValues = $this->tthlp->getUserTimeData($this->tthlp->getCurrentUser(),$daterange,$project_ids); 138 139 140 if($INPUT->has('UserTime')) { 141 $errors = $this->saveUserTime($INPUT->arr('UserTime'), $dbUserValues); 142 } 143 144 if($INPUT->has('UserTime') && empty($errors)) { 145 $result = array( 146 'success' => true 147 ); 148 } 149 $dbTasks = $this->tthlp->getTasks($project_ids); 150 $dialogHtml = $this->renderErrors($errors); 151 $dialogHtml .= $this->tthlp->html_week( 152 $dbUserValues, 153 $daterange, 154 $dbTasks, 155 'current', 156 $pageid); 157 158 $result = array_merge($result,array( 159 'dialog' => $this->tthlp->html_prepareDialog('current', 160 $dialogHtml, 161 $pageid), 162 'cmd' => 'current', 163 )); 164 165 } else if($cmd === 'overview' ) { 166 $result = array( 167 'dialog' => $this->tthlp->html_prepareDialog('overview',$this->tthlp->html_overview($this->tthlp->getCurrentUser(),$daterange,$pageid),$pageid), 168 'cmd' => 'overview', 169 ); 170 171 } else if($cmd === 'recent' ) { 172 $dbUserValues = $this->tthlp->getUserTimeData($this->tthlp->getCurrentUser(), $daterange); 173 174 if($INPUT->has('UserTime')) { 175 $errors = $this->saveUserTime($INPUT->arr('UserTime'), $dbUserValues); 176 } 177 178 if($INPUT->has('UserTime') && empty($errors)) { 179 $result = array( 180 'success' => true 181 ); 182 } 183 $dbUserTasks = $this->tthlp->getRecentTasks($this->tthlp->getCurrentUser(), $daterange); 184 $dialogHtml = $this->renderErrors($errors); 185 $dialogHtml .= $this->tthlp->html_week($dbUserValues,$daterange,$dbUserTasks,'recent',$pageid); 186 $result = array_merge($result,array( 187 'dialog' => $this->tthlp->html_prepareDialog('recent', 188 $dialogHtml, 189 $pageid), 190 'cmd' => 'recent', 191 )); 192 193 } else { 194 $result = array( 195 'dialog' => 'cmd unknown' 196 ); 197 } 198 199 $json = new JSON($result); 200 echo $json->encode($result); 201 202 } 203 204 public function validateUserTime($data) { 205 $dates = array(); 206 $errors = array(); 207 $task_ids = array(); 208 foreach($data as $project_id => $taskValues) { 209 foreach($taskValues as $task_id => $dateValues) { 210 foreach($dateValues as $date => $value) { 211 if($value < 0) $value = 0; 212 $dates[$date] += (int)$value; 213 $task_ids[] = $task_id; 214 } 215 } 216 } 217 218 $task_ids = array_unique($task_ids); 219 220 foreach($dates as $date=>$datevalue) { 221 if($datevalue + $this->tthlp->getHoursNotInTasksOnDate($this->tthlp->getCurrentUser(),$date,$task_ids) 222 > $this->getConf('max_hours')) 223 $errors[] = sprintf($this->getLang('err_max_hours'),$date); 224 } 225 return $errors; 226 } 227 228 public function saveUserTime($userTime, &$dbUserValues) { 229 $errors = $this->validateUserTime($userTime); 230 231 if(empty($errors)) { 232 foreach($userTime as $project_id => $taskValues) { 233 if(!$this->tthlp->canAccessProject($project_id)) continue; 234 235 $projectDetails = $this->tthlp->getProjectDetails($project_id); 236 foreach($taskValues as $task_id => $dateValues) { 237 foreach($dateValues as $date => $value) { 238 $res = true; 239 $value = (int)$value; 240 if($value < 0) $value = 0; 241 //not between from to 242 if(($projectDetails['from'] && $projectDetails['from'] > strtotime($date)) || 243 ($projectDetails['to'] && $projectDetails['to'] < strtotime($date))) 244 continue; 245 246 if(isset($dbUserValues[$project_id][$task_id][$date]) && $dbUserValues[$project_id][$task_id][$date]['value'] != $value) { 247 $dbUserValues[$project_id][$task_id][$date]['value'] = $value; 248 $res = $this->tthlp->updateUserTime($dbUserValues[$project_id][$task_id][$date]['id'], $value); 249 } else if ($value){ 250 $dbUserValues[$project_id][$task_id][$date]['value'] = $value; 251 252 $res = $this->tthlp->insertUserTime($this->tthlp->getCurrentUser(), $task_id, $date, $value); 253 } 254 if($res !== true) { 255 $errors[] = $res; 256 } 257 } 258 } 259 } 260 } else { 261 foreach($userTime as $project_id => $taskValues) { 262 foreach($taskValues as $task_id => $dateValues) { 263 foreach($dateValues as $date => $value) { 264 $dbUserValues[$project_id][$task_id][$date]['value_db'] = $dbUserValues[$project_id][$task_id][$date]['value']?$dbUserValues[$project_id][$task_id][$date]['value']:0; 265 $dbUserValues[$project_id][$task_id][$date]['value'] = $value; 266 } 267 } 268 } 269 } 270 271 return $errors; 272 273 } 274 275 276 public function renderErrors($errors) { 277 if(!empty($errors)) { 278 return '<div class="errors">' . implode('<br>',$errors) . '</div>'; 279 } 280 return ''; 281 } 282} 283