1<?php 2/** 3* IssueTracker Plugin: allows to create simple issue tracker 4* 5* initial code from DokuMicroBugTracker Plugin: allows to create simple bugtracker 6* 7* @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 8* @author Taggic <taggic@t-online.de> 9* 10* 11* 12*/ 13//session_start(); 14if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); 15if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 16require_once(DOKU_PLUGIN.'syntax.php'); 17require_once(DOKU_PLUGIN.'issuetracker/assilist.php'); 18/****************************************************************************** 19* All DokuWiki plugins to extend the parser/rendering mechanism 20* need to inherit from this class 21*/ 22class syntax_plugin_issuetracker extends DokuWiki_Syntax_Plugin 23{ 24/******************************************************************************/ 25/* return some info 26*/ 27 function getInfo(){ 28 return confToHash(dirname(__FILE__).'/plugin.info.txt'); 29 } 30 31 function getType(){ return 'substition';} 32 function getPType(){ return 'block';} 33 function getSort(){ return 167;} 34 35/******************************************************************************/ 36/* Connect pattern to lexer 37*/ 38 function connectTo($mode){ 39 $this->Lexer->addSpecialPattern('\{\{issuetracker>[^}]*\}\}',$mode,'plugin_issuetracker'); 40 } 41 42/******************************************************************************/ 43/* Handle the match 44*/ 45 function handle($match, $state, $pos,Doku_Handler &$handler){ 46 $match = substr($match,15,-2); //strip markup from start and end 47 //handle params 48 $data = array(); 49 $params = explode('|',$match); 50 51 foreach($params as $param) { 52 $splitparam = explode('=',$param); 53 if ($splitparam[1] != '') 54 { 55 if ($splitparam[0]=='project') { $data['project'] = trim(strtolower($splitparam[1])) ;} 56 if ($splitparam[0]=='product') { $data['product'] = trim(strtoupper($splitparam[1])) ;} 57 if ($splitparam[0]=='status') { $data['status'] = trim(strtoupper($splitparam[1])) ;} 58 if ($splitparam[0]=='severity') { $data['severity'] = trim(strtoupper($splitparam[1])) ;} 59 if ($splitparam[0]=='display') { $data['display'] = trim(strtoupper($splitparam[1])) ;} 60 if ($splitparam[0]=='view') { $data['view'] = trim(strtoupper($splitparam[1])) ;} 61 if ($splitparam[0]=='controls') { $data['controls'] = trim(strtoupper($splitparam[1])) ;} 62 if ($splitparam[0]=='prod_limit') { $data['prod_limit'] = trim(strtoupper($splitparam[1])) ;} 63 if ($splitparam[0]=='id') { $data['id'] = trim(strtoupper($splitparam[1])) ;} 64 if ($splitparam[0]=='version') { $data['version'] = trim(strtoupper($splitparam[1])) ;} 65 if ($splitparam[0]=='component') { $data['component'] = trim(strtoupper($splitparam[1])) ;} 66 if ($splitparam[0]=='tblock') { $data['tblock'] = trim(strtoupper($splitparam[1])) ;} 67 if ($splitparam[0]=='assignee') { $data['assignee'] = trim(strtoupper($splitparam[1])) ;} 68 if ($splitparam[0]=='reporter') { $data['reporter'] = trim(strtoupper($splitparam[1])) ;} 69 if ($splitparam[0]=='myissues') { $data['myissues'] = trim(strtoupper($splitparam[1])) ;} 70 if ($splitparam[0]=='config') { $data['config'] = trim(strtoupper($splitparam[1])) ;} 71 if ($splitparam[0]=='sort') { $data['sort'] = trim(strtoupper($splitparam[1])) ;} 72 if ($splitparam[0]=='columns') { $data['columns'] = trim(strtoupper($splitparam[1])) ;} 73 if ($splitparam[0]=='asympupl') { $data['asympupl'] = trim(strtoupper($splitparam[1])) ;} 74 if ($splitparam[0]=='email_address') {$data['email_address'] = trim(strtolower($splitparam[1])) ;} 75 /*continue;*/ 76 } 77 } 78 79 return $data; 80 } 81 82/******************************************************************************/ 83/* Captcha OK 84*/ 85 function _captcha_ok() 86 { 87 $helper = null; 88 89 if(@is_dir(DOKU_PLUGIN.'captcha')) 90 { $helper = plugin_load('helper','captcha'); } 91 92 if(!is_null($helper) && $helper->isEnabled()) 93 { return $helper->check(); } 94 95 return ($this->getConf('use_captcha')); 96 } 97 98/******************************************************************************/ 99/* Create output 100*/ 101 function render($mode,Doku_Renderer &$renderer, $data) { 102 global $ID; 103 $project = htmlspecialchars(stripslashes($_REQUEST['project'])); 104 if(strlen($project) <1) $project = $data['project']; 105 else $data['project'] = $project; 106 107 if ($mode == 'xhtml'){ 108 109 $renderer->info['cache'] = false; 110 111 $Generated_Header = ''; 112 $Generated_Table = ''; 113 $Generated_Scripts = ''; 114 $Generated_Report = ''; 115 116 if ($data['display'] == '') {$data['display'] = 'ISSUES';} 117 if ($data['view'] == '') {$data['view'] = '10';} 118 if ($data['controls'] == '') {$data['controls'] = 'ON';} 119 if ($data['prod_limit'] == '') {$data['prod_limit'] = 'OFF';} 120 if ($data['id'] == '') {$data['id'] = '0';} 121 if ($data['severity'] == '') {$data['severity'] = 'ALL';} 122 if ($data['status'] == '') {$data['status'] = 'ALL';} 123 if ($data['product'] == '') {$data['product'] = 'ALL';} 124 if ($data['version'] == '') {$data['version'] = 'ALL';} 125 if ($data['component'] == '') {$data['component'] = 'ALL';} 126 if ($data['tblock'] == '') {$data['tblock'] = false;} 127 else { $data['tblock'] = true; } 128 if ($data['assignee'] == '') {$data['assignee'] = 'ALL';} 129 if ($data['reporter'] == '') {$data['reporter'] = 'ALL';} 130 if ($data['myissues'] == '') {$data['myissues'] = false;} 131 else { $data['myissues']= true; } 132 if ($data['config'] == '') {$data['config'] = false;} 133 else { $data['config'] = true; } 134 if($data['asympupl'] == '') {$data['asympupl']=false;} 135 else{$data['asympupl']=true;} 136 137 if ($this->validEmail($data['email_address'])===false ) { 138 if($data['email_address']!='') { msg("invalid mail given by syntax",-1);} 139 $data['email_address'] = $this->getConf('email_address'); 140 } 141 142 if (stristr($data['display'],'FORM')!= false) 143 { 144 //If it is a user report add it to the db-file 145 if (isset($_REQUEST['severity'])) 146 { 147 if ($_REQUEST['severity']) 148 { 149 // check if captcha is to be used by issue tracker in general 150 if ($this->getConf('use_captcha') === 0) { $captcha_ok = 1;} 151 else { $captcha_ok = ($this->_captcha_ok());} 152 153 if ($captcha_ok) 154 { 155 if (checkSecurityToken()) 156 { // get issues file contents 157 $all = false; 158 $issues = $this->_get_issues($data, $all); 159 160 //Add it to the issue file 161 $issue_id=count($issues); 162 foreach ($issues as $value) 163 {if ($value['id'] >= $issue_id) {$issue_id=$value['id'] + 1;}} 164 165 $issues[$issue_id]['id'] = $issue_id; 166 $issues[$issue_id]['product'] = htmlspecialchars(stripslashes($_REQUEST['product'])); 167 $issues[$issue_id]['version'] = htmlspecialchars(stripslashes($_REQUEST['version'])); 168 $issues[$issue_id]['component'] = htmlspecialchars(stripslashes($_REQUEST['component'])); 169 $issues[$issue_id]['tblock'] = htmlspecialchars(stripslashes($_REQUEST['tblock'])); 170 $issues[$issue_id]['severity'] = htmlspecialchars(stripslashes($_REQUEST['severity'])); 171 $issues[$issue_id]['created'] = htmlspecialchars(stripslashes($_REQUEST['created'])); 172 $status = explode(',', $this->getConf('status')) ; 173 $issues[$issue_id]['status'] = $status[0]; 174 $issues[$issue_id]['user_name'] = htmlspecialchars(stripslashes($_REQUEST['user_name'])); 175 $issues[$issue_id]['user_mail'] = trim(htmlspecialchars(stripslashes($_REQUEST['user_mail']))); 176 $issues[$issue_id]['user_phone'] = htmlspecialchars(stripslashes($_REQUEST['user_phone'])); 177 $issues[$issue_id]['add_user_mail'] = htmlspecialchars(stripslashes($_REQUEST['add_user_mail'])); 178// $issues[$issue_id]['title'] = htmlspecialchars(stripslashes($_REQUEST['title'])); 179 $issues[$issue_id]['title'] = htmlspecialchars($_REQUEST['title']); 180// $issues[$issue_id]['description'] = htmlspecialchars(stripslashes($_REQUEST['description'])); 181 $issues[$issue_id]['description'] = htmlspecialchars($_REQUEST['description']); 182 $issues[$issue_id]['attachment1'] = htmlspecialchars(stripslashes($_REQUEST['attachment1'])); 183 $issues[$issue_id]['attachment2'] = htmlspecialchars(stripslashes($_REQUEST['attachment2'])); 184 $issues[$issue_id]['attachment3'] = htmlspecialchars(stripslashes($_REQUEST['attachment3'])); 185 $issues[$issue_id]['assigned'] = ''; 186 $issues[$issue_id]['resolution'] = ''; 187 $issues[$issue_id]['comments'] = ''; 188 $issues[$issue_id]['modified'] = htmlspecialchars(stripslashes($_REQUEST['modified'])); 189 190 $xuser = $issues[$issue_id]['user_mail']; 191 $xdescription = $issues[$issue_id]['description']; 192 193//echo "Beschreibung: ".$xdescription."<br />"; 194 195// ***************************************************************************** 196// upload a symptom file 197// ***************************************************************************** 198 // check if current user is admin/assignee 199 // check if syntax parameter asympupl is switched on 200 $user_grp = pageinfo(); 201 if(array_key_exists('userinfo', $user_grp)) 202 { foreach ($user_grp['userinfo']['grps'] as $ugrp) 203 { $user_grps = $user_grps . $ugrp; } 204 } 205 else 206 { $user_grps = 'all'; } 207 $allowed_users = explode('|', $this->getConf('assign')); 208 $cFlag = false; 209 foreach ($allowed_users as $w) 210 { // check if one of the assigned user roles does match with current user roles 211 if (strpos($user_grps,$w)!== false) 212 { $cFlag = true; 213 break; } 214 } 215 216 $mime_type1 = $_FILES['attachment1']['type']; 217 if((($this->getConf('upload')> 0) ||(($cFlag === true) && ($data['asympupl']=true)) || ($this->getConf('registered_users')== 0)) && (strlen($mime_type1)>1)) { 218 $Generated_Header = $this->_symptom_file_upload($issues,$issue_id,'attachment1'); 219 } 220 $mime_type2 = $_FILES['attachment2']['type']; 221 if(($this->getConf('upload')> 0) && (strlen($mime_type2)>1)) { 222 $Generated_Header = $this->_symptom_file_upload($issues,$issue_id,'attachment2'); 223 } 224 $mime_type3 = $_FILES['attachment3']['type']; 225 if(($this->getConf('upload')> 0) && (strlen($mime_type3)>1)) { 226 $Generated_Header = $this->_symptom_file_upload($issues,$issue_id,'attachment3'); 227 } 228 229 //check user mail address, necessary for further clarification of the issue 230 $valid_umail = $this->validEmail($xuser); 231 if ( ($valid_umail == true) && ((stripos($xdescription, " ") > 0) || (strlen($xdescription)>5)) && (strlen($issues[$issue_id]['version']) >0)) 232 { 233 // assemble the path to IssueTracker data store & file 234 if($this->getConf('it_data')==false) $pfile = DOKU_CONF."../data/meta/".$data['project'].'.issues'; 235 else $pfile = DOKU_CONF."../". $this->getConf('it_data').$data['project'].'.issues'; 236 237 //save issue-file 238 $xvalue = io_saveFile($pfile,serialize($issues)); 239 $this->_log_mods($data['project'], $issues[$issue_id], $issues[$issue_id]['user_name'], 'status', '', $issues[$issue_id]['status']); 240 241 $pstring = sprintf("showid=%s&project=%s", urlencode($issues[$issue_id]['id']), urlencode($project)); 242 $tmp_link = '<a href="'.DOKU_URL.'doku.php?id='.$ID.'&do=showcaselink&'.$pstring.'" >'.$issue_id.'</a>'; 243 244 $Generated_Header .= '<div class="it__positive_feedback">'.$this->getLang('msg_reporttrue').$tmp_link.'</div>'; 245 $this->_emailForNewIssue($data['project'],$issues[$issue_id],$data['email_address']); 246 $_REQUEST['description'] = ''; 247 } 248 249 else 250 { 251 $wmsg =''; 252 if ($valid_umail == false) 253 { $wmsg = $this->getLang('wmsg1'); } 254 elseif (strlen($issues[$issue_id]['version']) <1) 255 { $wmsg = $this->getLang('wmsg2'); } 256 else 257 { $wmsg = $this->getLang('wmsg3').' ('.stripos($xdescription, " ").', '.strlen($xdescription).')'; } 258 259 $Generated_Header .= '<div class="it__negative_feedback">'.$wmsg.'</div>'; 260 } 261 } 262 else 263 { 264 $Generated_Header .= ':<div class="it__negative_feedback">'.$this->getLang('msg_captchawrong').'</div>'; 265 } 266 } 267 } 268 } 269 else 270 {$Generated_Report = $this->_report_render($data);} 271 } 272 273 // Create issue list 274 elseif (stristr($data['display'],'ISSUES')!= false) 275 { // get issues file contents 276 $all = true; 277 $issues = $this->_get_issues($data, $all); 278 279 // global sort of issues array 280 if($data['sort']='') $data['sort']='id'; 281 $sort_key = $data['sort']; 282 $issues = $this->_issues_globalsort($issues, $sort_key); 283 $step = $data['view']; 284 $Generated_Table = $this->_table_render($data['project'],$issues,$data,$step,$start); 285 if (strtolower($data['controls'])==='on') { 286 $Generated_Scripts = $this->_scripts_render($project); 287 } 288 } 289 // Count only ... 290 elseif (stristr($data['display'],'COUNT')!= false) 291 { // get issues file contents 292 $all = true; 293 $issues = $this->_get_issues($data, $all); 294 $a_result = $this->_count_render($issues,$start,$step,$next_start,$data,$project); 295 $Generated_Table =$a_result[1]; 296 $count = $a_result[0]; 297 } 298 // syntax to display a single issue inside wiki text 299 elseif (stristr($data['display'],'single_issue')!= false) 300 { // retrieve issue details 301 $all = false; 302 $issues = $this->_get_issues($data, $all); 303 $issue_id = $data['id']; 304 if($issues[$issue_id]['status'] == $this->getLang('issue_resolved_status')) { $a_style="<del>"; $e_style="</del>";} 305 // define output 306 $Generated_Table = $a_style."<a href='".DOKU_URL.'doku.php?id='.$ID."&do=showcaselink&showid=".$issue_id."&project=".$data['project']."' title='".$issues[$issue_id]['status']."'>".NL; 307 $Generated_Table .= "<span>#".$issue_id.":</span> "; 308 $Generated_Table .= "<span>".$issues[$issue_id]['title']."</span> "; 309 $Generated_Table .= "<span>(".$issues[$issue_id]['status'].")</span>"; 310 $Generated_Table .= "</a>".$e_style; 311 312 $Generated_Header = ""; 313 $Generated_Scripts = ""; 314 $Generated_Report = ""; 315 } 316// ***************************************************************************** 317// Show configuration 318// ***************************************************************************** 319 elseif (stristr($data['display'],'config')!= false) 320 { /* 1. load the defined elements per type 321 - the related config file (it_matrix.cfg) is stored to the plugin folder 322 - the matrix structure is as follows 323 elmnt_type | elmnt_name | rel_childs 324 - type project has childs of type product 325 - type product has at least one relative parent or is just newly created 326 */ 327/* $cfg_file = DOKU_PLUGIN."issuetracker/conf/it_matrix.cfg"; 328 $it_cfg = array(); 329 if (@file_exists($cfg_file)) { $it_cfg = unserialize(@file_get_contents($cfg_file)); } 330 echo "<pre style='font:italic 11px/15px Arial, serif;'>".print_r($it_cfg, true)."</pre>"; 331 332 // 2. replace the placeholder with config values 333 // a) loop through the matrix and collect all defined projects 334 // initially we start with projects 335 // string to be built according: <option value="strtolower($name)" >$name</option> 336 $itm_counter = 0; 337 $itm_counter2 = 0; 338 foreach($it_cfg as $item) { 339 if ($item['elmnt_type']=="project") { 340 $itm_counter++; 341 if($itm_counter===1){ 342 $name2 .= '<option value="'.$item['elmnt_name'].'" selected="selected">'.$item['elmnt_name'].'</option>'.NL; 343 $sel_prod = $item['elmnt_name']; 344 } 345 else { 346 $name2 .= '<option value="'.$item['elmnt_name'].'" >'.$item['elmnt_name'].'</option>'.NL; 347 } 348 } 349 350 // list all potential childs and check the already related items 351 elseif ($item['elmnt_type']=="product") { 352 $itm_counter2++; 353 if (stripos($item['rel_childs'],$sel_prod)!== false) { 354 $cfgelements .= '<input id="childs_'.$itm_counter2.'" name="childs_'.$itm_counter2.'" class="element checkbox" type="checkbox" checked /> 355 <label class="choice" for="childs_'.$itm_counter2.'">'.$item['elmnt_name'].'</label> <br />'.NL; 356 } 357 else { 358 $cfgelements .= '<input id="childs_'.$itm_counter2.'" name="childs_'.$itm_counter2.'" class="element checkbox" type="checkbox" /> 359 <label class="choice" for="childs_'.$itm_counter2.'">'.$item['elmnt_name'].'</label> <br />'.NL; 360 } 361 } 362 } 363 364 $type1 = '<option value="project" selected="selected">Project</option> 365 <option value="product" >Product</option> 366 <option value="component" >Component</option>'.NL; 367*/ 368/* $name2 = ' <option value="" selected="selected"></option> 369 <option value="1" >First element</option> 370 <option value="2" >Second element</option> 371 <option value="3" >Third element</option>'.NL; 372 373 $cfgelements = '<input id="element_6_1" name="element_6_1" class="element checkbox" type="checkbox" value="1" /> 374 <label class="choice" for="element_6_1">First option</label> <br /> 375 <input id="element_6_2" name="element_6_2" class="element checkbox" type="checkbox" value="1" /> 376 <label class="choice" for="element_6_2">Second option</label> <br /> 377 <input id="element_6_3" name="element_6_3" class="element checkbox" type="checkbox" value="1" /> 378 <label class="choice" for="element_6_3">Third option</label> <br />'.NL; 379*/ 380/* // 3. load html-skeleton 381 $html_skeleton = DOKU_PLUGIN."issuetracker/cfg_skeleton.html"; 382 if (@file_exists($html_skeleton)) { $Generated_config = @file_get_contents($html_skeleton); } 383 else { msg("The file 'cfg_skeleton.html' was not found at plugin directory.",-1); return;} 384 385 // 4. replace placeholders at html-skeleton 386 $Generated_config = str_ireplace("%%ID%%",$ID,$Generated_config); 387 $Generated_config = str_ireplace("%%type1%%",$type1,$Generated_config); 388 $Generated_config = str_ireplace("%%name2%%",$name2,$Generated_config); 389 $Generated_config = str_ireplace("%%cfgelements%%",$cfgelements,$Generated_config); 390 391 // 5. load the script to assemble the element childs for submit to action.php 392 $it_script = DOKU_PLUGIN."issuetracker/it_matrix.script"; 393 if (@file_exists($it_script)) { $it_cfg_script = @file_get_contents($it_script); } 394 else { msg("The file 'it_matrix.script' was not found at plugin directory.",-1); } 395 $Generated_config = $it_cfg_script .NL. $Generated_config; 396 397*/ } 398 399 // Render 400 $renderer->doc .= $Generated_Header.$Generated_Table.$Generated_Scripts.$Generated_Report.$Generated_config; 401 402 } 403 } 404 405/******************************************************************************/ 406/* Create count output 407*/ 408 function _count_render($issues,$start,$step,$next_start,$data, $project) 409 { global $ID; 410 $count = array(); 411 $productfilter=$data['product']; 412 413 foreach ($issues as $issue) 414 { 415 if(($issue['project'] !== $project) && ($this->getConf('multi_projects')==0)) { 416 continue; 417 } 418 elseif((strcasecmp($productfilter,'ALL')===0) || (stristr($productfilter,$this->_get_one_value($issue,'product'))!= false)) 419 { $status = trim($this->_get_one_value($issue,'status')); 420 $a_count = $a_count + 1; 421 if (($status != '') && (stripos($this->getConf('status_special'),$status)===false)) 422 { if ($this->_get_one_value($count,strtoupper($status))=='') 423 {$count[strtoupper($status)] = array(1,$status);} 424 else 425 {$count[strtoupper($status)][0] += 1;} 426 } 427 } 428 } 429 $rendered_count = '<div class="itl__count_div">'.'<table class="itl__count_tbl">'; 430 foreach ($count as $value) 431 { 432 //http://www.fristercons.de/fcon/doku.php?id=issuetracker:issuelist&do=showcaselink&showid=19&project=fcon_project 433 // $ID.'&do=issuelist_filter&itl_sev_filter='.$value[1] 434 $rendered_count .= '<tr><td><a href="'.DOKU_URL.'doku.php?id='.$ID.'&do=issuelist_filterlink'.'&itl_start='.$start.'&itl_step='.$step.'&itl_next='.$next_start.'&itl_stat_filter='.$value[1].'&itl_sev_filter='.$data['severity'].'&itl__prod_filter='.$data['product'].'&itl_project='.$data['project'].'" >'.$value[1].'</a> </td><td> '.$value[0].'</td></tr>'; 435 } 436 $rendered_count .= '</table></div>'; 437 $ret_array = array($a_count,$rendered_count); 438 return $ret_array; 439 } 440 441/******************************************************************************/ 442/* Create table scripts 443*/ 444 function _scripts_render($project) 445 { 446 // load status values from config into select control 447 $s_counter = 0; 448 $status = explode(',', $this->getConf('status')) ; 449 foreach ($status as $x_status) 450 { 451 $s_counter = $s_counter + 1; 452 $x_status = trim($x_status); 453 $STR_STATUS = $STR_STATUS . "case '".$x_status."': val = ".$s_counter."; break;"; 454 $pattern = $pattern . "|" . $x_status; 455 $x_status_select = $x_status_select . "['".$x_status."','".$x_status."'],"; 456 } 457 458 // Build string to load products select 459 $products = explode(',', $this->getConf('products')) ; 460 foreach ($products as $x_products) 461 { 462 $x_products = trim($x_products); 463 $x_products_select = $x_products_select . "['".$x_products."','".$x_products."'],"; 464 } 465 466 // Build string to load severity select 467 $severity = explode(',', $this->getConf('severity')) ; 468 foreach ($severity as $x_severity) 469 { 470 $x_severity = trim($x_severity); 471 $x_severity_select = $x_severity_select . "['".$x_severity."','".$x_severity."'],"; 472 } 473 474 // see issue 37: AUTH:AD switch to provide text input instead 475 // select with retriveing all_users from AD 476 // search also action.php for 'auth_ad_overflow' 477 if($this->getConf('auth_ad_overflow') == false) { 478 global $auth; 479 global $conf; 480 $filter['grps'] = $this->getConf('assign'); 481 $target = $auth->retrieveUsers(0,0,$filter); 482 $shw_assignee_as = trim($this->getConf('shw_assignee_as')); 483 if(stripos("login, mail, name",$shw_assignee_as) === false) $shw_assignee_as = "login"; 484//-------------------------------------------------------------------------------------------- 485// Build 'assign to' list from a simple textfile 486 // 1. check if file exist else use configuration 487 if($this->getConf('assgnee_list')==="") { 488 foreach ($target as $key => $x_umail) 489 { // show assignee by login, name, mail 490 if($shw_assignee_as=='login') $x_umail_select = $x_umail_select . "['".$key."','".$x_umail['mail']."'],"; 491 else $x_umail_select = $x_umail_select . "['".$x_umail[$shw_assignee_as]."','".$x_umail['mail']."'],"; 492 } 493 } 494 else{ 495 $fileextension = $this->getConf('assgnee_list'); 496 $x_umail_select = __get_assignees_from_files($fileextension); 497 } 498//-------------------------------------------------------------------------------------------- 499 500 $x_umail_select .= "['',''],"; 501 $authAD_selector = "TableKit.Editable.selectInput('assigned',{}, [".$x_umail_select."]);"; 502 } 503 //hack if DOKU_BASE is not properly set 504 if(strlen(DOKU_BASE) < strlen(DOKU_URL)) $BASE = DOKU_URL."lib/plugins/issuetracker/"; 505 else $BASE = DOKU_BASE."lib/plugins/issuetracker/"; 506 507 return "<script type=\"text/javascript\" src=\"".$BASE."prototype.js\"></script><script type=\"text/javascript\" src=\"".$BASE."fabtabulous.js\"></script> 508 <script type=\"text/javascript\" src=\"".$BASE."tablekit.js\"></script> 509 <script type=\"text/javascript\"> 510 TableKit.options.editAjaxURI = '".$BASE."edit.php'; 511 TableKit.Editable.selectInput('status',{}, [".$x_status_select."]); 512 TableKit.Editable.selectInput('product',{}, [".$x_products_select."]); 513 TableKit.Editable.selectInput('severity',{}, [".$x_severity_select."]); 514 ".$authAD_selector." 515 TableKit.Editable.multiLineInput('description'); 516 TableKit.Editable.multiLineInput('resolution'); 517 var _tabs = new Fabtabs('tabs'); 518 $$('a.next-tab').each(function(a) { 519 Event.observe(a, 'click', function(e){ 520 Event.stop(e); 521 var t = $(this.href.match(/#(\w.+)/)[1]+'-tab'); 522 _tabs.show(t); 523 _tabs.menu.without(t).each(_tabs.hide.bind(_tabs)); 524 }.bindAsEventListener(a)); 525 }); 526 </script>"; 527 } 528 529/******************************************************************************/ 530/* Create list of Issues 531*/ 532 function _table_render($project,$issues,$data,$step,$start) 533 { 534 global $ID; 535 global $lang; 536 if ($step==0) $step=10; 537 if ($start==0) $start=count($issues)-$step+1; 538 $next_start = $start + $step + 1; 539 if ($next_start>count($issues)) $next_start=count($issues); 540 541 $imgBASE = DOKU_BASE."lib/plugins/issuetracker/images/"; 542 $style =' style="text-align:center; white-space:pre-wrap;">'; 543// $date_style =' style="text-align:center; white-space:pre;">'; 544 $user_grp = pageinfo(); 545 $noStatIMG = $this->getConf('noStatIMG'); 546 $noSevIMG = $this->getConf('noSevIMG'); 547 $a_project = $data['project']; 548 549 if(array_key_exists('userinfo', $user_grp)) 550 { foreach ($user_grp['userinfo']['grps'] as $ugrp) 551 { $user_grps = $user_grps . $ugrp; } 552 } 553 else 554 { $user_grps = 'all'; } 555 556 if (strtolower($data['controls'])==='on') { 557 $ret = '<br /><br /><form class="issuetracker__form2" method="post" action="'.$_SERVER['REQUEST_URI'].'" accept-charset="'.$lang['encoding'].'"><p>'; 558 $ret .= formSecurityToken(false).'<input type="hidden" name="do" value="show" />'; 559 } 560 // the user maybe member of different user groups 561 // check if one of its assigned groups match with configuration 562 $allowed_users = explode('|', $this->getConf('assign')); 563 $cFlag = false; 564 foreach ($allowed_users as $w) 565 { // check if one of the assigned user roles does match with current user roles 566 if (strpos($user_grps,$w)!== false) 567 { $cFlag = true; 568 break; } 569 } 570 571 // members of defined groups $user_grps allowed to change issue contents 572 if (($cFlag === true) || ($this->getConf('registered_users')== 0)) 573 { $dynatable_id = "t_".uniqid((double)microtime()*1000000,1); 574 if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) 575 { $th_project = "<th id='project'>".$this->getLang('th_project')."</th>"; } 576 577 $head = "<div class='itl__table'><table id='".$dynatable_id."' class='sortable editable resizable inline' width='100%'>".NL. 578 "<thead><tr>".NL. 579 $th_project.NL. 580 "<th class='".$this->getConf('listview_sort')."' id='id'>".$this->getLang('th_id')."</th>".NL. 581 "<th id='created'>" .$this->getLang('th_created') ."</th>".NL. 582 "<th id='product'>" .$this->getLang('th_product') ."</th>".NL. 583 "<th id='version'>" .$this->getLang('th_version') ."</th>".NL. 584 "<th id='severity'>" .$this->getLang('th_severity') ."</th>".NL. 585 "<th id='status'>" .$this->getLang('th_status') ."</th>".NL. 586 "<th id='user_name'>" .$this->getLang('th_user_name') ."</th>".NL. 587 "<th id='title'>" .$this->getLang('th_title') ."</th>".NL. 588 "<th id='assigned'>" .$this->getLang('th_assigned') ."</th>".NL. 589 "<th id='resolution'>".$this->getLang('th_resolution')."</th>".NL. 590 "<th id='modified'>" .$this->getLang('th_modified') ."</th>".NL. 591 "</tr></thead>".NL; 592 $body = '<tbody>'.NL; 593 594 // Note: The checked attribute is a boolean attribute. 595 if($data['myissues'] == '') { $data['myissues']= false; } 596 else { $data['myissues']= true; } 597 598 for ($i=$next_start-1;$i>=0;$i=$i-1) 599 { // check start and end of rows to be displayed 600 if($i>count($issues)) break; // prevent the php-warning 601 $issue = $issues[$i]; 602 603 $a_status = strtolower($this->_get_one_value($issue,'status')); 604 $a_severity = strtolower($this->_get_one_value($issue,'severity')); 605 $a_product = strtoupper($this->_get_one_value($issue,'product')); 606 $a_version = strtoupper($this->_get_one_value($issue,'version')); 607 $a_component = strtoupper($this->_get_one_value($issue,'component')); 608 $a_tblock = strtoupper($this->_get_one_value($issue,'tblock')); 609 $a_assignee = strtoupper($this->_get_one_value($issue,'assignee')); 610 $a_reporter = strtoupper($this->_get_one_value($issue,'user_name')); 611 612 if ((($data['status'] =='ALL') || (stristr($data['status'],$a_status) != false)) && 613 (($data['severity'] =='ALL') || (stristr($data['severity'],$a_severity) != false)) && 614 (($data['product'] =='ALL') || (stristr($data['product'],$a_product) != false)) && 615 (($data['version'] =='ALL') || (stristr($data['version'],$a_version) != false)) && 616 (($data['component'] =='ALL') || (stristr($data['component'],$a_component) != false)) && 617 (($data['assignee'] =='ALL') || (stristr($data['assignee'],$a_assignee) != false)) && 618 (($data['reporter'] =='ALL') || (stristr($data['reporter'],$a_reporter) != false)) && 619 (($data['myissues'] == false ) || ($this->_find_myissues($issue, $user_grp) == true))) 620 { 621 if ($y>=$step) break; 622 if (stripos($this->getConf('status_special'),$a_status) !== false) continue; 623 $y=$y+1; 624 // check if status image or text to be displayed 625 if ($noStatIMG == false) { 626 $status_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($a_status))).'.gif'; 627// if(!file_exists(str_replace("//", "/", DOKU_INC.$status_img))) { $status_img = $imgBASE . 'status.gif' ;} 628 $status_img =' class="it_center"><span style="display : none;">'.$a_status.'</span><img border="0" alt="'.$a_status.'" title="'.$a_status.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$status_img.'" width="16" height="16"/>'.NL; 629 } 630 else { $status_img = $style.$a_status; } 631 // check if severity image or text to be displayed 632 if ($noSevIMG == false) { 633 $severity_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($a_severity))).'.gif'; 634// if(!file_exists(str_replace("//", "/", DOKU_INC.$severity_img))) { $severity_img = $imgBASE . 'status.gif' ;} 635 $severity_img =' class="it_center"><span style="display : none;">'.$a_severity.'</span><img border="0" alt="'.$a_severity.'" title="'.$a_severity.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$severity_img.'" width="16" height="16"/>'.NL; 636 } 637 else { $severity_img = $style.$a_severity; } 638 639 640 $it_issue_username = $this->_get_one_value($issue,'user_name'); 641 $a_project = $this->_get_one_value($issue,'project'); 642 if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) 643 { $td_project = '<td class="itl__td_standard">'.$a_project.'</td>'; 644 } 645 646 // build parameter for $_GET method 647 $pstring = sprintf("showid=%s&project=%s", urlencode($this->_get_one_value($issue,'id')), urlencode($a_project)); 648 $itl_item_title = '<a href="doku.php?id='.$ID.'&do=showcaselink&'.$pstring.'" title="'.$this->_get_one_value($issue,'title').'">'.$this->_get_one_value($issue,'title').'</a>'.NL; 649 650 651 if((($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) || $project == $a_project ) 652 { if($rowEven==="it_roweven") $rowEven="it_rowodd"; 653 else $rowEven="it_roweven"; 654 $body .= '<tr id = "'.$a_project.' '.$this->_get_one_value($issue,'id').'" class="'.$rowEven.'" >'.NL. 655 $td_project.NL. 656 '<td class="itl__td_standard">'.$this->_get_one_value($issue,'id').'</td>'.NL. 657 '<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'created'))).'</td>'.NL. 658 '<td class="itl__td_standard">'.$this->_get_one_value($issue,'product').'</td>'.NL. 659 '<td class="itl__td_standard">'.$this->_get_one_value($issue,'version').'</td>'.NL. 660 '<td'.$severity_img.'</td>'.NL. 661 '<td'.$status_img.'</td>'.NL. 662 '<td class="canbreak itl__td_standard"><a href="mailto:'.$this->_get_one_value($issue,'user_mail').'">'.$it_issue_username.'</a></td>'.NL. 663 '<td class="canbreak itl__td_standard">'.$itl_item_title.'</td>'.NL; 664 665 // check how the assignee to be displayed: login, name or mail 666 $a_display = $this->_get_assignee($issue,'assigned'); 667 $body .= '<td class="canbreak itl__td_standard"><a href="mailto:'.$this->_get_one_value($issue,'assigned').'">'.$a_display.'</a></td>'.NL. 668 '<td class="canbreak itl__td_standard">'.$this->xs_format($this->_get_one_value($issue,'resolution')).'</td>'.NL. 669 '<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'modified'))).'</td>'.NL. 670 '</tr>'.NL; 671 } 672 } 673 } 674 $body .= '</tbody></table></div>'.NL; 675 } 676 677 else 678 { //$head = "<div class='issuetracker_div' ".$hdr_style."><table id='".$project."' class=\"sortable resizable inline\"><thead><thead><tr><th class=\"sortfirstdesc\" id='id'>Id</th><th id='Status'>Status</th><th id='Severity'>Severity</th><th id='Created'>Created</th><th id='Version'>Version</th><th id='User'>User</th><th id='Description'>Description</th><th id='assigned'>assigned</th><th id='Resolution'>Resolution</th><th id='Modified'>Modified</th></tr></thead>"; 679 $dynatable_id = "t_".uniqid((double)microtime()*1000000,1); 680 //Build table header according settings or syntax 681 if(strlen($data['columns'])>0) { 682 $configs = explode(',', strtolower($data['columns'])); 683 } 684 else { 685 $configs = explode(',', $this->getConf('shwtbl_usr')) ; 686 } 687 688 689 if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) 690 { $th_project = "<th id='project'>".$this->getLang('th_project')."</th>"; } 691 692 $reduced_header =''; 693 $reduced_header = "<div class='itl__table'><table id='".$dynatable_id."' class='sortable resizable inline' width='100%'>".NL. 694 "<thead><tr>".NL.$th_project.NL."<th class='".$this->getConf('listview_sort')."' id='id'>".$this->getLang('th_id')."</th>".NL; 695 696 foreach ($configs as $config) 697 { 698 $reduced_header .= "<th id='".$config."'>".$this->getLang('th_'.$config)."</th>".NL; 699 } 700 701 $reduced_header .= "</tr></thead>".NL; 702 703 //Build rows according settings 704 $reduced_issues=''; 705 for ($i=$next_start-1;$i>=0;$i=$i-1) 706 { // check start and end of rows to be displayed 707 if($i>count($issues)) break; // prevent the php-warning 708 $issue = $issues[$i]; 709 $a_project = strtolower($this->_get_one_value($issue,'project')); 710 $a_status = strtolower($this->_get_one_value($issue,'status')); 711 $a_severity = strtolower($this->_get_one_value($issue,'severity')); 712 $a_product = strtoupper($this->_get_one_value($issue,'product')); 713 $a_version = strtoupper($this->_get_one_value($issue,'version')); 714 $a_component = strtoupper($this->_get_one_value($issue,'component')); 715 $a_tblock = strtoupper($this->_get_one_value($issue,'tblock')); 716 $a_assignee = strtoupper($this->_get_one_value($issue,'assignee')); 717 $a_reporter = strtoupper($this->_get_one_value($issue,'user_name')); 718 719 if ((($data['status'] =='ALL') || (stristr($data['status'],$a_status) != false)) && 720 (($data['severity'] =='ALL') || (stristr($data['severity'],$a_severity) != false)) && 721 (($data['product'] =='ALL') || (stristr($data['product'],$a_product) != false)) && 722 (($data['version'] =='ALL') || (stristr($data['version'],$a_version) != false)) && 723 (($data['component'] =='ALL') || (stristr($data['component'],$a_component) != false)) && 724 (($data['assignee'] =='ALL') || (stristr($data['assignee'],$a_assignee) != false)) && 725 (($data['reporter'] =='ALL') || (stristr($data['reporter'],$a_reporter) != false)) && 726 (($data['myissues'] == false ) || ($this->_find_myissues($issue, $user_grp) == true))) 727 { 728 729 if (stripos($this->getConf('status_special'),$a_status) !== false) continue; 730 if((($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) || $project == $a_project ) 731 { if ($y>=$step) break; 732 $y=$y+1; 733 734 if($rowEven==="it_roweven") $rowEven="it_rowodd"; 735 else $rowEven="it_roweven"; 736 737 if(($this->getConf('multi_projects')!==0) && ($this->getConf('shw_project_col')!==0)) 738 { $a_project = $this->_get_one_value($issue,'project'); 739 $td_project = '<td class="itl__td_standard">'.$a_project.'</td>'; 740 } 741 else{$td_project="";} 742 743 $reduced_issues = $reduced_issues.'<tr id = "'.$a_project.' '.$this->_get_one_value($issue,'id').'" class="'.$rowEven.'" >'.NL. 744 $td_project.NL. 745 '<td'.$style.$this->_get_one_value($issue,'id').'</td>'.NL; 746 foreach ($configs as $config) 747 { 748 $isval = $this->_get_one_value($issue,strtolower($config)); 749 if ($config == 'status') 750 { 751 if ($noStatIMG == false) { 752 $status_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($isval))).'.gif'; 753 $reduced_issues .='<td class="it_center"><span style="display : none;">'.$a_status.'</span><img border="0" alt="'.$isval.'" title="'.$isval.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$status_img.'" width="16" height="16"/></td>'.NL; 754 } 755 else { $reduced_issues .= '<td'.$style.$isval.'</td>'.NL; } 756 } 757 elseif ($config == 'severity') 758 { 759 if ($noSevIMG == false) { 760 $severity_img = $imgBASE . implode('', explode(' ',$this->img_name_encode($isval))).'.gif'; 761 $reduced_issues .='<td class="it_center"><span style="display : none;">'.$a_severity.'</span><img border="0" alt="'.$isval.'" title="'.$isval.'" style="margin-right:0.5em" vspace="1" align="middle" src="'.$severity_img.'" width="16" height="16"/></td>'.NL; 762 } 763 else { $reduced_issues .= '<td'.$style.$isval.'</td>'.NL; } 764 } 765 elseif ($config == 'title') 766 { // build parameter for $_GET method 767 $pstring = sprintf("showid=%s&project=%s", urlencode($this->_get_one_value($issue,'id')), urlencode($a_project)); 768 $reduced_issues .='<td>'. 769 '<a href="doku.php?id='.$ID.'&do=showcaselink&'.$pstring.'" title="'.$isval.'">'.$isval.'</a></td>'.NL; 770 } 771 elseif ($config == 'created') 772 { $reduced_issues .='<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'created'))).'</td>'.NL; 773 } 774 elseif ($config == 'modified') 775 { $reduced_issues .='<td class="itl__td_date">'.date($this->getConf('d_format'),strtotime($this->_get_one_value($issue,'modified'))).'</td>'.NL; 776 } 777 elseif ($config == 'resolution') 778 { $reduced_issues .='<td class="canbreak itl__td_standard">'.$this->xs_format($this->_get_one_value($issue,'resolution')).'</td>'.NL; 779 } 780 elseif ($config == 'description') 781 { $reduced_issues .='<td class="canbreak itl__td_standard">'.$this->xs_format($this->_get_one_value($issue,'description')).'</td>'.NL; 782 } 783 else 784 { 785 $reduced_issues .= '<td'.$style.$isval.'</td>'.NL; 786 } 787 } 788 $reduced_issues .= '</tr>'.NL; 789 } 790 } 791 } 792 793 $head = NL.$reduced_header.NL; 794 $body = '<tbody>'.$reduced_issues.'</tbody>'.NL.'</table>'.NL.'</div>'.NL; 795 } 796// ----------------------------------------------------------------------------- 797// Control render 798 if($data['myissues']==false) {$data['myissues'] = "";} 799 else {$data['myissues'] = "checked='true'";} 800 801 if($data['tblock']==false) { $data['tblock'] = ""; } 802 else $data['tblock'] = "checked='true'"; 803 804 if (strtolower($data['controls'])==='on') { 805 $a_result = $this->_count_render($issues,$start,$step,$next_start,$data,$project); 806 $li_count =$a_result[1]; 807 $count = $a_result[0]; 808 809 $ret = '<div>'.NL. 810 '<script type="text/javascript">'.NL. 811 ' function changeAction(where) {'.NL. 812 ' if(where==1) {'.NL. 813 ' document.forms["myForm"].action = "doku.php?id=' . $ID . '&do=issuelist_previous";'.NL. 814 ' }'.NL. 815 ' else if(where==2){'.NL. 816 ' document.forms["myForm"].action = "doku.php?id=' . $ID . '&do=issuelist_next";'.NL. 817 ' }'.NL. 818 ' else if(where==3){'.NL. 819 ' document.forms["myForm"].action = "doku.php?id=' . $ID . '&do=issuelist_filter";'.NL. 820 ' }'.NL. 821 ' document.forms["myForm"].submit();'.NL. 822 ' }'.NL. 823 ' </script>'.NL. 824 '<table class="itl__t1"><tbody>'.NL. 825 '<tr class="itd__tables_tr">'.NL. 826 ' <td colspan="4" align="left" valign="middle" height="30">'.NL. 827 ' <label class="it__cir_projectlabel">'.sprintf($this->getLang('lbl_issueqty'),$project).$count.'</label>'.NL. 828 ' </td>'.NL. 829 ' <td class="itl__showdtls" rowspan="2" width="30%">'.$li_count.'</td>'.NL. 830 '</tr>'.NL. 831 832 '<tr class="itd__tables_tr">'.NL. 833 ' <td align ="left" valign="top" width="15%">'.NL; 834 835 $ret .= ' <p class="it__cir_projectlabel">'.'<label for="itl_step" style="align:left;">'.$this->getLang('lbl_scroll') .'</label><br />'.NL; 836 if(stripos($this->getConf('ltdListFilters'),'Filter Severity')=== false) $ret .= '<label for="itl_sev_filter" style="align:left;">'.$this->getLang('lbl_filtersev') .'</label><br />'.NL; 837 if(stripos($this->getConf('ltdListFilters'),'Filter Status')=== false) $ret .= '<label for="itl_stat_filter" style="align:left;">'.$this->getLang('lbl_filterstat') .'</label><br />'.NL; 838 $ret .= '</p><p class="it__cir_projectlabel">'.NL; 839 if(stripos($this->getConf('ltdListFilters'),'Filter Product')=== false) $ret .= '<label for="itl__prod_filter" style="align:left;">'.$this->getLang('lbl_filterprod') .'</label><br />'.NL; 840 if(stripos($this->getConf('ltdListFilters'),'Filter Version')=== false) $ret .= '<label for="itl__vers_filter" style="align:left;">'.$this->getLang('lbl_filtervers') .'</label><br />'.NL; 841 if(stripos($this->getConf('ltdListFilters'),'Filter Component')=== false) $ret .= '<label for="itl__comp_filter" style="align:left;">'.$this->getLang('lbl_filtercomp') .'</label><br />'.NL; 842 $ret .= '</p><p class="it__cir_projectlabel">'.NL; 843 if(stripos($this->getConf('ltdListFilters'),'Filter Test blocking')=== false) $ret .= '<label for="itl__block_filter" style="align:left;">'.$this->getLang('lbl_filterblock') .'</label><br />'.NL; 844 if(stripos($this->getConf('ltdListFilters'),'Filter Assignee')=== false) $ret .= '<label for="itl__assi_filter" style="align:left;">'.$this->getLang('lbl_filterassi') .'</label><br />'.NL; 845 if(stripos($this->getConf('ltdListFilters'),'Filter Reporter')=== false) $ret .= '<label for="itl__user_filter" style="align:left;">'.$this->getLang('lbl_filterreporter').'</label><br />'.NL; 846 $ret .= '</p><p class="it__cir_projectlabel">'.NL; 847 if(stripos($this->getConf('ltdListFilters'),'MyIssues')=== false) $ret .= '<label for="itl_myis_filter" style="align:left;">'.$this->getLang('cbx_myissues') .'</label><br />'.NL; 848 if(stripos($this->getConf('ltdListFilters'),'Sort by')=== false) $ret .= '<label for="it_glbl_sort" style="align:left;">'.$this->getLang('lbl_sort') .'</label>'.NL; 849 $ret .= '</p></td>'.NL; 850 851 $ret .= ' <td align ="left" valign="top" width="25%">'.NL. 852 ' <form name="myForm" action="" method="post">'.NL. 853 ' <input type="hidden" name="itl_start" id="itl_start" value="'.$start.'"/>'.NL. 854 ' <input type="hidden" name="itl_step" id="itl_step" value="'.$step.'"/>'.NL. 855 ' <input type="hidden" name="itl_next" id="itl_next" value="'.$next_start.'"/>'.NL. 856 ' <input type="hidden" name="itl_project" id="itl_project" value="'.$project.'"/>'.NL. 857 ' <input type="hidden" name="it_th_cols" id="it_th_cols" value="'.$data['columns'].'"/>'.NL. 858 ' <input class="itl__buttons" type="button" name="showprevious" value="'.$this->getLang('btn_previuos').'" title="'.$this->getLang('btn_previuos_title').'" onClick="changeAction(1)"/>'.NL. 859 ' <input class="itl__step_input" type="text" name="itl_step" id="itl_step" value="'.$step.'"/>'.NL. 860 ' <input class="itl__buttons" type="button" name="shownext" value="'.$this->getLang('btn_next').'" title="'.$this->getLang('btn_next_title').'" onClick="changeAction(2)"/><br />'.NL; 861 862 if(stripos($this->getConf('ltdListFilters'),'Filter Severity')=== false) $ret .= '<input class="itl__sev_filter" type="text" name="itl_sev_filter" id="itl_sev_filter" value="'.$data['severity'].'"/><br />'.NL; 863 if(stripos($this->getConf('ltdListFilters'),'Filter Status')=== false) $ret .= '<input class="itl__stat_filter" type="text" name="itl_stat_filter" id="itl_stat_filter" value="'.$data['status'].'"/><br /></p>'.NL; 864 $ret .= '</p><p>'.NL; 865 if(stripos($this->getConf('ltdListFilters'),'Filter Product')=== false) $ret .= '<input class="itl__prod_filter" type="text" name="itl__prod_filter" id="itl__prod_filter" value="'.$data['product'].'"/><br />'.NL; 866 if(stripos($this->getConf('ltdListFilters'),'Filter Version')=== false) $ret .= '<input class="itl__prod_filter" type="text" name="itl__vers_filter" id="itl__vers_filter" value="'.$data['version'].'"/><br />'.NL; 867 if(stripos($this->getConf('ltdListFilters'),'Filter Component')=== false) $ret .= '<input class="itl__prod_filter" type="text" name="itl__comp_filter" id="itl__comp_filter" value="'.$data['component'].'"/><br /></p>'.NL; 868 $ret .= '</p><p>'.NL; 869 if(stripos($this->getConf('ltdListFilters'),'Filter Test blocking')=== false) $ret .= '<input type="checkbox" name="itl__block_filter" id="itl__block_filter" ' .$data['tblock'].'/><br />'.NL; 870 if(stripos($this->getConf('ltdListFilters'),'Filter Assignee')=== false) $ret .= '<input class="itl__prod_filter" type="text" name="itl__assi_filter" id="itl__assi_filter" value="'.$data['assignee'].'"/><br />'.NL; 871 if(stripos($this->getConf('ltdListFilters'),'Filter Reporter')=== false) $ret .= '<input class="itl__prod_filter" type="text" name="itl__user_filter" id="itl__user_filter" value="'.$data['reporter'].'"/><br />'.NL; 872 $ret .= '</p><p>'.NL; 873 if(stripos($this->getConf('ltdListFilters'),'MyIssues')=== false) $ret .= '<input type="checkbox" name="itl_myis_filter" id="itl_myis_filter" ' .$data['myissues'].' title="'.$this->getLang('cbx_myissues').'" /><br />'.NL; 874 if(stripos($this->getConf('ltdListFilters'),'Sort by')=== false) $ret .= '<input class="itl__sev_filter" type="text" name="it_glbl_sort" id="it_glbl_sort" value="'.$data['sort'].'"/><br /></p>'.NL; 875 $ret .= '</p><input class="itl__buttons" type="button" name="go" value="'.$this->getLang('btn_go').'" title="'.$this->getLang('btn_go').'" onClick="changeAction(3)"/><br />'.NL; 876 $ret .= '</form>'.NL. 877 ' </td>'.NL. 878 ' <td width="2%"> </td>'.NL. 879 ' <td class="itl__showdtls" align ="left" width="40%">'.NL. 880 ' <form method="post" action="doku.php?id=' . $ID . '&do=showcase">'.NL. 881 ' <label class="it__searchlabel">'.$this->getLang('lbl_showid').'</label>'.NL. 882 ' <input class="itl__sev_filter" type="text" name="showid" id="showid" value="0"/>'.NL. 883 ' <input type="hidden" name="project" id="project" value="'.$project.'"/>'.NL. 884 ' <input type="hidden" name="itl_sev_filter" id="itl_sev_filter" value="'.$data['severity'].'"/>'.NL. 885 ' <input type="hidden" name="itl_stat_filter" id="itl_stat_filter" value="'.$data['status'].'"/>'.NL. 886 ' <input type="hidden" name="itl_myis_filter" id="itl_myis_filter" ' .$data['myissues'].' />'.NL. 887 ' <input class="itl__showid_button" type="submit" name="showcase" id="showcase" value="'.$this->getLang('btn_showid').'" title="'.$this->getLang('btn_showid_title').'"/>'.NL. 888 ' </form><br />'.NL. 889 ' <form method="post" action="doku.php?id=' . $ID . '&do=it_search">'.NL. 890 ' <label class="it__searchlabel">'.$this->getLang('lbl_search').'</label>'.NL. 891 ' <input class="itl__sev_filter" type="text" name="it_str_search" id="it_str_search" value="'.$search.'"/>'.NL. 892 ' <input type="hidden" name="project" id="project" value="'.$project.'"/>'.NL. 893 ' <input class="itl__search_button" type="submit" name="searchcase" id="searchcase" value="'.$this->getLang('btn_search').'" title="'.$this->getLang('btn_search_title').'"/>'.NL. 894 ' </form>'.NL. 895 ' </td>'.NL. 896 '</tr>'.NL.'</tbody>'.NL.'</table>'.NL.'</div>'.NL; 897 } 898 899 900 $usr = '<span style="display:none;" id="currentuser">'.$user_grp['userinfo']['name'].'</span>' ; //to log issue mods 901 $usr .= '<span style="display:none;" id="currentID">'.urlencode($ID).'</span>' ; // to log issue mods 902 $a_lang = '<span style="display:none;" name="table_kit_OK" id="table_kit_OK">'.$this->getLang('table_kit_OK').'</span>'; // for tablekit.js 903 $a_lang .= '<span style="display:none;" name="table_kit_Cancel" id="table_kit_Cancel">'.$this->getLang('table_kit_Cancel').'</span>'; // for tablekit.js 904 $ret = $a_lang.$usr.$ret.$head.$body; 905 return $ret; 906 } 907/******************************************************************************/ 908/* pic-up a single value 909*/ 910 function _get_one_value($issue, $key) { 911 if (@array_key_exists($key,$issue)) 912 return $issue[$key]; 913 return ''; 914 } 915 916/******************************************************************************/ 917/* elaborate the display string of assignee (login, name or mail) 918*/ 919 function _get_assignee($issue, $key) { 920 if(!$issue) return; 921 if (array_key_exists($key,$issue)) { 922 global $auth; 923 global $conf; 924 $filter['grps'] = $this->getConf('assign'); 925 $usr_array = $auth->retrieveUsers(0,0,$filter); 926 $shw_assignee_as = trim($this->getConf('shw_assignee_as')); 927 if(stripos("login, mail, name",$shw_assignee_as) === false) $shw_assignee_as = "login"; 928 foreach ($usr_array as $u_key => $usr) 929 { if($usr['mail']==$issue[$key]) 930 { if ($shw_assignee_as=='login') { return $u_key; } 931 elseif($shw_assignee_as=='mail') { return $usr['mail']; } 932 else { return $usr['name']; } 933 } 934 } 935 } 936 if(stripos("mail",$shw_assignee_as) !== false) return $issue[$key]; 937 else { 938 $b_display = explode("@",$issue[$key]); 939 return $b_display[0]; 940 } 941 } 942/******************************************************************************/ 943/* send an e-mail to admin due to new issue created 944*/ 945 function _emailForNewIssue($project,$issue,$email_to) 946 { 947 if ($this->getConf('send_email')==1) 948 { global $ID; 949 950 if ($this->getConf('mail_templates')==1) { 951 // load user html mail template 952 $sFilename = DOKU_PLUGIN.'issuetracker/mailtemplate/new_issue_mail.html'; 953 $bodyhtml = file_get_contents($sFilename); 954 } 955 $subject=sprintf($this->getLang('issuenew_subject'),$issue['severity'], $project, $issue['product'],$issue['version']); 956 $subject= mb_encode_mimeheader($subject, "UTF-8", "Q" ); 957 $pstring = sprintf("showid=%s&project=%s", urlencode($issue['id']), urlencode($project)); 958 959 $body = $this->getLang('issuenew_head').chr(10).chr(10). 960 $this->getLang('issuenew_intro').chr(10). 961 $this->getLang('issuemod_title').$issue['title'].chr(10). 962 $this->getLang('issuemod_issueid').$issue['id'].chr(10). 963 $this->getLang('issuemod_product').$issue['product'].chr(10). 964 $this->getLang('issuemod_version').$issue['version'].chr(10). 965 $this->getLang('issuemod_severity').$issue['severity'].chr(10). 966 $this->getLang('issuemod_status').$issue['status'].chr(10). 967 $this->getLang('issuemod_creator').$issue['user_name'].chr(10). 968 $this->getLang('th_assigned').$issue['assigned'].chr(10).chr(10). 969 $this->getLang('issuenew_descr').$this->xs_format($issue['description']).chr(10).chr(10). 970 $this->getLang('issuemod_see').DOKU_URL.'doku.php?id='.$ID.'&do=showcaselink&'.$pstring.chr(10).chr(10). 971 $this->getLang('issuemod_br').chr(10).$this->getLang('issuemod_end'); 972 973 $body = html_entity_decode($body); 974 if ($this->getConf('mail_templates')==1) $bodyhtml = $this->replace_bodyhtml($bodyhtml, $pstring, $project, $issue, $comment); 975 $from=$email_to ; 976 $to=$from; 977 $cc=$issue['add_user_mail']; 978 if ($this->getConf('mail_templates')==1) { 979 $headers = "Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable"; 980 $this->mail_send_html($to, $subject, $body, $bodyhtml, $from, $cc, $bcc='', $headers, $params=null); 981 } 982 else { 983 mail_send($to, $subject, $body, $from, $cc, $bcc='', $headers=null, $params=null); 984 } 985 } 986 } 987 988/******************************************************************************/ 989 /*********************************** 990 * HTML Mail functions 991 * 992 * Sends HTML-formatted mail 993 * By Lin Junjie (mail [dot] junjie [at] gmail [dot] com) 994 * 995 ***********************************/ 996 function mail_send_html($to, $subject, $body, $bodyhtml, $from='', $cc='', $bcc='', $header='', $params=null){ 997 if(defined('MAILHEADER_ASCIIONLY')){ 998 $subject = utf8_deaccent($subject); 999 $subject = utf8_strip($subject); 1000 } 1001 if(!defined('MAILHEADER_EOL')) define('MAILHEADER_EOL',"\n"); 1002 if(!utf8_isASCII($subject)) { 1003 $subject = '=?UTF-8?Q?'.mail_quotedprintable_encode($subject,0).'?='; 1004 // Spaces must be encoded according to rfc2047. Use the "_" shorthand 1005 $subject = preg_replace('/ /', '_', $subject); 1006 } 1007 1008 $header = ''; 1009 1010 $usenames = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? false : true; 1011 1012 $random_hash = md5(date('r', time())); // added 1013 1014 $to = mail_encode_address($to,'',$usenames); 1015 $header .= mail_encode_address($from,'From'); 1016 $header .= mail_encode_address($cc,'Cc'); 1017 $header .= mail_encode_address($bcc,'Bcc'); 1018 $header .= 'MIME-Version: 1.0'.MAILHEADER_EOL; 1019 $header .= "Content-Type: multipart/alternative; boundary=PHP-alt-".$random_hash.MAILHEADER_EOL; 1020 $header = trim($header); 1021 1022 1023 $body = mail_quotedprintable_encode($body,0); 1024 $bodyhtml = mail_quotedprintable_encode($bodyhtml,0); 1025 1026 $message = "--PHP-alt-".$random_hash."\r\n". 1027 "Content-Type: text/plain; charset=UTF-8"."\n". 1028 "Content-Transfer-Encoding: quoted-printable"."\n\n". 1029 $body."\n\n". 1030 "--PHP-alt-".$random_hash."\r\n". 1031 "Content-Type: text/html; charset=UTF-8"."\n". 1032 "Content-Transfer-Encoding: quoted-printable"."\n\n". 1033 $bodyhtml."\n". 1034 "--PHP-alt-".$random_hash."--"; 1035 1036 if($params == null){ 1037 return mail($to,$subject,$message,$header); 1038 }else{ 1039 return mail($to,$subject,$message,$header,$params); 1040 } 1041 } 1042/******************************************************************************/ 1043 function replace_bodyhtml($bodyhtml, $pstring, $project, $issue, $comment) { 1044 global $ID; 1045 $bodyhtml = str_ireplace("%%_SEE%%",DOKU_URL.'doku.php?id='.$ID.'&do=showcaselink&'.$pstring,$bodyhtml); 1046 $bodyhtml = str_ireplace("%%issuemod_head%%",$this->getLang('issuemod_head'),$bodyhtml); 1047 $bodyhtml = str_ireplace("%%issuemod_issueid%%",$this->getLang('issuemod_issueid'),$bodyhtml); 1048 $bodyhtml = str_ireplace("%%ID%%",$issue['id'],$bodyhtml); 1049 $bodyhtml = str_ireplace("%%issuemod_title%%",$this->getLang('issuemod_title'),$bodyhtml); 1050 $bodyhtml = str_ireplace("%%TITEL%%",$issue['title'],$bodyhtml); 1051 $bodyhtml = str_ireplace("%%issuemod_status%%",$this->getLang('issuemod_status'),$bodyhtml); 1052 $bodyhtml = str_ireplace("%%STATUS%%",$issue['status'],$bodyhtml); 1053 $bodyhtml = str_ireplace("%%th_project%%",$this->getLang('th_project'),$bodyhtml); 1054 $bodyhtml = str_ireplace("%%PROJECT%%",$project,$bodyhtml); 1055 $bodyhtml = str_ireplace("%%issuemod_product%%",$this->getLang('issuemod_product'),$bodyhtml); 1056 $bodyhtml = str_ireplace("%%PRODUCT%%",$issue['product'],$bodyhtml); 1057 $bodyhtml = str_ireplace("%%issuemod_version%%",$this->getLang('issuemod_version'),$bodyhtml); 1058 $bodyhtml = str_ireplace("%%VERSION%%",$issue['version'],$bodyhtml); 1059 $bodyhtml = str_ireplace("%%issuemod_severity%%",$this->getLang('issuemod_severity'),$bodyhtml); 1060 $bodyhtml = str_ireplace("%%SEVERITY%%",$issue['severity'],$bodyhtml); 1061 $bodyhtml = str_ireplace("%%issuemod_creator%%",$this->getLang('issuemod_creator'),$bodyhtml); 1062 $bodyhtml = str_ireplace("%%CREATOR%%",$issue['user_name'],$bodyhtml); 1063 $bodyhtml = str_ireplace("%%CREATOR_MAIL%%",$issue['user_mail'],$bodyhtml); 1064 $bodyhtml = str_ireplace("%%th_assigned%%",$this->getLang('th_assigned'),$bodyhtml); 1065 $bodyhtml = str_ireplace("%%ASSIGNED%%",$issue['assigned'],$bodyhtml); 1066 $bodyhtml = str_ireplace("%%th_created%%",$this->getLang('th_created'),$bodyhtml); 1067 $bodyhtml = str_ireplace("%%CREATED%%",$issue['created'],$bodyhtml); 1068 1069 $bodyhtml = str_ireplace("%%issue_resolved_intro%%",$this->getLang('issue_resolved_intro'),$bodyhtml); 1070 $bodyhtml = str_ireplace("%%issue_resolved_text%%",$this->getLang('issue_resolved_text'),$bodyhtml); 1071 $frmt_res = str_ireplace(chr(10),"<br />",$issue['resolution']); 1072 $bodyhtml = str_ireplace("%%RESOLUTION%%",$this->xs_format($frmt_res),$bodyhtml); 1073 $bodyhtml = str_ireplace("%%TIMESTAMP%%",date($this->getConf('d_format')),$bodyhtml); 1074 1075 $user_grp = pageinfo(); 1076 $usr = $user_grp['userinfo']['name'] ; 1077 $bodyhtml = str_ireplace("%%RESOLVER%%",$usr,$bodyhtml); 1078 $bodyhtml = str_ireplace("%%MOD_BY%%",$usr,$bodyhtml); 1079 $bodyhtml = str_ireplace("%%issuedescrmod_subject%%",sprintf($this->getLang('issuedescrmod_subject'),$issue['id'], $project),$bodyhtml); 1080 $bodyhtml = str_ireplace("%%th_description%%",$this->getLang('th_description'),$bodyhtml); 1081 $frmt_descr = str_ireplace(chr(10),"<br />",$issue['description']); 1082 $bodyhtml = str_ireplace("%%DESCRIPTION%%",$this->xs_format($frmt_descr),$bodyhtml); 1083 1084 1085// if($comment) { 1086 $bodyhtml = str_ireplace("%%lbl_cmts_wlog%%",$this->getLang('lbl_cmts_wlog'),$bodyhtml); 1087 $bodyhtml = str_ireplace("%%CMNT_ID%%",$comment['id'],$bodyhtml); 1088 $bodyhtml = str_ireplace("%%CMNT_AUTHOR%%",$comment['author'],$bodyhtml); 1089 $bodyhtml = str_ireplace("%%CMNT_TIMESTAMP%%",date($this->getConf('d_format'),strtotime($comment['timestamp'])),$bodyhtml); 1090 $frmt_cmnt = str_ireplace(chr(10),"<br />",$comment['comment']); 1091 $bodyhtml = str_ireplace("%%COMMENT%%",$this->xs_format($frmt_cmnt),$bodyhtml); 1092// } 1093 $bodyhtml = str_ireplace("%%issuemod_br%%",$this->getLang('issuemod_br'),$bodyhtml); 1094 $bodyhtml = str_ireplace("%%issuemod_end%%",$this->getLang('issuemod_end'),$bodyhtml); 1095 1096 return $bodyhtml; 1097 } 1098/******************************************************************************/ 1099/* Report an Issue 1100*/ 1101 function _report_render($data) 1102 { 1103 global $lang; 1104 global $ID; 1105 $imgBASE = DOKU_BASE."lib/plugins/issuetracker/images/"; 1106 $project = $data['project']; 1107 1108 // retrive some basic information 1109 $user_mail = pageinfo(); //to get mail address of reporter 1110 $cur_date = date($this->getConf('d_format')); 1111 $user_check = $this->getConf('registered_users'); 1112 1113 // check if current user is admin/assignee 1114 // check if syntax parameter asympupl is switched on 1115 $user_mail = pageinfo(); 1116 if(array_key_exists('userinfo', $user_mail)) 1117 { foreach ($user_mail['userinfo']['grps'] as $ugrp) 1118 { $user_grps = $user_grps . $ugrp; } 1119 } 1120 else 1121 { $user_grps = 'all'; } 1122 $allowed_users = explode('|', $this->getConf('assign')); 1123 $cFlag = false; 1124 foreach ($allowed_users as $w) 1125 { // check if one of the assigned user roles does match with current user roles 1126 if (strpos($user_grps,$w)!== false) 1127 { $cFlag = true; 1128 break; } 1129 } 1130 1131 $_cFlag = false; 1132 if($user_check == 0) { 1133 $_cFlag = true; } 1134 elseif (($user_check == 1) && ($user_mail['perm'] > 1)) { 1135 $_cFlag = true; } 1136 1137 if($_cFlag === true) { 1138 /*--------------------------------------------------------------------*/ 1139 // load set of projects defined by admin 1140 /*--------------------------------------------------------------------*/ 1141 $STR_PROJECT = ""; 1142 $l_projects = explode(',', $this->getConf('projects')) ; 1143 $STR_PROJECT = '<option value="" >'.$project.'</option>'.NL; 1144 foreach ($l_projects as $a_project) 1145 { 1146 $a_project = trim($a_project); 1147 $STR_PROJECT .= '<option value="'.$a_project.'" >'.$a_project."</option>".NL; 1148 } 1149 /*--------------------------------------------------------------------*/ 1150 // load set of product names defined by admin 1151 /*--------------------------------------------------------------------*/ 1152 if($data['prod_limit'] !== "OFF") { 1153 $temp2 = explode(',', $this->getConf('products')); 1154 foreach($temp2 as $a) { 1155 if(stripos(strtoupper($data['product']),strtoupper($a))!==false) { 1156 if(strlen($temp)<1){ 1157 $temp .= $a; 1158 } 1159 else $temp .= ','.$a; 1160 } 1161 } 1162 $products = explode(',', $temp); 1163 } 1164 else { 1165 $products = explode(',', $this->getConf('products')); 1166 } 1167 1168 $STR_PRODUCTS = ""; 1169 foreach ($products as $_products) 1170 { 1171 $x_products = trim($x_products); 1172 //if product is preselected by syntax 1173 if(strtoupper ($_products) == strtoupper ($data['product'])) { $option_param = '<option value="'.$_products.'" selected >'; } 1174 else { $option_param = '<option value="'.$_products.'" >'; } 1175 1176 $STR_PRODUCTS = $STR_PRODUCTS . $option_param .$_products."</option>".NL; 1177 } 1178 1179 /*--------------------------------------------------------------------*/ 1180 // load set of components defined by admin 1181 /*--------------------------------------------------------------------*/ 1182 $STR_COMPONENTS = ""; 1183 $components = explode(',', $this->getConf('components')) ; 1184// $STR_COMPONENTS = '<option value="" ></option>'.NL; 1185 foreach ($components as $_component) 1186 { 1187 $_component = trim($_component); 1188 $STR_COMPONENTS .= '<option value="'.$_component.'" >'.$_component."</option>".NL; 1189 } 1190 if($STR_COMPONENTS === "") $STR_COMPONENTS = '<option value="" ></option>'.NL; 1191 1192 /*--------------------------------------------------------------------*/ 1193 // load set of severity values defined by admin 1194 /*--------------------------------------------------------------------*/ 1195 $STR_SEVERITY = ""; 1196 $severity = explode(',', $this->getConf('severity')) ; 1197 foreach ($severity as $_severity) 1198 { 1199 $_severity = trim($_severity); 1200 $STR_SEVERITY = $STR_SEVERITY . '<option value="'.$_severity.'" >'.$_severity."</option>".NL; 1201 } 1202 1203 /*--------------------------------------------------------------------*/ 1204 // create the report template and check input on client site 1205 /*--------------------------------------------------------------------*/ 1206 if($this->getConf('wysiwyg')==true) { 1207 $_editor_java ='if ((document.getElementById("a_description").innerHTML.length <= 5) & (document.getElementById("a_description").innerHTML.indexOf(" ") == -1)) { 1208 alert ("'.$this->getLang('wmsg3').'"); 1209 frm.description.focus(); 1210 return false;}'; 1211 $_editor_java_2 ='function myFunction() { 1212 document.getElementById("description").value = document.getElementById("a_description").innerHTML; 1213 }'; 1214 $myFunc = 'onsubmit="myFunction()"'; 1215 1216 } 1217 else { 1218 $_editor_java ='if ((frm.description.value.length <= 5) & (frm.description.value.indexOf(" ") == -1)) { 1219 alert ("'.$this->getLang('wmsg3').'"); 1220 frm.description.focus(); 1221 return false;'; 1222 1223 $_editor_java_2 =''; 1224 $myFunc = 'onsubmit="return chkFormular(this)"'; 1225 } 1226 1227 $ret = '<div class="it__cir_form"><script> 1228 // JavaScript Document 1229 function chkFormular(frm) { 1230 1231 if (frm.product.value == "") { 1232 alert("Please select a valid product!"); 1233 frm.product.focus(); 1234 return false; 1235 } 1236 1237 if (frm.version.value == "") { 1238 alert("'.$this->getLang('wmsg2').'"); 1239 frm.version.focus(); 1240 return false; 1241 } 1242 1243 if (frm.user_name.value < 3) { 1244 alert("Please enter your user name!"); 1245 frm.user_name.focus(); 1246 return false; 1247 } 1248 1249 if (frm.user_mail.value.indexOf("@") == -1) { 1250 alert ("'.$this->getLang('wmsg1').'"); 1251 frm.user_mail.focus(); 1252 return false; 1253 } 1254 1255 if (frm.severity.value == "") { 1256 alert ("Please select a severity"); 1257 frm.severity.focus(); 1258 return false; 1259 } 1260 1261 if ((frm.ittitle.value.length <= 5) & (frm.ittitle.value.indexOf(" ") == -1)) { 1262 alert ("'.$this->getLang('wmsg5').'"); 1263 frm.ittitle.focus(); 1264 return false; 1265 } 1266 1267 '.NL.$_editor_java.NL.' 1268 } 1269 '.NL.$_editor_java_2.NL.' 1270 }</script>'.NL; 1271 $ret .= '<form class="issuetracker__form" name="issuetracker__form" method="post" '.$myFunc.' accept-charset="'.$lang['encoding'].'" enctype="multipart/form-data" ><p>'.NL. 1272 formSecurityToken(false). 1273 '<input type="hidden" name="do" value="show" />'.NL. 1274 '<input type="hidden" name="id" value="'.$ID.'" />'.NL. 1275 '<input type="hidden" name="created" value="'.$cur_date.'"/>'.NL. 1276// '<input type="hidden" name="comments" value="'.$comments_file.'"/>'. 1277 '</p>'.NL. 1278 '<table class="it_form_table"> 1279 <tr> 1280 <td>'.$this->getLang('th_project').'</td>'.NL; 1281 1282 //Check config if hidden 1283 if($this->getConf('projects')==""){ 1284 $ret .= '<td><label class="it__cir_projectlabel">'.$project.'</label></td>'.NL; } 1285 else { 1286 $ret .='<td><select class="element select small it__cir_select" name="project">'.$STR_PROJECT.'</select></td>'.NL; 1287 } 1288 $ret .= '</tr>'.NL. 1289 '<tr> 1290 <td>'.$this->getLang('th_product').'</td> 1291 <td><select class="element select small it__cir_select" name="product">'.$STR_PRODUCTS.'</select></td> 1292 </tr>'.NL. 1293 '<tr>'; 1294 //Check config if hidden 1295 if(strpos($this->getConf('ltdReport'),'Version')!==false){ 1296 $STR_VERSIONS = ' '; 1297 $ret .= ' <input type="hidden" class="it__cir_input" name="version" value="'.$STR_VERSIONS.'"/>'; 1298 } 1299 else { 1300 $ret .= ' <td>'.$this->getLang('th_version').'</td> 1301 <td><input class="it__cir_input" name="version" value="'.$STR_VERSIONS.'"/></td>'; 1302 } 1303 1304 $ret .= '</tr><tr>'.NL; 1305 //Check config if hidden 1306 if(strpos($this->getConf('ltdReport'),'Components')!==false){ 1307 $STR_COMPONENTS = ' '; 1308 $ret .= '<input type="hidden" class="it__cir_input" name="component" value="'.$STR_COMPONENTS.'"/>'; 1309 } 1310 else { 1311 $ret .='<td>'.$this->getLang('th_components').'</td> 1312 <td><select class="element select small it__cir_select" name="component">'.$STR_COMPONENTS.'</select></td>'.NL; 1313 } 1314 $ret .= '</tr><tr>'.NL; 1315 1316 //Check config if hidden 1317 if(strpos($this->getConf('ltdReport'),'Test blocking')!==false){ 1318 $ret .= '<input type="hidden" name="tblock" value="false">'; 1319 } 1320 else { 1321 $ret .='<td>'.$this->getLang('th_tblock').'</td> 1322 <td><input class="it__cir_cbx" type="checkbox" name="tblock"></td>'.NL; 1323 } 1324 1325 $ret .= '</tr><tr><td colspan=2> </td></tr>'.NL. 1326 '<tr> 1327 <td>'.$this->getLang('th_user_name').'</td> 1328 <td><input class="it__cir_input" name="user_name" value="'.$user_mail['userinfo']['name'].'"/></td> 1329 </tr>'.NL. 1330 '<tr> 1331 <td>'.$this->getLang('th_usermail').'</td> 1332 <td><input class="it__cir_input" name="user_mail" value="'.$user_mail['userinfo']['mail'].'"/></td> 1333 </tr>'.NL. 1334 '<tr>'; 1335 //Check config if hidden 1336 if(strpos($this->getConf('ltdReport'),'User phone')!==false){ 1337 $ret .= ' <input type="hidden" class="it__cir_input" name="user_phone" value="'.$user_phone['userinfo']['phone'].'"/>'; 1338 } 1339 else { 1340 $ret .= ' <td>'.$this->getLang('th_userphone').'</td> 1341 <td><input class="it__cir_input" name="user_phone" value="'.$user_phone['userinfo']['phone'].'"/></td>'; 1342 } 1343 $ret .= '</tr>'.NL. 1344 '<tr>'; 1345 //Check config if hidden 1346 if(strpos($this->getConf('ltdReport'),'Add contact')!==false){ 1347 $ret .= ' <input type="hidden" class="it__cir_input" name="add_user_mail" value="'.$_REQUEST['add_user_mail'].'"/>'; 1348 } 1349 else { 1350 $ret .= ' <td>'.$this->getLang('th_reporteradcontact').'</td> 1351 <td><input class="it__cir_input" name="add_user_mail" value="'.$_REQUEST['add_user_mail'].'"/></td>'; 1352 } 1353 $ret .= '</tr>'.NL. 1354 '<tr><td colspan=2> </td></tr>'.NL. 1355 '<tr>'; 1356 //Check config if hidden 1357 if(strpos($this->getConf('ltdReport'),'Severity')!==false){ 1358 $severity = explode(',', $this->getConf('severity')) ; 1359 $STR_SEVERITY = $severity[0]; 1360 $ret .= ' <input type="hidden" class="it__cir_input" name="severity" value="'.$STR_SEVERITY.'"/>'; 1361 } 1362 else { 1363 $ret .= ' <td>'.$this->getLang('th_severity').'</td> 1364 <td><select class="element select small it__cir_select" name="severity">'.$STR_SEVERITY.'</select></td>'; 1365 } 1366 $ret .= '</tr>'.NL. 1367 '<tr> 1368 <td>'.$this->getLang('th_title').'</td> 1369 <td><input class="it__cir_linput" name="title" value="'.$_REQUEST['title'].'"/></td> 1370 </tr>'.NL. 1371 '<tr> 1372 <td>'.$this->getLang('th_description').'</td> 1373 <td>'.NL; 1374 1375// mod for editor --------------------------------------------------------------------- 1376// check the config setting what editor to be used 1377 if($this->getConf('wysiwyg')==true) 1378 { 1379 //hack if DOKU_BASE is not properly set 1380 if(strlen(DOKU_BASE) < strlen(DOKU_URL)) $sFilename = DOKU_URL."lib/plugins/issuetracker/wysiwyg_editor.js"; 1381 else $sFilename = DOKU_BASE."lib/plugins/issuetracker/wysiwyg_editor.js"; 1382 $ret .= '<script type="text/javascript" src="'.$sFilename.'"></script>'; 1383 $sFilename = DOKU_PLUGIN.'issuetracker/wysiwyg_editor.html'; 1384 $ret .= file_get_contents($sFilename); 1385 $ret = str_ireplace("%%DOKU_BASE%%",DOKU_BASE,$ret); 1386 $ret .= '<span class="reply_close_link"> 1387 <a href="javascript:resizeBoxId(\'description\', -20)"><img src="'.$imgBASE.'reduce.png" title="reduce textarea" style="float:right;" /></a> 1388 <a href="javascript:resizeBoxId(\'description\', +20)"><img src="'.$imgBASE.'enlarge.png" title="enlarge textarea" style="float:right;" /></a> 1389 </span>'.NL; 1390 $ret .= '<textarea id="description" name="description" style="display: none;">'.$_REQUEST['description'].'</textarea>'; 1391 1392 1393 } 1394 else 1395 { 1396 if(strlen(DOKU_BASE) < strlen(DOKU_URL)) $sFilename = DOKU_URL."lib/plugins/issuetracker/xsEditor.js"; 1397 else $sFilename = DOKU_BASE."lib/plugins/issuetracker/xsEditor.js"; 1398 $ret .= '<script type="text/javascript" src="'.$sFilename.'"></script>'; 1399 $ret .= file_get_contents($sFilename); 1400 global $_FILES; 1401 $ret .= $this->it_edit_toolbar('description'); 1402 $ret .= '<textarea class="it__cir_linput" id="description" name="description" cols="109" rows="7">'.$_REQUEST['description'].'</textarea></td></tr> 1403 <span class="reply_close_link"> 1404 <a href="javascript:resizeBoxId(\'description\', -20)"><img src="'.$imgBASE.'reduce.png" title="reduce textarea" style="float:right;" /></a> 1405 <a href="javascript:resizeBoxId(\'description\', +20)"><img src="'.$imgBASE.'enlarge.png" title="enlarge textarea" style="float:right;" /></a> 1406 </span>'.NL; 1407 } 1408// mod for editor --------------------------------------------------------------------- 1409 1410 $ret .= '<tr><td colspan=2> </td></tr>'; 1411 // check if symptom file upload is allowed 1412 if(($this->getConf('upload')>0) || (($cFlag === true) && ($data['asympupl']=true))) { 1413 //Check config if hidden 1414 if(($cFlag === true) && ($data['asympupl']=true)) { 1415 $ret .= '<tr><td>'.$this->getLang('th_sympt').'1</td> 1416 <td><input type="file" class="it__cir_linput" name="attachment1" value="'.$_REQUEST['attachment1'].'"/></td></tr>'; 1417 } 1418 elseif(strpos($this->getConf('ltdReport'),'Symptom link 1')!==false){ 1419 $ret .= ' <input type="hidden" class="it__cir_linput" name="attachment1" value="'.$_REQUEST['attachment1'].'"/>'; 1420 } 1421 else { 1422 $ret .= '<tr><td>'.$this->getLang('th_sympt').'1</td> 1423 <td><input type="file" class="it__cir_linput" name="attachment1" value="'.$_REQUEST['attachment1'].'"/></td></tr>'; 1424 } 1425 if(strpos($this->getConf('ltdReport'),'Symptom link 2')!==false){ 1426 $ret .= ' <input type="hidden" class="it__cir_linput" name="attachment2" value="'.$_REQUEST['attachment2'].'"/>'; 1427 } 1428 else { 1429 $ret .= '<tr><td>'.$this->getLang('th_sympt').'2</td> 1430 <td><input type="file" class="it__cir_linput" name="attachment2" value="'.$_REQUEST['attachment2'].'"/></td></tr>'; 1431 } 1432 if(strpos($this->getConf('ltdReport'),'Symptom link 3')!==false){ 1433 $ret .= ' <input type="hidden" class="it__cir_linput" name="attachment3" value="'.$_REQUEST['attachment3'].'"/>'; 1434 } 1435 else { 1436 $ret .= '<tr><td>'.$this->getLang('th_sympt').'3</td> 1437 <td><input type="file" class="it__cir_linput" name="attachment3" value="'.$_REQUEST['attachment3'].'"/></td></tr>'; 1438 } 1439 } 1440 $ret .= '</table><p><input type="hidden" name="modified" value="'.$cur_date.'"/>'.NL. 1441 '<input type="hidden" name="assigned" value="" />'.NL; 1442 1443 if ($this->getConf('use_captcha')==1) 1444 { 1445 $helper = null; 1446 if(@is_dir(DOKU_PLUGIN.'captcha')) 1447 $helper = plugin_load('helper','captcha'); 1448 1449 if(!is_null($helper) && $helper->isEnabled()) 1450 { 1451 $ret .= '<p>'.$helper->getHTML().'</p>'; 1452 } 1453 } 1454 //<input name="do[save]" type="submit" value="Save" class="button" id="edbtn__save" accesskey="s" tabindex="4" title="Save [S]" /> 1455 $ret .= '</p><p><input name="submit" type="submit" value="'.$this->getLang('btn_reportsave').'" class="button" id="edbtn__save" title="'.$this->getLang('btn_reportsave').'"/>'. 1456 '</p></form></div>'.NL; 1457 } 1458 // the user maybe registered within group "all" but the registered flag is turned on 1459 // eigther the user has to be moved into group "user" or the flag to be switched off 1460 elseif(($user_mail['perm'] < 2) && (strlen($user_mail['userinfo']['mail'])>1)) { 1461 $issue_edit_resolution ='<table class="itd__tables"> 1462 <tr> 1463 <td class="itd_tables_tdh" colSpan="2" >'.$this->getLang('th_resolution').'</td> 1464 </tr>'; 1465 $issue_edit_resolution .= '<tr class="itd__tables_tr"> 1466 <td width="1%"></td> 1467 <td>'.$this->xs_format($x_resolution).'</td> 1468 </tr></table>'.NL; 1469 1470 $wmsg = $this->getLang('lbl_lessPermission'); 1471 $issue_edit_resolution .= '<div class="it__standard_feedback">'.$wmsg.'</div>'; 1472 } 1473 else { 1474 $ret .= '<div class="it__standard_feedback">'.$this->getLang('wmsg4').'</div>'; 1475 } 1476 1477 return $ret; 1478 } 1479/******************************************************************************/ 1480/* Display positive/negative message box according user input on submit->Report 1481*/ 1482 function _show_message($string){ 1483 return "<script type='text/javascript'> 1484 alert('$string'); 1485 </script>"; 1486 } 1487 1488/******************************************************************************/ 1489/* improved implode needed 1490*/ 1491 function array_implode($arrays, &$target = array()) 1492 { 1493 foreach ($arrays as $item) { 1494 if (is_array($item)) { 1495 $this->array_implode($item, $target); 1496 } else { 1497 $target[] = $item; 1498 } 1499 } 1500 return $target; 1501 } 1502 1503/******************************************************************************/ 1504/** http://www.linuxjournal.com/article/9585?page=0,0 1505Validate an email address. 1506Provide email address (raw input) 1507Returns true if the email address has the email 1508address format and the domain exists. 1509*/ 1510 function validEmail($email) 1511 { 1512 $isValid = true; 1513 $atIndex = strrpos($email, "@"); 1514 if (is_bool($atIndex) && !$atIndex) 1515 { 1516 $isValid = false; 1517 } 1518 else 1519 { 1520 $domain = substr($email, $atIndex+1); 1521 $local = substr($email, 0, $atIndex); 1522 $localLen = strlen($local); 1523 $domainLen = strlen($domain); 1524 if ($localLen < 1 || $localLen > 64) 1525 { 1526 // local part length exceeded 1527 $isValid = false; 1528 } 1529 else if ($domainLen < 1 || $domainLen > 255) 1530 { 1531 // domain part length exceeded 1532 $isValid = false; 1533 } 1534 else if ($local[0] == '.' || $local[$localLen-1] == '.') 1535 { 1536 // local part starts or ends with '.' 1537 $isValid = false; 1538 } 1539 else if (preg_match('/\\.\\./', $local)) 1540 { 1541 // local part has two consecutive dots 1542 $isValid = false; 1543 } 1544 else if (!preg_match('/^[A-Za-z0-9\\-\\.]+$/', $domain)) 1545 { 1546 // character not valid in domain part 1547 $isValid = false; 1548 } 1549 else if (preg_match('/\\.\\./', $domain)) 1550 { 1551 // domain part has two consecutive dots 1552 $isValid = false; 1553 } 1554 else if 1555 (!preg_match('/^(\\\\.|[A-Za-z0-9!#%&`_=\\/$\'*+?^{}|~.-])+$/', 1556 str_replace("\\\\","",$local))) 1557 { 1558 // character not valid in local part unless local part is quoted 1559 if (!preg_match('/^"(\\\\"|[^"])+"$/', 1560 str_replace("\\\\","",$local))) 1561 { 1562 $isValid = false; 1563 } 1564 } 1565 1566 if((!function_exists('checkdnsrr')) && ($this->getConf('validate_mail_addr')==true)) 1567 { 1568 function checkdnsrr($host, $type='') 1569 { 1570 if(!empty($host)) 1571 { 1572 $type = (empty($type)) ? 'MX' : $type; 1573 exec('nslookup -type='.$type.' '.escapeshellcmd($host), $result); 1574 $it = new ArrayIterator($result); 1575 foreach(new RegexIterator($it, '~^'.$host.'~', RegexIterator::GET_MATCH) as $result) 1576 { 1577 if($result) { return true; } 1578 } 1579 } 1580 return false; 1581 } 1582 } 1583 else if ($isValid && !(checkdnsrr($domain,"MX") || checkdnsrr($domain,"A")) && ($this->getConf('validate_mail_addr')==true)) 1584 { 1585 // domain not found in DNS 1586 $isValid = false; 1587 } 1588 } 1589 return $isValid; 1590 } 1591/******************************************************************************/ 1592/* replace simple formats used by editor buttons 1593*/ 1594 function xs_format($x_comment) 1595 { // bold , italic, underline, etc. 1596 $x_comment = preg_replace('/\[([bius])\]/i', '<\\1>', $x_comment); 1597 $x_comment = preg_replace('/\[\/([bius])\]/i', '</\\1>', $x_comment); 1598 1599 $x_comment = preg_replace('/\[ol\]/i', '<ol>', $x_comment); 1600 $x_comment = preg_replace('/\[\/ol\]/i', '</ol>', $x_comment); 1601 1602 $x_comment = preg_replace('/\[ul\]/i', '<ul>', $x_comment); 1603 $x_comment = preg_replace('/\[\/ul\]/i', '</ul>', $x_comment); 1604 1605 $x_comment = preg_replace('/\[li\]/i', '<li>', $x_comment); 1606 $x_comment = preg_replace('/\[\/li\]/i', '</li>', $x_comment); 1607 1608 $x_comment = preg_replace('/\[sup\]/i', '<sup>', $x_comment); 1609 $x_comment = preg_replace('/\[\/sup\]/i', '</sup>', $x_comment); 1610 1611 $x_comment = preg_replace('/\[sub\]/i', '<sub>', $x_comment); 1612 $x_comment = preg_replace('/\[\/sub\]/i', '</sub>', $x_comment); 1613 1614 $x_comment = preg_replace('/\[hr\]/i', '<hr>', $x_comment); 1615 1616 $x_comment = preg_replace('/\[blockquote\]/i', '<blockquote>', $x_comment); 1617 $x_comment = preg_replace('/\[\/blockquote\]/i', '</blockquote>', $x_comment); 1618 1619 $x_comment = preg_replace('/\[code\]/i', '<div class="it_code"><code>', $x_comment); 1620 $x_comment = preg_replace('/\[\/code\]/i', '</code></div>', $x_comment); 1621 1622 $x_comment = preg_replace('/\[red\]/i', '<span style="color:red;">', $x_comment); 1623 $x_comment = preg_replace('/\[\/red\]/i', '</span>', $x_comment); 1624 1625 $x_comment = preg_replace('/\[grn\]/i', '<span style="color:green;">', $x_comment); 1626 $x_comment = preg_replace('/\[\/grn\]/i', '</span>', $x_comment); 1627 1628 $x_comment = preg_replace('/\[bgy\]/i', '<span style="background:yellow;">', $x_comment); 1629 $x_comment = preg_replace('/\[\/bgy\]/i', '</span>', $x_comment); 1630 1631 $x_comment = preg_replace('/\[blu\]/i', '<span style="color:blue;">', $x_comment); 1632 $x_comment = preg_replace('/\[\/blu\]/i', '</span>', $x_comment); 1633 1634 $urlsuch[]="/([^]_a-z0-9-=\"'\/])((https?|ftp):\/\/|www\.)([^ \r\n\(\)\^\$!`\"'\|\[\]\{\}<>]*)/si"; 1635 $urlsuch[]="/^((https?|ftp):\/\/|www\.)([^ \r\n\(\)\^\$!`\"'\|\[\]\{\}<>]*)/si"; 1636 $urlreplace[]="\\1[link]\\2\\4[/link]"; 1637 $urlreplace[]="[link]\\1\\3[/link]"; 1638 $x_comment = preg_replace($urlsuch, $urlreplace, $x_comment); 1639 $x_comment = preg_replace("/\[link\]www.(.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"http://www.\\1\">www.\\1</a>", $x_comment); 1640 $x_comment = preg_replace("/\[link=www.(.*?)\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"http://www.\\1\">\\2</a>", $x_comment); 1641 $x_comment = preg_replace("/\[link\](\:.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"doku.php?id=\\1\">\\1</a>", $x_comment); 1642 $x_comment = preg_replace("/\[link=(\:.*?)\]\[\/link\]/si", "<a target=\"_blank\" href=\"doku.php?id=\\1\">\\1</a>", $x_comment); 1643 $x_comment = preg_replace("/\[link=(\:.*?)\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"doku.php?id=\\1\">\\2</a>", $x_comment); 1644 $x_comment = preg_replace("/\[link\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"\\1\">\\1</a>", $x_comment); 1645 $x_comment = preg_replace("/\[link=(.*?)\](.*?)\[\/link\]/si", "<a target=\"_blank\" href=\"\\1\">\\2</a>", $x_comment); 1646 1647 $x_comment = preg_replace("/\[img\](http.*?)\[\/img\]/si", "<img src=\"\\1\"title=\"\\1\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment); 1648 $x_comment = preg_replace("/\[img=(http.*?)\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\2\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment); 1649 $x_comment = preg_replace("/\[img\](file.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\1\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment); 1650 $x_comment = preg_replace("/\[img=(file.*?)\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\2\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment); 1651 $x_comment = preg_replace("/\[img\](\:.*?)\[\/img\]/si", "<img src=\"". DOKU_URL . "lib/exe/fetch.php?media=\\1\" title=\"\\1\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment); 1652 $x_comment = preg_replace("/\[img=(\:.*?)\](.*?)\[\/img\]/si", "<img src=\"". DOKU_URL . "lib/exe/fetch.php?media=\\1\" title=\"\\2\" alt=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment); 1653 $x_comment = preg_replace("/\[img\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\1\" style=\"max-width:850px;\" \/>", $x_comment); 1654 $x_comment = preg_replace("/\[img=(.*?)\](.*?)\[\/img\]/si", "<img src=\"\\1\" title=\"\\2\" style=\"max-width:850px;\" \/>", $x_comment); 1655 1656 1657 1658/*--------------------------------------------------------------------------------- 1659* think about parsing content by dokuwiki renderer for dokuwiki syntax recognition 1660* $x_comment = p_render('xhtml',p_get_instructions($x_comment),$info); 1661* take care to strip IssueTracker syntax to prevent endless loop 1662---------------------------------------------------------------------------------*/ 1663 1664 return $x_comment; 1665 } 1666/******************************************************************************/ 1667/* return html-code for edit toolbar 1668*/ 1669 function it_edit_toolbar($type) { 1670 $imgBASE = DOKU_BASE."lib/plugins/issuetracker/images/"; 1671 $it_edit_tb = '<div class="itr_edittoolbar">'.NL; 1672 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."bold.png\" name=\"btnBold\" title=\"Bold\" onClick=\"doAddTags('[b]','[/b]','$type')\">".NL; 1673 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."italic.png\" name=\"btnItalic\" title=\"Italic\" onClick=\"doAddTags('[i]','[/i]','$type')\">".NL; 1674 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."underline.png\" name=\"btnUnderline\" title=\"Underline\" onClick=\"doAddTags('[u]','[/u]','$type')\">".NL; 1675 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."strikethrough.png\" name=\"btnStrike\" title=\"Strike through\" onClick=\"doAddTags('[s]','[/s]','$type')\">".NL; 1676 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."subscript.png\" name=\"btnSubscript\" title=\"Subscript\" onClick=\"doAddTags('[sub]','[/sub]','$type')\">".NL; 1677 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."superscript.png\" name=\"btnSuperscript\" title=\"Superscript\" onClick=\"doAddTags('[sup]','[/sup]','$type')\">".NL; 1678 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."hr.png\" name=\"btnLine\" title=\"hLine\" onClick=\"doHLine('[hr]','$type')\">".NL; 1679 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."ordered.png\" name=\"btn_o_List\" title=\"Ordered List\" onClick=\"doList('[ol]','[/ol]','$type')\">".NL; 1680 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."unordered.png\" name=\"btn_u_List\" title=\"Unordered List\" onClick=\"doList('[ul]','[/ul]','$type')\">".NL; 1681 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."quote.png\" name=\"btnQuote\" title=\"Quote\" onClick=\"doAddTags('[blockquote]','[/blockquote]','$type')\">".NL; 1682 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."code.png\" name=\"btnCode\" title=\"Code\" onClick=\"doAddTags('[code]','[/code]','$type')\">".NL; 1683 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."pen_red.png\" name=\"btnRed\" title=\"Red\" onClick=\"doAddTags('[red]','[/red]','$type')\">".NL; 1684 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."pen_green.png\" name=\"btnGreen\" title=\"Green\" onClick=\"doAddTags('[grn]','[/grn]','$type')\">".NL; 1685 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."pen_blue.png\" name=\"btnBlue\" title=\"Blue\" onClick=\"doAddTags('[blu]','[/blu]','$type')\">".NL; 1686 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."bg_yellow.png\" name=\"btn_bgYellow\" title=\"bgYellow\" onClick=\"doAddTags('[bgy]','[/bgy]','$type')\">".NL; 1687 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."link.png\" name=\"btn_link\" title=\"Link\" onClick=\"doAddTags('[link]','[/link]','$type')\">".NL; 1688 $it_edit_tb .= "<img class=\"xseditor_button\" src=\"".$imgBASE."img.png\" name=\"btn_img\" title=\"Image - max width 850px\" onClick=\"doAddTags('[img]','[/img]','$type')\">".NL; 1689 $it_edit_tb .= "<a href=\"http://www.imageshack.us/\" target=\"_blank\"><<img class=\"xseditor_button\" src=\"".$imgBASE."imageshack.png\" name=\"btn_ishack\" title=\"ImageShack upload (ext TaC !)\">></a>".NL; 1690 $it_edit_tb .= "<br></div>".NL; 1691 return $it_edit_tb; 1692 } 1693/******************************************************************************/ 1694/* log issue modificaions 1695 * who changed what and when per issue 1696*/ 1697 function _log_mods($project, $issue, $usr, $column, $new_value) 1698 { global $conf; 1699 // get mod-log file contents 1700 if($this->getConf('it_data')==false) $modfile = DOKU_CONF."../data/meta/".$project.'_'.$issue_id.'.mod-log'; 1701 else $modfile = DOKU_CONF."../". $this->getConf('it_data').$project.'_'.$issue_id.'.mod-log'; 1702 if (@file_exists($modfile)) 1703 {$mods = unserialize(@file_get_contents($modfile));} 1704 else 1705 {$mods = array();} 1706 1707 $mod_id = count($mods); 1708 1709 $mods[$mod_id]['timestamp'] = date ($this->getConf('d_format')); 1710 $mods[$mod_id]['user'] = $usr; 1711 $mods[$mod_id]['field'] = $column; 1712 $mods[$mod_id]['old_value'] = $old_value; 1713 $mods[$mod_id]['new_value'] = $new_value; 1714 1715 // Save issues file contents 1716 $fh = fopen($modfile, 'w'); 1717 fwrite($fh, serialize($mods)); 1718 fclose($fh); 1719 } 1720/******************************************************************************/ 1721/* replace special characters in file names like German "Umlaute" 1722*/ 1723 function img_name_encode($f_name) { 1724 $umlaute = $this->getLang('umlaute'); 1725 $replace = $this->getLang('conv_umlaute'); 1726 if((count($umlaute)>1) && (count($replace)>1)) $f_name = preg_replace($umlaute, $replace, $f_name); 1727 $f_name = strtolower($f_name); 1728 return $f_name; 1729 } 1730/******************************************************************************/ 1731/* upload a file if valid on mime type and file extension 1732*/ 1733 function _symptom_file_upload(&$issues, $issue_id, $attachment_id) { 1734 global $conf; 1735 if($this->getConf('it_data')==false) $target_path = "data/meta/"; 1736 else $target_path = $this->getConf('it_data'); 1737 $ip_block_path = $target_path."ipblock"; 1738 $target_path .= 'symptoms/'; 1739 if(!is_dir(DOKU_CONF."../".$target_path)) { mkdir(DOKU_CONF."../".$target_path, 0777); } 1740 1741 $valid_file_extensions = array(); 1742 $valid_mimetypes = array(); 1743 $mimetypes = getMimeTypes(); 1744 1745 foreach($mimetypes as $key => $value) { 1746 $valid_file_extensions[] = $key; 1747 $valid_mimetypes[] = $value; 1748 } 1749 1750 if($this->getConf('ip_blocked') == 1){ 1751 $ip_blocked_sec = $this->getConf('ip_blockd_time')*60; 1752 1753 // search folder ipblock 1754 if(is_dir(DOKU_INC.$ip_block_path)) { 1755 $path = openDir(DOKU_INC.$ip_block_path); 1756 while(false !== ($filename = readdir($path))){ 1757 if($filename != "." && $filename != ".."){ 1758 // delete aged ipblocks 1759 if(file_exists(DOKU_INC.$ip_block_path.'/'.$filename)) { 1760 $t_check = filemtime(DOKU_INC.$ip_block_path.'/'.$filename)+$ip_blocked_sec; 1761 if($t_check <= time()) { @unlink(DOKU_INC.$ip_block_path.'/'.$filename); } 1762 } 1763 } 1764 } 1765 closedir($path); 1766 } 1767 else { 1768 mkdir(DOKU_INC.$ip_block_path.'/', 0777); 1769 } 1770 1771 $ip_addr = $_SERVER['REMOTE_ADDR']; 1772 if($ip_addr == "") { 1773 if(getenv(HTTP_X_FORWARDED_FOR)) { $ip_addr = getenv('HTTP_X_FORWARD_FOR'); } 1774 else { $ip_addr = getenv('REMOTE_ADDR'); } 1775 } 1776 1777 if($ip_addr != ""){ 1778 // check if ip already known 1779 if(file_exists(DOKU_INC.$ip_block_path.'/'.$ip_addr)) { 1780 // check upload remaining attempts (to be larger than 0) 1781 $iplog = fopen(DOKU_INC.$ip_block_path.'/'.$ip_addr, "r"); 1782 $attachments_left=fread($iplog, filesize(DOKU_INC.$ip_block_path.'/'.$ip_addr)); 1783 fclose($iplog); 1784 if($attachments_left<1) { 1785 $error_code = 1; 1786 $t_check = intval((filemtime(DOKU_INC.$ip_block_path.'/'.$filename)+$ip_blocked_sec-time())/60); 1787 msg(sprintf($this->getLang('wmsg9'), $t_check),-1); 1788 } 1789 } 1790 else $attachments_left = 3; 1791 } 1792 } 1793 1794 if(isset($error_code)){ 1795 $t_check = intval((filemtime(DOKU_INC.$ip_block_path.'/'.$filename)+$ip_blocked_sec-time())/60); 1796 $Generated_Header = '<div class="it__negative_feedback">'.sprintf($this->getLang('wmsg9'), $t_check).'</div>'; 1797 $renderer->doc .= $Generated_Header; 1798 return; 1799 } 1800 1801 // get file extension 1802 $mime_type = $_FILES[$attachment_id]['type']; 1803 $file_extension = strrchr($_FILES[$attachment_id]['name'],'.'); // last occurance of dot to detect extension 1804 $file_dot_extension = strtolower($file_extension); 1805 $file_extension = str_replace(".", "", strtolower($file_dot_extension)); 1806 $error_flag = 0; 1807 1808 // check validity of file extension 1809 if(!in_array($file_extension, $valid_file_extensions)) { 1810 $error_flag = 1; 1811 $Generated_Header .= '<span>'.$this->getLang('wmsg7').' (File: <b>'.$_FILES[$attachment_id]['name'].'</b>)</span><br>'; 1812 } 1813 // check mime type 1814 if((!in_array($mime_type, $valid_mimetypes)) && (!in_array("!".$mime_type, $valid_mimetypes)) ) { 1815 $error_flag = 1; 1816 $Generated_Header .= '<span>'.$this->getLang('wmsg8').' (File: <b>'.$_FILES[$attachment_id]['name'].', Mime-Type: '.$mime_type.'</b>)</span><br>'; 1817 } 1818 // check file-size 1819 if($_FILES[$attachment_id]['size'] > ($this->getConf('max_fsize'))){ 1820 $error_flag = 1; 1821 $Generated_Header .= '<span>'.sprintf($this->getLang('wmsg6'), $this->getConf('max_fsize')).' (File: <b>'.$_FILES[$attachment_id]['name'].'</b>)</span><br>'; 1822 } 1823// ----------------------------------------------------------------------------- 1824 if($error_flag > 0) { 1825 echo $Generated_Header = '<div class="it__negative_feedback">'.$Generated_Header.'</div>'; 1826 } 1827 else { 1828 //$safe_filename = preg_replace(array("/\s+/", "/[^-\.\w]+/"),array("_", ""),trim(basename( $_FILES[$attachment_id]['name']))); 1829 // delete all other characters beside the following defined 1830 $safe_filename = preg_replace('#[^A-Za-z0-9_.-]#', '',trim(basename( $_FILES[$attachment_id]['name']))); 1831 $target_path = $target_path . $issue_id . '_sympt_' . $safe_filename; 1832 if(move_uploaded_file($_FILES[$attachment_id]['tmp_name'], DOKU_INC.$target_path)) { 1833 $attachments_left = $attachments_left-1; 1834 $issues[$issue_id]['attachment1'] = DOKU_URL.$target_path; 1835// msg("The file ".$safe_filename." has been successfully uploaded to ".DOKU_URL.$target_path,1); 1836 msg("The file ".$safe_filename." has been successfully uploaded.",1); 1837 } else{ 1838// msg("There was an error uploading the file to ".DOKU_URL.$target_path." \n, please try again!",-1); 1839 msg("There was an error uploading the file, please try again!",-1); 1840 } 1841// ----------------------------------------------------------------------------- 1842 // block ip 1843 if($this->getConf('ip_blocked') == 1) { 1844 $ip_addr=$_SERVER['REMOTE_ADDR']; 1845 if($ip_addr==""){ 1846 if(getenv(HTTP_X_FORWARDED_FOR)) { $ip_addr = getenv('HTTP_X_FORWARD_FOR'); } 1847 else { $ip_addr = getenv('REMOTE_ADDR'); } 1848 } 1849 if(!is_dir(DOKU_INC.$ip_block_path) && ($ip_addr != "")) { 1850 @mkdir(DOKU_INC.$ip_block_path.'/', 0777); 1851 $iplog = fopen(DOKU_INC.$ip_block_path.'/'.$ip_addr, "w+"); 1852 fwrite($iplog, $attachments_left); 1853 fclose($iplog); 1854 } 1855 elseif($ip_addr != ""){ 1856 $iplog = fopen(DOKU_INC.$ip_block_path.'/'.$ip_addr, "w+"); 1857 fwrite($iplog, $attachments_left); 1858 fclose($iplog); 1859 } 1860 } 1861 } 1862// ----------------------------------------------------------------------------- 1863 return $Generated_Header; 1864 } 1865/******************************************************************************/ 1866 function __find_projects($path) { 1867 if(!is_dir($path)) return false; // prevent the php-warning 1868 if ($handle=opendir($path)) { 1869 while (false!==($file=readdir($handle))) { 1870 if ($file<>"." AND $file<>"..") { 1871 if (is_file($path.'/'.$file)) { 1872 $ext = explode('.',$file); 1873 $last = count($ext) - 1; 1874 if ($ext[$last] == 'issues') { 1875 $projects .= ','.substr($file,0,strlen($file)-strlen('.issues')); 1876 } 1877 } 1878 } 1879 } 1880 } 1881 return $projects; 1882 } 1883/******************************************************************************/ 1884/* 1885 * Check for MyIssues 1886 * 1887 * Check if the issue is related to the current user 1888 * the user maybe the issue reporter, assignee or registered as follower 1889 * it will return true/false 1890 * 1891 * @author Taggic <taggic@t-online.de> 1892 * @param array $issue the single issue 1893 * @param array $user the current user info 1894 * @return bool true if foo in bar 1895 * 1896 */ 1897 1898 function _find_myissues($issue, $user) { 1899 // current user is issue reporter 1900 if($user['userinfo']['mail'] === $issue['user_mail']) return true; 1901 1902 // current user is assigned to this issue 1903 if($user['userinfo']['mail'] === $issue['assigned']) return true; 1904 1905 // current user is registered as follower within the comments log of actual issue 1906 if(stristr($issue['add_user_mail'],$user['userinfo']['mail']) !== false) return true; 1907 1908 // else return false 1909 return false; 1910 } 1911/******************************************************************************/ 1912/* 1913 * Load all issues into an array 1914 * 1915 * Check if multi_project is set to true 1916 * Load current $project or all projects of it_data_store 1917 * Return the issues array 1918 * 1919 * @author Taggic <taggic@t-online.de> 1920 * @param array $data 1921 * @return $issues 1922 * 1923 */ 1924 1925 function _get_issues($data, $all = false) { 1926 // detect the IssueTracker data store (path) 1927 if($this->getConf('it_data')==false) $it_datastore = DOKU_CONF."../data/meta/"; 1928 else $it_datastore = DOKU_CONF."../". $this->getConf('it_data'); 1929 1930 // check if last sign is a slash 1931 $i = strrchr ($it_datastore, chr(47)); // chr(47) = "/" 1932 $j = strrchr ($it_datastore, chr(92)); // chr(92) = "\" 1933 if(($i !== strlen($it_datastore)) && ($i !== strlen($it_datastore))) { $it_datastore .= chr(47); } 1934 1935 if(($this->getConf('multi_projects')!==false) && ($all !== false)) { 1936 // loop through it_datastore and list all .issues files 1937 $xprojects = $this->__find_projects($it_datastore); 1938 1939 $x_projects = explode(',',$xprojects); 1940 $issues = array(); 1941 $tmp = array(); 1942 1943 foreach ($x_projects as $project) 1944 { $project = trim($project); 1945 if(is_file($it_datastore.$project.'.issues') == true) { 1946 $tmp = unserialize(@file_get_contents($it_datastore.$project.'.issues')); 1947 1948 // loop through the field and add project to each row 1949 foreach($tmp as &$tmps) 1950 { $tmps['project'] = $project; } 1951 1952 $issues = array_merge($issues, $tmp); 1953 $tmp = array(); 1954 } 1955 } 1956 } 1957 else { 1958 // get issues from single project file 1959 if($this->getConf('it_data')==false) $pfile = $it_datastore.$data['project'].'.issues'; 1960 else $pfile = $it_datastore.$data['project'].'.issues'; 1961 1962 if (@file_exists($pfile)) 1963 {$issues = unserialize(@file_get_contents($pfile));} 1964 else 1965 {$issues = array();} 1966 } 1967 1968 return $issues; 1969 } 1970/******************************************************************************/ 1971/* sort the issues array according the selected key */ 1972 function _issues_globalsort($issues, $sort_key) { 1973/* $tmp = Array(); 1974 foreach($issues as &$ma) $tmp[] = &$ma[$sort_key]; 1975 array_multisort($tmp, $issues); */ 1976 foreach ($issues as $key => $row) { 1977 $down[$key] = $row['id']; 1978 $up[$key] = $row[$sort_key]; 1979 } 1980 if($up) { @array_multisort($up, constant($this->getConf('global_sort')), $down, SORT_ASC, $issues); } 1981 return $issues; 1982 } 1983} 1984