1<?php 2# MantisBT - A PHP based bugtracking system 3 4# MantisBT is free software: you can redistribute it and/or modify 5# it under the terms of the GNU General Public License as published by 6# the Free Software Foundation, either version 2 of the License, or 7# (at your option) any later version. 8# 9# MantisBT is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with MantisBT. If not, see <http://www.gnu.org/licenses/>. 16 17/** 18 * Columns API 19 * 20 * @package CoreAPI 21 * @subpackage ColumnsAPI 22 * @copyright Copyright 2000 - 2002 Kenzaburo Ito - kenito@300baud.org 23 * @copyright Copyright 2002 MantisBT Team - mantisbt-dev@lists.sourceforge.net 24 * @link http://www.mantisbt.org 25 * 26 * @uses access_api.php 27 * @uses bug_api.php 28 * @uses category_api.php 29 * @uses config_api.php 30 * @uses constant_inc.php 31 * @uses custom_field_api.php 32 * @uses date_api.php 33 * @uses error_api.php 34 * @uses event_api.php 35 * @uses file_api.php 36 * @uses helper_api.php 37 * @uses icon_api.php 38 * @uses lang_api.php 39 * @uses prepare_api.php 40 * @uses print_api.php 41 * @uses project_api.php 42 * @uses sponsorship_api.php 43 * @uses string_api.php 44 */ 45 46require_api( 'access_api.php' ); 47require_api( 'bug_api.php' ); 48require_api( 'category_api.php' ); 49require_api( 'columns_api.php' ); 50require_api( 'config_api.php' ); 51require_api( 'constant_inc.php' ); 52require_api( 'custom_field_api.php' ); 53require_api( 'date_api.php' ); 54require_api( 'error_api.php' ); 55require_api( 'event_api.php' ); 56require_api( 'file_api.php' ); 57require_api( 'helper_api.php' ); 58require_api( 'icon_api.php' ); 59require_api( 'lang_api.php' ); 60require_api( 'prepare_api.php' ); 61require_api( 'print_api.php' ); 62require_api( 'project_api.php' ); 63require_api( 'sponsorship_api.php' ); 64require_api( 'string_api.php' ); 65 66/** 67 * Filters an array of columns based on configuration options. The filtering can remove 68 * columns whose features are disabled. 69 * 70 * @param array $p_columns The columns proposed for display. 71 * @return array The columns array after removing the disabled features. 72 */ 73function columns_filter_disabled( array $p_columns ) { 74 $t_columns = array(); 75 $t_enable_profiles = ( config_get( 'enable_profiles' ) == ON ); 76 77 foreach ( $p_columns as $t_column ) { 78 switch( $t_column ) { 79 case 'os': 80 case 'os_build': 81 case 'platform': 82 if( ! $t_enable_profiles ) { 83 continue 2; 84 } 85 break; 86 87 case 'eta': 88 if( config_get( 'enable_eta' ) == OFF ) { 89 continue 2; 90 } 91 break; 92 93 case 'projection': 94 if( config_get( 'enable_projection' ) == OFF ) { 95 continue 2; 96 } 97 break; 98 99 case 'build': 100 if( config_get( 'enable_product_build' ) == OFF ) { 101 continue 2; 102 } 103 break; 104 105 case 'sponsorship_total': 106 if( config_get( 'enable_sponsorship' ) == OFF ) { 107 continue 2; 108 } 109 break; 110 111 default: 112 # don't filter 113 break; 114 } 115 $t_columns[] = $t_column; 116 } # continued 2 117 118 return $t_columns; 119} 120 121/** 122 * Get a list of standard columns. 123 * @param boolean $p_enabled_columns_only Default true, if false returns all columns regardless of configuration settings. 124 * @return array of column names 125 */ 126function columns_get_standard( $p_enabled_columns_only = true ) { 127 $t_reflection = new ReflectionClass( 'BugData' ); 128 $t_columns = $t_reflection->getDefaultProperties(); 129 130 $t_columns['selection'] = null; 131 $t_columns['edit'] = null; 132 $t_columns['notes'] = null; 133 $t_columns['tags'] = null; 134 135 # Overdue icon column (icons appears if an issue is beyond due_date) 136 $t_columns['overdue'] = null; 137 138 # The following fields are used internally and don't make sense as columns 139 unset( $t_columns['_stats'] ); 140 unset( $t_columns['profile_id'] ); 141 unset( $t_columns['sticky'] ); 142 unset( $t_columns['loading'] ); 143 144 # legacy field 145 unset( $t_columns['duplicate_id'] ); 146 147 $t_column_names = array_keys( $t_columns ); 148 149 if( $p_enabled_columns_only ) { 150 $t_column_names = columns_filter_disabled( $t_column_names ); 151 } 152 153 return $t_column_names; 154} 155 156/** 157 * Allow plugins to define a set of class-based columns, and register/load 158 * them here to be used by columns_api. 159 * @return array Mapping of column name to column object 160 */ 161function columns_get_plugin_columns() { 162 static $s_column_array = null; 163 164 if( is_null( $s_column_array ) ) { 165 $s_column_array = array(); 166 167 $t_all_plugin_columns = event_signal( 'EVENT_FILTER_COLUMNS' ); 168 foreach( $t_all_plugin_columns as $t_plugin => $t_plugin_columns ) { 169 foreach( $t_plugin_columns as $t_callback => $t_plugin_column_array ) { 170 if( is_array( $t_plugin_column_array ) ) { 171 foreach( $t_plugin_column_array as $t_column_item ) { 172 if( is_object( $t_column_item ) && $t_column_item instanceof MantisColumn ) { 173 $t_column_object = $t_column_item; 174 } elseif( class_exists( $t_column_item ) && is_subclass_of( $t_column_item, 'MantisColumn' ) ) { 175 $t_column_object = new $t_column_item(); 176 } else { 177 continue; 178 } 179 $t_column_name = mb_strtolower( $t_plugin . '_' . $t_column_object->column ); 180 $s_column_array[$t_column_name] = $t_column_object; 181 } 182 } 183 } 184 } 185 } 186 187 return $s_column_array; 188} 189 190/** 191 * Get all columns for existing custom_fields 192 * @return string Array of column names 193 */ 194function columns_get_custom_fields() { 195 static $t_col_names = null; 196 if( isset( $t_col_names ) ) { 197 return $t_col_names; 198 } 199 200 $t_all_cfids = custom_field_get_ids(); 201 $t_col_names = array(); 202 foreach( $t_all_cfids as $t_id ) { 203 $t_col_names[] = column_get_custom_field_column_name( $t_id ); 204 } 205 return $t_col_names; 206} 207 208/** 209 * Get all columns active for the current system. 210 * This includes standard, custom fields, and plugin columns. 211 * Columns for disabled modules are removed from this list, according to system 212 * configuration. 213 * 214 * This function cannot check on current user/project, so it can be used by core 215 * in potential unlogged-in scenarios. 216 * @return array Array of column names 217 */ 218function columns_get_all_active_columns() { 219 $t_columns = array_merge( 220 columns_get_standard(), 221 array_keys( columns_get_plugin_columns() ), 222 columns_get_custom_fields() 223 ); 224 return columns_filter_disabled( $t_columns ); 225} 226 227/** 228 * Returns true if the specified $p_column is a plugin column. 229 * @param string $p_column A column name. 230 * @return boolean 231 */ 232function column_is_plugin_column( $p_column ) { 233 $t_plugin_columns = columns_get_plugin_columns(); 234 return isset( $t_plugin_columns[$p_column] ); 235} 236 237/** 238 * Get all accessible columns for the current project / current user. 239 * @param integer $p_project_id A project identifier. 240 * @return array array of columns 241 * @access public 242 */ 243function columns_get_all( $p_project_id = null ) { 244 $t_columns = columns_get_standard(); 245 246 # add plugin columns 247 $t_columns = array_merge( $t_columns, array_keys( columns_get_plugin_columns() ) ); 248 249 # Add project custom fields to the array. Only add the ones for which the current user has at least read access. 250 if( $p_project_id === null ) { 251 $t_project_id = helper_get_current_project(); 252 } else { 253 $t_project_id = $p_project_id; 254 } 255 # Get custom fields from this project and sub-projects 256 $t_projects = user_get_all_accessible_projects( null, $t_project_id ); 257 $t_related_custom_field_ids = custom_field_get_linked_ids( $t_projects ); 258 foreach( $t_related_custom_field_ids as $t_id ) { 259 $t_cfdef = custom_field_get_definition( $t_id ); 260 $t_projects_to_check = array_intersect( $t_projects, custom_field_get_project_ids( $t_id ) ); 261 if( access_has_any_project_level( (int)$t_cfdef['access_level_r'], $t_projects_to_check ) ) { 262 $t_columns[] = column_get_custom_field_column_name( $t_id ); 263 } 264 } 265 266 return $t_columns; 267} 268 269/** 270 * Checks if the specified column is an extended column. Extended columns are native columns that are 271 * associated with the issue but are saved in mantis_bug_text_table. 272 * @param string $p_column The column name. 273 * @return boolean true for extended; false otherwise. 274 * @access public 275 */ 276function column_is_extended( $p_column ) { 277 switch( $p_column ) { 278 case 'description': 279 case 'steps_to_reproduce': 280 case 'additional_information': 281 return true; 282 default: 283 return false; 284 } 285} 286 287/** 288 * Checks if the specified column is a custom field column. 289 * @param string $p_column The column name. 290 * @return boolean True if its a custom field column 291 */ 292function column_is_custom_field( $p_column ) { 293 $t_cf_columns = columns_get_custom_fields(); 294 return in_array( $p_column, $t_cf_columns ); 295} 296 297/** 298 * Checks if the specified column can be sorted 299 * @param string $p_column The column name. 300 * @return boolean True if the column can be sorted 301 */ 302function column_is_sortable( $p_column ) { 303 304 # custom fields are always sortable 305 if( column_is_custom_field( $p_column ) ) { 306 return true; 307 } 308 309 # plugin fields contains a 'sortable' property 310 if( column_is_plugin_column( $p_column ) ) { 311 $t_plugin_columns = columns_get_plugin_columns(); 312 $t_plugin_obj = $t_plugin_columns[$p_column]; 313 return $t_plugin_obj->sortable; 314 } 315 316 #standard fields: define exceptions here 317 switch( $p_column ) { 318 case 'selection': 319 case 'edit': 320 case 'bugnotes_count': 321 case 'attachment_count': 322 case 'tags': 323 case 'overdue': 324 case 'additional_information': 325 case 'description': 326 case 'notes': 327 case 'steps_to_reproduce': 328 return false; 329 } 330 331 # after all exceptions, return true as default 332 return true; 333} 334 335/** 336 * Given a column name from the array of columns to be included in a view, this method checks if 337 * the column is a custom column and if so returns its name. Note that for custom fields, then 338 * provided names will have the "custom_" prefix, where the returned ones won't have the prefix. 339 * 340 * @param string $p_column Column name. 341 * @return string The custom field column name or null if the specific column is not a custom field or invalid column. 342 * @access public 343 */ 344function column_get_custom_field_name( $p_column ) { 345 if( strncmp( $p_column, 'custom_', 7 ) === 0 ) { 346 return mb_substr( $p_column, 7 ); 347 } 348 349 return null; 350} 351 352/** 353 * Returns the name of a column corresponding to a custom field, providing the id as parameter. 354 * 355 * @param integer $p_cf_id Custom field id 356 * @return string The column name 357 */ 358function column_get_custom_field_column_name( $p_cf_id ) { 359 $t_def = custom_field_get_definition( $p_cf_id ); 360 if( $t_def ) { 361 return 'custom_' . $t_def['name']; 362 } else { 363 return null; 364 } 365} 366 367/** 368 * Converts a string of comma separate column names to an array. 369 * 370 * @param string $p_string Comma separate column name (not case sensitive). 371 * @return array The array with all column names lower case. 372 * @access public 373 */ 374function columns_string_to_array( $p_string ) { 375 $t_columns = explode( ',', $p_string ); 376 $t_count = count( $t_columns ); 377 378 for( $i = 0; $i < $t_count; $i++ ) { 379 $t_columns[$i] = trim( $t_columns[$i] ); 380 } 381 382 return $t_columns; 383} 384 385/** 386 * Gets the localized title for the specified column. The column can be native or custom. 387 * The custom fields must contain the 'custom_' prefix. 388 * 389 * @param string $p_column The column name. 390 * @return string The column localized name. 391 * @access public 392 */ 393function column_get_title( $p_column ) { 394 $t_custom_field = column_get_custom_field_name( $p_column ); 395 if( $t_custom_field !== null ) { 396 $t_field_id = custom_field_get_id_from_name( $t_custom_field ); 397 398 if( $t_field_id === false ) { 399 $t_custom_field = '@' . $t_custom_field . '@'; 400 } else { 401 $t_def = custom_field_get_definition( $t_field_id ); 402 $t_custom_field = lang_get_defaulted( $t_def['name'] ); 403 } 404 405 return $t_custom_field; 406 } 407 408 $t_plugin_columns = columns_get_plugin_columns(); 409 if( isset( $t_plugin_columns[$p_column] ) ) { 410 $t_column_object = $t_plugin_columns[$p_column]; 411 return $t_column_object->title; 412 } 413 414 switch( $p_column ) { 415 case 'attachment_count': 416 return lang_get( 'attachments' ); 417 case 'bugnotes_count': 418 return '#'; 419 case 'category_id': 420 return lang_get( 'category' ); 421 case 'edit': 422 return ''; 423 case 'handler_id': 424 return lang_get( 'assigned_to' ); 425 case 'last_updated': 426 return lang_get( 'updated' ); 427 case 'os_build': 428 return lang_get( 'os_build' ); 429 case 'project_id': 430 return lang_get( 'email_project' ); 431 case 'reporter_id': 432 return lang_get( 'reporter' ); 433 case 'selection': 434 return ''; 435 case 'sponsorship_total': 436 return sponsorship_get_currency(); 437 case 'version': 438 return lang_get( 'product_version' ); 439 case 'view_state': 440 return lang_get( 'view_status' ); 441 default: 442 return lang_get_defaulted( $p_column ); 443 } 444} 445 446/** 447 * Checks an array of columns for duplicate or invalid fields. 448 * 449 * @param string $p_field_name The logic name of the array being validated. Used when triggering errors. 450 * @param array $p_columns_to_validate The array of columns to validate. 451 * @param array $p_columns_all The list of all valid columns. 452 * @return boolean 453 * @access public 454 */ 455function columns_ensure_valid( $p_field_name, array $p_columns_to_validate, array $p_columns_all ) { 456 $t_columns_all_lower = array_map( 'mb_strtolower', $p_columns_all ); 457 458 # Check for invalid fields 459 foreach( $p_columns_to_validate as $t_column ) { 460 if( !in_array( mb_strtolower( $t_column ), $t_columns_all_lower ) ) { 461 error_parameters( $p_field_name, $t_column ); 462 trigger_error( ERROR_COLUMNS_INVALID, ERROR ); 463 return false; 464 } 465 } 466 467 # Check for duplicate fields 468 $t_columns_no_duplicates = array(); 469 foreach( $p_columns_to_validate as $t_column ) { 470 $t_column_lower = mb_strtolower( $t_column ); 471 if( in_array( $t_column, $t_columns_no_duplicates ) ) { 472 error_parameters( $p_field_name, $t_column ); 473 trigger_error( ERROR_COLUMNS_DUPLICATE, ERROR ); 474 } else { 475 $t_columns_no_duplicates[] = $t_column_lower; 476 } 477 } 478 479 return true; 480} 481 482/** 483 * Validates an array of column names and removes ones that are not valid. The validation 484 * is not case sensitive. 485 * 486 * @param array $p_columns The array of column names to be validated. 487 * @param array $p_columns_all The array of all valid column names. 488 * @return array The array of valid column names found in $p_columns. 489 * @access public 490 */ 491function columns_remove_invalid( array $p_columns, array $p_columns_all ) { 492 $t_columns_all_lower = array_values( array_map( 'mb_strtolower', $p_columns_all ) ); 493 $t_columns = array(); 494 495 foreach( $p_columns as $t_column ) { 496 if( in_array( mb_strtolower( $t_column ), $t_columns_all_lower ) ) { 497 $t_columns[] = $t_column; 498 } 499 } 500 501 return $t_columns; 502} 503 504/** 505 * Print table header for selection column 506 * 507 * @param string $p_sort Sort. 508 * @param string $p_dir Direction. 509 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 510 * @return void 511 * @access public 512 */ 513function print_column_title_selection( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 514 echo '<th class="column-selection">   </th>'; 515} 516 517/** 518 * Print table header for edit column 519 * @param string $p_sort Sort. 520 * @param string $p_dir Direction. 521 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 522 * @return void 523 * @access public 524 */ 525function print_column_title_edit( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 526 echo '<th class="column-edit">   </th>'; 527} 528 529/** 530 * Print table header for column ID 531 * 532 * @param string $p_sort Sort. 533 * @param string $p_dir Direction. 534 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 535 * @return void 536 * @access public 537 */ 538function print_column_title_id( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 539 echo '<th class="column-id">'; 540 print_view_bug_sort_link( lang_get( 'id' ), 'id', $p_sort, $p_dir, $p_columns_target ); 541 print_sort_icon( $p_dir, $p_sort, 'id' ); 542 echo '</th>'; 543} 544 545/** 546 * Print table header for column project id 547 * 548 * @param string $p_sort Sort. 549 * @param string $p_dir Direction. 550 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 551 * @return void 552 * @access public 553 */ 554function print_column_title_project_id( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 555 echo '<th class="column-project-id">'; 556 print_view_bug_sort_link( lang_get( 'email_project' ), 'project_id', $p_sort, $p_dir, $p_columns_target ); 557 print_sort_icon( $p_dir, $p_sort, 'project_id' ); 558 echo '</th>'; 559} 560 561/** 562 * Print table header for column reporter id 563 * 564 * @param string $p_sort Sort. 565 * @param string $p_dir Direction. 566 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 567 * @return void 568 * @access public 569 */ 570function print_column_title_reporter_id( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 571 echo '<th class="column-reporter">'; 572 print_view_bug_sort_link( lang_get( 'reporter' ), 'reporter_id', $p_sort, $p_dir, $p_columns_target ); 573 print_sort_icon( $p_dir, $p_sort, 'reporter_id' ); 574 echo '</th>'; 575} 576 577/** 578 * Print table header for column handler id 579 * 580 * @param string $p_sort Sort. 581 * @param string $p_dir Direction. 582 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 583 * @return void 584 * @access public 585 */ 586function print_column_title_handler_id( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 587 echo '<th class="column-assigned-to">'; 588 print_view_bug_sort_link( lang_get( 'assigned_to' ), 'handler_id', $p_sort, $p_dir, $p_columns_target ); 589 print_sort_icon( $p_dir, $p_sort, 'handler_id' ); 590 echo '</th>'; 591} 592 593/** 594 * Print table header for column priority 595 * 596 * @param string $p_sort Sort. 597 * @param string $p_dir Direction. 598 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 599 * @return void 600 * @access public 601 */ 602function print_column_title_priority( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 603 echo '<th class="column-priority">'; 604 # Use short label only when displaying icons 605 $t_label = lang_get( config_get( 'show_priority_text' ) ? 'priority' : 'priority_abbreviation' ); 606 print_view_bug_sort_link( $t_label, 'priority', $p_sort, $p_dir, $p_columns_target ); 607 print_sort_icon( $p_dir, $p_sort, 'priority' ); 608 echo '</th>'; 609} 610 611/** 612 * Print table header for column reproducibility 613 * 614 * @param string $p_sort Sort. 615 * @param string $p_dir Direction. 616 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 617 * @return void 618 * @access public 619 */ 620function print_column_title_reproducibility( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 621 echo '<th class="column-reproducibility">'; 622 print_view_bug_sort_link( lang_get( 'reproducibility' ), 'reproducibility', $p_sort, $p_dir, $p_columns_target ); 623 print_sort_icon( $p_dir, $p_sort, 'reproducibility' ); 624 echo '</th>'; 625} 626 627/** 628 * Print table header for column projection 629 * 630 * @param string $p_sort Sort. 631 * @param string $p_dir Direction. 632 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 633 * @return void 634 * @access public 635 */ 636function print_column_title_projection( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 637 echo '<th class="column-projection">'; 638 print_view_bug_sort_link( lang_get( 'projection' ), 'projection', $p_sort, $p_dir, $p_columns_target ); 639 print_sort_icon( $p_dir, $p_sort, 'projection' ); 640 echo '</th>'; 641} 642 643/** 644 * Print table header for column ETA 645 * 646 * @param string $p_sort Sort. 647 * @param string $p_dir Direction. 648 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 649 * @return void 650 * @access public 651 */ 652function print_column_title_eta( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 653 echo '<th class="column-eta">'; 654 print_view_bug_sort_link( lang_get( 'eta' ), 'eta', $p_sort, $p_dir, $p_columns_target ); 655 print_sort_icon( $p_dir, $p_sort, 'eta' ); 656 echo '</th>'; 657} 658 659/** 660 * Print table header for column resolution 661 * 662 * @param string $p_sort Sort. 663 * @param string $p_dir Direction. 664 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 665 * @return void 666 * @access public 667 */ 668function print_column_title_resolution( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 669 echo '<th class="column-resolution">'; 670 print_view_bug_sort_link( lang_get( 'resolution' ), 'resolution', $p_sort, $p_dir, $p_columns_target ); 671 print_sort_icon( $p_dir, $p_sort, 'resolution' ); 672 echo '</th>'; 673} 674 675/** 676 * Print table header for column fixed in version 677 * 678 * @param string $p_sort Sort. 679 * @param string $p_dir Direction. 680 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 681 * @return void 682 * @access public 683 */ 684function print_column_title_fixed_in_version( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 685 echo '<th class="column-fixed-in-version">'; 686 print_view_bug_sort_link( lang_get( 'fixed_in_version' ), 'fixed_in_version', $p_sort, $p_dir, $p_columns_target ); 687 print_sort_icon( $p_dir, $p_sort, 'fixed_in_version' ); 688 echo '</th>'; 689} 690 691/** 692 * Print table header for column tags 693 * 694 * @param string $p_sort Sort. 695 * @param string $p_dir Direction. 696 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 697 * @return void 698 * @access public 699 */ 700function print_column_title_tags( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 701 echo '<th class="column-tags">' . lang_get('tags') . '</th>'; 702} 703 704/** 705 * Print table header for column target version 706 * 707 * @param string $p_sort Sort. 708 * @param string $p_dir Direction. 709 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 710 * @return void 711 * @access public 712 */ 713function print_column_title_target_version( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 714 echo '<th class="column-target-version">'; 715 print_view_bug_sort_link( lang_get( 'target_version' ), 'target_version', $p_sort, $p_dir, $p_columns_target ); 716 print_sort_icon( $p_dir, $p_sort, 'target_version' ); 717 echo '</th>'; 718} 719 720/** 721 * Print table header for column view state 722 * 723 * @param string $p_sort Sort. 724 * @param string $p_dir Direction. 725 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 726 * @return void 727 * @access public 728 */ 729function print_column_title_view_state( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 730 echo '<th class="column-view-state">'; 731 $t_view_state_text = lang_get( 'view_status' ); 732 $t_view_state_icon = ' ' . icon_get( 'fa-lock', '', $t_view_state_text ); 733 print_view_bug_sort_link( $t_view_state_icon, 'view_state', $p_sort, $p_dir, $p_columns_target ); 734 print_sort_icon( $p_dir, $p_sort, 'view_state' ); 735 echo '</th>'; 736} 737 738/** 739 * Print table header for column OS 740 * 741 * @param string $p_sort Sort. 742 * @param string $p_dir Direction. 743 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 744 * @return void 745 * @access public 746 */ 747function print_column_title_os( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 748 echo '<th class="column-os">'; 749 print_view_bug_sort_link( lang_get( 'os' ), 'os', $p_sort, $p_dir, $p_columns_target ); 750 print_sort_icon( $p_dir, $p_sort, 'os' ); 751 echo '</th>'; 752} 753 754/** 755 * Print table header for column OS Build 756 * 757 * @param string $p_sort Sort. 758 * @param string $p_dir Direction. 759 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 760 * @return void 761 * @access public 762 */ 763function print_column_title_os_build( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 764 echo '<th class="column-os-build">'; 765 print_view_bug_sort_link( lang_get( 'os_build' ), 'os_build', $p_sort, $p_dir, $p_columns_target ); 766 print_sort_icon( $p_dir, $p_sort, 'os_build' ); 767 echo '</th>'; 768} 769 770/** 771 * Print table header for column Build 772 * 773 * @param string $p_sort Sort. 774 * @param string $p_dir Direction. 775 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 776 * @return void 777 * @access public 778 */ 779function print_column_title_build( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 780 if( $p_columns_target != COLUMNS_TARGET_CSV_PAGE ) { 781 echo '<th class="column-build">'; 782 print_view_bug_sort_link( lang_get( 'build' ), 'build', $p_sort, $p_dir, $p_columns_target ); 783 print_sort_icon( $p_dir, $p_sort, 'build' ); 784 echo '</th>'; 785 } else { 786 echo lang_get( 'build' ); 787 } 788} 789 790/** 791 * Print table header for column Platform 792 * 793 * @param string $p_sort Sort. 794 * @param string $p_dir Direction. 795 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 796 * @return void 797 * @access public 798 */ 799function print_column_title_platform( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 800 echo '<th class="column-platform">'; 801 print_view_bug_sort_link( lang_get( 'platform' ), 'platform', $p_sort, $p_dir, $p_columns_target ); 802 print_sort_icon( $p_dir, $p_sort, 'platform' ); 803 echo '</th>'; 804} 805 806/** 807 * Print table header for column version 808 * 809 * @param string $p_sort Sort. 810 * @param string $p_dir Direction. 811 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 812 * @return void 813 * @access public 814 */ 815function print_column_title_version( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 816 echo '<th class="column-version">'; 817 print_view_bug_sort_link( lang_get( 'product_version' ), 'version', $p_sort, $p_dir, $p_columns_target ); 818 print_sort_icon( $p_dir, $p_sort, 'version' ); 819 echo '</th>'; 820} 821 822/** 823 * Print table header for column date submitted 824 * 825 * @param string $p_sort Sort. 826 * @param string $p_dir Direction. 827 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 828 * @return void 829 * @access public 830 */ 831function print_column_title_date_submitted( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 832 echo '<th class="column-date-submitted">'; 833 print_view_bug_sort_link( lang_get( 'date_submitted' ), 'date_submitted', $p_sort, $p_dir, $p_columns_target ); 834 print_sort_icon( $p_dir, $p_sort, 'date_submitted' ); 835 echo '</th>'; 836} 837 838/** 839 * Print table header for column attachment count 840 * 841 * @param string $p_sort Sort. 842 * @param string $p_dir Direction. 843 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 844 * @return void 845 * @access public 846 */ 847function print_column_title_attachment_count( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 848 $t_attachment_count_text = lang_get( 'attachment_count' ); 849 $t_attachment_count_icon = icon_get( 'fa-paperclip', 'blue', $t_attachment_count_text ); 850 echo "\t" . '<th class="column-attachments">' . $t_attachment_count_icon . '</th>' . "\n"; 851} 852 853/** 854 * Print table header for column category 855 * 856 * @param string $p_sort Sort. 857 * @param string $p_dir Direction. 858 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 859 * @return void 860 * @access public 861 */ 862function print_column_title_category_id( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 863 echo '<th class="column-category">'; 864 print_view_bug_sort_link( lang_get( 'category' ), 'category_id', $p_sort, $p_dir, $p_columns_target ); 865 print_sort_icon( $p_dir, $p_sort, 'category_id' ); 866 echo '</th>'; 867} 868 869/** 870 * Prints Category column header 871 * The actual column is 'category_id', this function is just here for backwards 872 * compatibility 873 * @param string $p_sort Sort. 874 * @param string $p_dir Direction. 875 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 876 * @return void 877 * @access public 878 */ 879function print_column_title_category( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 880 trigger_error( ERROR_GENERIC, WARNING ); 881 print_column_title_category_id( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ); 882} 883 884/** 885 * Print table header for column sponsorship total 886 * 887 * @param string $p_sort Sort. 888 * @param string $p_dir Direction. 889 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 890 * @return void 891 * @access public 892 */ 893function print_column_title_sponsorship_total( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 894 echo "\t<th class=\"column-sponsorship\">"; 895 print_view_bug_sort_link( sponsorship_get_currency(), 'sponsorship_total', $p_sort, $p_dir, $p_columns_target ); 896 print_sort_icon( $p_dir, $p_sort, 'sponsorship_total' ); 897 echo "</th>\n"; 898} 899 900/** 901 * Print table header for column severity 902 * 903 * @param string $p_sort Sort. 904 * @param string $p_dir Direction. 905 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 906 * @return void 907 * @access public 908 */ 909function print_column_title_severity( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 910 echo '<th class="column-severity">'; 911 print_view_bug_sort_link( lang_get( 'severity' ), 'severity', $p_sort, $p_dir, $p_columns_target ); 912 print_sort_icon( $p_dir, $p_sort, 'severity' ); 913 echo '</th>'; 914} 915 916/** 917 * Print table header for column status 918 * 919 * @param string $p_sort Sort. 920 * @param string $p_dir Direction. 921 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 922 * @return void 923 * @access public 924 */ 925function print_column_title_status( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 926 echo '<th class="column-status">'; 927 print_view_bug_sort_link( lang_get( 'status' ), 'status', $p_sort, $p_dir, $p_columns_target ); 928 print_sort_icon( $p_dir, $p_sort, 'status' ); 929 echo '</th>'; 930} 931 932/** 933 * Print table header for column last updated 934 * 935 * @param string $p_sort Sort. 936 * @param string $p_dir Direction. 937 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 938 * @return void 939 * @access public 940 */ 941function print_column_title_last_updated( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 942 echo '<th class="column-last-modified">'; 943 print_view_bug_sort_link( lang_get( 'updated' ), 'last_updated', $p_sort, $p_dir, $p_columns_target ); 944 print_sort_icon( $p_dir, $p_sort, 'last_updated' ); 945 echo '</th>'; 946} 947 948/** 949 * Print table header for column summary 950 * 951 * @param string $p_sort Sort. 952 * @param string $p_dir Direction. 953 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 954 * @return void 955 * @access public 956 */ 957function print_column_title_summary( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 958 echo '<th class="column-summary">'; 959 print_view_bug_sort_link( lang_get( 'summary' ), 'summary', $p_sort, $p_dir, $p_columns_target ); 960 print_sort_icon( $p_dir, $p_sort, 'summary' ); 961 echo '</th>'; 962} 963 964/** 965 * Print table header for column bugnotes count 966 * 967 * @param string $p_sort Sort. 968 * @param string $p_dir Direction. 969 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 970 * @return void 971 * @access public 972 */ 973function print_column_title_bugnotes_count( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 974 echo '<th class="column-bugnotes-count">'; 975 print_icon( 'fa-comments', 'blue' ); 976 echo '</th>'; 977} 978 979/** 980 * Print table header for column description 981 * 982 * @param string $p_sort Sort. 983 * @param string $p_dir Direction. 984 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 985 * @return void 986 * @access public 987 */ 988function print_column_title_description( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 989 echo '<th class="column-description">'; 990 echo lang_get( 'description' ); 991 echo '</th>'; 992} 993 994/** 995 * Print table header for notes column. 996 * 997 * @param string $p_sort Sort. 998 * @param string $p_dir Direction. 999 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1000 * @return void 1001 * @access public 1002 */ 1003function print_column_title_notes( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1004 echo '<th class="column-notes">'; 1005 echo lang_get( 'bug_notes_title' ); 1006 echo '</th>'; 1007} 1008 1009/** 1010 * Print table header for column steps to reproduce 1011 * 1012 * @param string $p_sort Sort. 1013 * @param string $p_dir Direction. 1014 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1015 * @return void 1016 * @access public 1017 */ 1018function print_column_title_steps_to_reproduce( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1019 echo '<th class="column-steps-to-reproduce">'; 1020 echo lang_get( 'steps_to_reproduce' ); 1021 echo '</th>'; 1022} 1023 1024/** 1025 * Print table header for column additional information 1026 * 1027 * @param string $p_sort Sort. 1028 * @param string $p_dir Direction. 1029 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1030 * @return void 1031 * @access public 1032 */ 1033function print_column_title_additional_information( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1034 echo '<th class="column-additional-information">'; 1035 echo lang_get( 'additional_information' ); 1036 echo '</th>'; 1037} 1038 1039/** 1040 * Prints Due Date column header 1041 * @param string $p_sort Sort. 1042 * @param string $p_dir Direction. 1043 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1044 * @return void 1045 * @access public 1046 */ 1047function print_column_title_due_date( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1048 echo '<th class="column-due-date">'; 1049 print_view_bug_sort_link( lang_get( 'due_date' ), 'due_date', $p_sort, $p_dir, $p_columns_target ); 1050 print_sort_icon( $p_dir, $p_sort, 'due_date' ); 1051 echo '</th>'; 1052} 1053 1054/** 1055 * Print table header for column overdue 1056 * 1057 * @param string $p_sort Sort. 1058 * @param string $p_dir Direction. 1059 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1060 * @return void 1061 * @access public 1062 */ 1063function print_column_title_overdue( $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1064 echo '<th class="column-overdue">'; 1065 $t_overdue_text = lang_get( 'overdue' ); 1066 $t_overdue_icon = ' ' . icon_get( 'fa-times-circle-o', '', $t_overdue_text ); 1067 print_view_bug_sort_link( $t_overdue_icon, 'due_date', $p_sort, $p_dir, $p_columns_target ); 1068 print_sort_icon( $p_dir, $p_sort, 'due_date' ); 1069 echo '</th>'; 1070} 1071 1072/** 1073 * Print table data for column selection 1074 * 1075 * @param BugData $p_bug BugData object. 1076 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1077 * @return void 1078 * @access public 1079 */ 1080function print_column_selection( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1081 global $g_checkboxes_exist; 1082 1083 echo '<td class="column-selection">'; 1084 if( COLUMNS_TARGET_PRINT_PAGE == $p_columns_target || 1085 # check report_bug_threshold for the actions "copy" or "move" into any other project 1086 access_has_any_project_level( 'report_bug_threshold' ) || 1087 # !TODO: check if any other projects actually exist for the bug to be moved to 1088 access_has_project_level( config_get( 'move_bug_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1089 # !TODO: factor in $g_auto_set_status_to_assigned == ON 1090 access_has_project_level( config_get( 'update_bug_assign_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1091 access_has_project_level( config_get( 'update_bug_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1092 access_has_project_level( config_get( 'delete_bug_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1093 # !TODO: check to see if the bug actually has any different selectable workflow states 1094 access_has_project_level( config_get( 'update_bug_status_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1095 access_has_project_level( config_get( 'set_bug_sticky_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1096 access_has_project_level( config_get( 'change_view_status_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1097 access_has_project_level( config_get( 'add_bugnote_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1098 access_has_project_level( config_get( 'tag_attach_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) || 1099 access_has_project_level( config_get( 'roadmap_update_threshold', null, null, $p_bug->project_id ), $p_bug->project_id ) ) { 1100 $g_checkboxes_exist = true; 1101 echo '<div class="checkbox no-padding no-margin"><label>'; 1102 printf( '<input type="checkbox" name="bug_arr[]" value="%d" class="ace" />', $p_bug->id ); 1103 echo '<span class="lbl"></span>'; 1104 echo '</label></div>'; 1105 } else { 1106 echo ' '; 1107 } 1108 echo '</td>'; 1109} 1110 1111/** 1112 * Print column title for a specific custom column. 1113 * 1114 * @param string $p_column Active column. 1115 * @param object $p_column_object Column object. 1116 * @param string $p_sort Sort. 1117 * @param string $p_dir Direction. 1118 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1119 * @return void 1120 * @access public 1121 */ 1122function print_column_title_plugin( $p_column, $p_column_object, $p_sort, $p_dir, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1123 echo '<th class="column-plugin">'; 1124 if( $p_column_object->sortable ) { 1125 print_view_bug_sort_link( string_display_line( $p_column_object->title ), $p_column, $p_sort, $p_dir, $p_columns_target ); 1126 print_sort_icon( $p_dir, $p_sort, $p_column ); 1127 } else { 1128 echo string_display_line( $p_column_object->title ); 1129 } 1130 echo '</th>'; 1131} 1132 1133/** 1134 * Print custom column content for a specific bug. 1135 * @param object $p_column_object Column object. 1136 * @param BugData $p_bug BugData object. 1137 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1138 * @return void 1139 * @access public 1140 */ 1141function print_column_plugin( $p_column_object, BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1142 if( $p_columns_target != COLUMNS_TARGET_CSV_PAGE ) { 1143 echo '<td class="column-plugin">'; 1144 $p_column_object->display( $p_bug, $p_columns_target ); 1145 echo '</td>'; 1146 } else { 1147 $p_column_object->display( $p_bug, $p_columns_target ); 1148 } 1149} 1150 1151/** 1152 * Print column content for column edit 1153 * 1154 * @param BugData $p_bug BugData object. 1155 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1156 * @return void 1157 * @access public 1158 */ 1159function print_column_edit( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1160 1161 echo '<td class="column-edit">'; 1162 1163 if( !bug_is_readonly( $p_bug->id ) && access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug->id ) ) { 1164 echo '<a href="' . string_get_bug_update_url( $p_bug->id ) . '">'; 1165 print_icon( 'fa-pencil', 'bigger-130 padding-2 grey', lang_get( 'edit' ) ); 1166 echo '</a>'; 1167 } else { 1168 echo ' '; 1169 } 1170 1171 echo '</td>'; 1172} 1173 1174/** 1175 * Print column content for column priority 1176 * 1177 * @param BugData $p_bug BugData object. 1178 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1179 * @return void 1180 * @access public 1181 */ 1182function print_column_priority( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1183 echo '<td class="column-priority">'; 1184 if( ON == config_get( 'show_priority_text' ) ) { 1185 print_formatted_priority_string( $p_bug ); 1186 } else { 1187 print_status_icon( $p_bug->priority ); 1188 } 1189 echo '</td>'; 1190} 1191 1192/** 1193 * Print column content for column id 1194 * 1195 * @param BugData $p_bug BugData object. 1196 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1197 * @return void 1198 * @access public 1199 */ 1200function print_column_id( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1201 echo '<td class="column-id">'; 1202 print_bug_link( $p_bug->id, false ); 1203 echo '</td>'; 1204} 1205 1206/** 1207 * Print column content for column sponsorship total 1208 * 1209 * @param BugData $p_bug BugData object. 1210 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1211 * @return void 1212 * @access public 1213 */ 1214function print_column_sponsorship_total( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1215 echo "\t<td class=\"right column-sponsorship\">"; 1216 1217 if( $p_bug->sponsorship_total > 0 ) { 1218 $t_sponsorship_amount = sponsorship_format_amount( $p_bug->sponsorship_total ); 1219 echo string_no_break( $t_sponsorship_amount ); 1220 } 1221 1222 echo "</td>\n"; 1223} 1224 1225/** 1226 * Print column content for column bugnotes count 1227 * 1228 * @param BugData $p_bug BugData object. 1229 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1230 * @return void 1231 * @access public 1232 */ 1233function print_column_bugnotes_count( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1234 global $g_filter; 1235 1236 # grab the bugnote count 1237 $t_bugnote_stats = bug_get_bugnote_stats( $p_bug->id ); 1238 if( is_array( $t_bugnote_stats ) ) { 1239 $t_bugnote_count = $t_bugnote_stats['count']; 1240 $t_bugnote_updated = $t_bugnote_stats['last_modified']; 1241 } else { 1242 $t_bugnote_count = 0; 1243 } 1244 1245 echo '<td class="column-bugnotes-count">'; 1246 if( $t_bugnote_count > 0 ) { 1247 $t_show_in_bold = $t_bugnote_updated > strtotime( '-' . $g_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] . ' hours' ); 1248 if( $t_show_in_bold ) { 1249 echo '<span class="bold">'; 1250 } 1251 print_link( string_get_bug_view_url( $p_bug->id ) . '&nbn=' . $t_bugnote_count . '#bugnotes', $t_bugnote_count ); 1252 if( $t_show_in_bold ) { 1253 echo '</span>'; 1254 } 1255 } else { 1256 echo ' '; 1257 } 1258 1259 echo '</td>'; 1260} 1261 1262/** 1263 * Print column content for column attachment count 1264 * 1265 * @param BugData $p_bug BugData object. 1266 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1267 * @return void 1268 * @access public 1269 */ 1270function print_column_attachment_count( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1271 1272 # Check for attachments 1273 $t_attachment_count = 0; 1274 if( file_can_view_bug_attachments( $p_bug->id, null ) ) { 1275 $t_attachment_count = file_bug_attachment_count( $p_bug->id ); 1276 } 1277 1278 echo '<td class="column-attachments">'; 1279 1280 if( $t_attachment_count > 0 ) { 1281 $t_href = string_get_bug_view_url( $p_bug->id ) . '#attachments'; 1282 $t_href_title = sprintf( lang_get( 'view_attachments_for_issue' ), $t_attachment_count, $p_bug->id ); 1283 echo '<a href="' . $t_href . '" title="' . $t_href_title . '">' . $t_attachment_count . '</a>'; 1284 } else { 1285 echo '   '; 1286 } 1287 1288 echo "</td>\n"; 1289} 1290 1291/** 1292 * Print column content for column category id 1293 * 1294 * @param BugData $p_bug BugData object. 1295 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1296 * @return void 1297 * @access public 1298 */ 1299function print_column_category_id( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1300 global $t_sort, $t_dir; 1301 1302 # grab the project name 1303 $t_project_name = project_get_field( $p_bug->project_id, 'name' ); 1304 1305 echo '<td class="column-category">'; 1306 echo '<div class="align-left">'; 1307 1308 # type project name if viewing 'all projects' or if issue is in a subproject 1309 if( ON == config_get( 'show_bug_project_links' ) && helper_get_current_project() != $p_bug->project_id ) { 1310 echo '<span class="small project">['; 1311 print_view_bug_sort_link( string_display_line( $t_project_name ), 'project_id', $t_sort, $t_dir, $p_columns_target ); 1312 echo ']</span>  '; 1313 } 1314 1315 echo string_display_line( category_full_name( $p_bug->category_id, false ) ); 1316 echo '</div>'; 1317 echo '</td>'; 1318} 1319 1320/** 1321 * Print column content for column severity 1322 * 1323 * @param BugData $p_bug BugData object. 1324 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1325 * @return void 1326 * @access public 1327 */ 1328function print_column_severity( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1329 echo '<td class="column-severity">'; 1330 print_formatted_severity_string( $p_bug ); 1331 echo '</td>'; 1332} 1333 1334/** 1335 * Print column content for column eta 1336 * 1337 * @param BugData $p_bug BugData object. 1338 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1339 * @return void 1340 * @access public 1341 */ 1342function print_column_eta( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1343 echo '<td class="column-eta">', get_enum_element( 'eta', $p_bug->eta, auth_get_current_user_id(), $p_bug->project_id ), '</td>'; 1344} 1345 1346/** 1347 * Print column content for column projection 1348 * 1349 * @param BugData $p_bug BugData object. 1350 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1351 * @return void 1352 * @access public 1353 */ 1354function print_column_projection( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1355 echo '<td class="column-projection">', get_enum_element( 'projection', $p_bug->projection, auth_get_current_user_id(), $p_bug->project_id ), '</td>'; 1356} 1357 1358/** 1359 * Print column content for column reproducibility 1360 * 1361 * @param BugData $p_bug BugData object. 1362 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1363 * @return void 1364 * @access public 1365 */ 1366function print_column_reproducibility( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1367 echo '<td class="column-reproducibility">', get_enum_element( 'reproducibility', $p_bug->reproducibility, auth_get_current_user_id(), $p_bug->project_id ), '</td>'; 1368} 1369 1370/** 1371 * Print column content for column resolution 1372 * 1373 * @param BugData $p_bug BugData object. 1374 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1375 * @return void 1376 * @access public 1377 */ 1378function print_column_resolution( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1379 echo '<td class="column-resolution">', 1380 get_enum_element( 'resolution', $p_bug->resolution, auth_get_current_user_id(), $p_bug->project_id ), 1381 '</td>'; 1382} 1383 1384/** 1385 * Print column content for column status 1386 * 1387 * @param BugData $p_bug BugData object. 1388 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1389 * @return void 1390 * @access public 1391 */ 1392function print_column_status( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1393 $t_current_user = auth_get_current_user_id(); 1394 # choose color based on status 1395 $t_status_css = html_get_status_css_fg( $p_bug->status, $t_current_user, $p_bug->project_id ); 1396 echo '<td class="column-status">'; 1397 echo '<div class="align-left">'; 1398 print_icon( 'fa-square', 'fa-status-box ' . $t_status_css ); 1399 printf( ' <span title="%s">%s</span>', 1400 get_enum_element( 'resolution', $p_bug->resolution, $t_current_user, $p_bug->project_id ), 1401 get_enum_element( 'status', $p_bug->status, $t_current_user, $p_bug->project_id ) 1402 ); 1403 1404 # print handler user next to status 1405 if( $p_bug->handler_id > 0 1406 && ON == config_get( 'show_assigned_names', null, $t_current_user, $p_bug->project_id ) 1407 && access_can_see_handler_for_bug( $p_bug ) ) { 1408 printf( ' (%s)', prepare_user_name( $p_bug->handler_id ) ); 1409 } 1410 echo '</div></td>'; 1411} 1412 1413/** 1414 * Print column content for column handler id 1415 * 1416 * @param BugData $p_bug BugData object. 1417 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1418 * @return void 1419 * @access public 1420 */ 1421function print_column_handler_id( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1422 echo '<td class="column-assigned-to">'; 1423 1424 # In case of a specific project, if the current user has no access to the field, then it would have been excluded from the 1425 # list of columns to view. In case of ALL_PROJECTS, then we need to check the access per row. 1426 if( $p_bug->handler_id > 0 && ( helper_get_current_project() != ALL_PROJECTS || access_has_project_level( config_get( 'view_handler_threshold' ), $p_bug->project_id ) ) ) { 1427 echo prepare_user_name( $p_bug->handler_id ); 1428 } 1429 1430 echo '</td>'; 1431} 1432 1433/** 1434 * Print column content for column reporter id 1435 * 1436 * @param BugData $p_bug BugData object. 1437 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1438 * @return void 1439 * @access public 1440 */ 1441function print_column_reporter_id( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1442 echo '<td class="column-reporter">'; 1443 echo prepare_user_name( $p_bug->reporter_id ); 1444 echo '</td>'; 1445} 1446 1447/** 1448 * Print column content for column project id 1449 * 1450 * @param BugData $p_bug BugData object. 1451 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1452 * @return void 1453 * @access public 1454 */ 1455function print_column_project_id( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1456 echo '<td class="column-project-id">'; 1457 echo string_display_line( project_get_name( $p_bug->project_id ) ); 1458 echo '</td>'; 1459} 1460 1461/** 1462 * Print column content for column last updated 1463 * 1464 * @param BugData $p_bug BugData object. 1465 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1466 * @return void 1467 * @access public 1468 */ 1469function print_column_last_updated( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1470 global $g_filter; 1471 1472 $t_last_updated = string_display_line( date( config_get( 'short_date_format' ), $p_bug->last_updated ) ); 1473 1474 echo '<td class="column-last-modified">'; 1475 if( $p_bug->last_updated > strtotime( '-' . $g_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] . ' hours' ) ) { 1476 printf( '<span class="bold">%s</span>', $t_last_updated ); 1477 } else { 1478 echo $t_last_updated; 1479 } 1480 echo '</td>'; 1481} 1482 1483/** 1484 * Print column content for column date submitted 1485 * 1486 * @param BugData $p_bug BugData object. 1487 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1488 * @return void 1489 * @access public 1490 */ 1491function print_column_date_submitted( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1492 $t_date_submitted = string_display_line( date( config_get( 'short_date_format' ), $p_bug->date_submitted ) ); 1493 1494 echo '<td class="column-date-submitted">', $t_date_submitted, '</td>'; 1495} 1496 1497/** 1498 * Print column content for column summary 1499 * 1500 * @param BugData $p_bug BugData object. 1501 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1502 * @return void 1503 * @access public 1504 */ 1505function print_column_summary( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1506 if( $p_columns_target == COLUMNS_TARGET_CSV_PAGE ) { 1507 $t_summary = string_attribute( $p_bug->summary ); 1508 } else { 1509 $t_summary = string_display_line_links( $p_bug->summary ); 1510 } 1511 1512 $t_bug_url = string_get_bug_view_url( $p_bug->id ); 1513 echo '<td class="column-summary"><a href="' . $t_bug_url . '">' . $t_summary . '</a></td>'; 1514} 1515 1516/** 1517 * Print column content for column description 1518 * 1519 * @param BugData $p_bug BugData object. 1520 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1521 * @return void 1522 * @access public 1523 */ 1524function print_column_description( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1525 $t_description = string_display_links( $p_bug->description ); 1526 1527 echo '<td class="column-description">', $t_description, '</td>'; 1528} 1529 1530/** 1531 * Print column content for notes column 1532 * 1533 * @param BugData $p_bug BugData object. 1534 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1535 * @return void 1536 * @access public 1537 */ 1538function print_column_notes( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1539 $t_notes = bugnote_get_all_visible_as_string( $p_bug->id, /* user_bugnote_order */ 'DESC', /* user_bugnote_limit */ 0 ); 1540 1541 echo '<td class="column-notes">', string_display_links( $t_notes ), '</td>'; 1542} 1543 1544/** 1545 * Print column content for column steps to reproduce 1546 * 1547 * @param BugData $p_bug BugData object. 1548 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1549 * @return void 1550 * @access public 1551 */ 1552function print_column_steps_to_reproduce( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1553 $t_steps_to_reproduce = string_display_links( $p_bug->steps_to_reproduce ); 1554 1555 echo '<td class="column-steps-to-reproduce">', $t_steps_to_reproduce, '</td>'; 1556} 1557 1558/** 1559 * Print column content for column additional information 1560 * 1561 * @param BugData $p_bug BugData object. 1562 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1563 * @return void 1564 * @access public 1565 */ 1566function print_column_additional_information( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1567 $t_additional_information = string_display_links( $p_bug->additional_information ); 1568 1569 echo '<td class="column-additional-information">', $t_additional_information, '</td>'; 1570} 1571 1572/** 1573 * Print column content for column target version 1574 * 1575 * @param BugData $p_bug BugData object. 1576 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1577 * @return void 1578 * @access public 1579 */ 1580function print_column_target_version( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1581 echo '<td class="column-target-version">'; 1582 1583 # In case of a specific project, if the current user has no access to the field, then it would have been excluded from the 1584 # list of columns to view. In case of ALL_PROJECTS, then we need to check the access per row. 1585 if( helper_get_current_project() != ALL_PROJECTS || access_has_project_level( config_get( 'roadmap_view_threshold' ), $p_bug->project_id ) ) { 1586 echo string_display_line( $p_bug->target_version ); 1587 } 1588 1589 echo '</td>'; 1590} 1591 1592/** 1593 * Print column content for view state column 1594 * 1595 * @param BugData $p_bug BugData object. 1596 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1597 * @return void 1598 * @access public 1599 */ 1600function print_column_view_state( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1601 1602 echo '<td class="column-view-state">'; 1603 1604 if( VS_PRIVATE == $p_bug->view_state ) { 1605 $t_view_state_text = lang_get( 'private' ); 1606 print_icon( 'fa-lock', '', $t_view_state_text ); 1607 } else { 1608 echo ' '; 1609 } 1610 1611 echo '</td>'; 1612} 1613 1614/** 1615 * Print column content for column tags 1616 * 1617 * @param BugData $p_bug BugData object. 1618 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1619 * @return void 1620 * @access public 1621 */ 1622function print_column_tags( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1623 echo '<td class="column-tags">'; 1624 1625 if( access_has_bug_level( config_get( 'tag_view_threshold' ), $p_bug->id ) ) { 1626 echo string_display_line( tag_bug_get_all( $p_bug->id ) ); 1627 } 1628 1629 echo '</td>'; 1630} 1631 1632/** 1633 * Print column content for column due date 1634 * 1635 * @param BugData $p_bug BugData object. 1636 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1637 * @return void 1638 * @access public 1639 */ 1640function print_column_due_date( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1641 if( !access_has_bug_level( config_get( 'due_date_view_threshold' ), $p_bug->id ) || 1642 date_is_null( $p_bug->due_date ) 1643 ) { 1644 $t_css = ''; 1645 $t_value = ' '; 1646 } else { 1647 $t_css = " due-" . bug_overdue_level( $p_bug->id ); 1648 $t_value = string_display_line( date( config_get( 'short_date_format' ), $p_bug->due_date ) ); 1649 } 1650 1651 printf( '<td class="column-due-date%s">%s</td>', $t_css, $t_value ); 1652} 1653 1654/** 1655 * Print column content for column overdue 1656 * 1657 * @param BugData $p_bug BugData object. 1658 * @param integer $p_columns_target See COLUMNS_TARGET_* in constant_inc.php. 1659 * @return void 1660 * @access public 1661 */ 1662function print_column_overdue( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) { 1663 1664 echo '<td class="column-overdue">'; 1665 1666 if( access_has_bug_level( config_get( 'due_date_view_threshold' ), $p_bug->id ) && 1667 !date_is_null( $p_bug->due_date ) 1668 ) { 1669 $t_level = bug_overdue_level( $p_bug->id ); 1670 if( $t_level === 0 ) { 1671 $t_icon = 'fa-times-circle-o'; 1672 $t_overdue_text_hover = sprintf( 1673 lang_get( 'overdue_since' ), 1674 date( config_get( 'short_date_format' ), $p_bug->due_date ) 1675 ); 1676 } else { 1677 $t_icon = $t_level === false ? 'fa-info-circle' : 'fa-warning'; 1678 1679 $t_duration = $p_bug->due_date - db_now(); 1680 if( $t_duration <= SECONDS_PER_DAY ) { 1681 $t_overdue_text_hover = lang_get( 'overdue_one_day' ); 1682 } else { 1683 $t_overdue_text_hover = sprintf( 1684 lang_get( 'overdue_days' ), 1685 ceil( $t_duration / SECONDS_PER_DAY ) 1686 ); 1687 } 1688 } 1689 print_icon( $t_icon, '', string_display_line( $t_overdue_text_hover ) ); 1690 } else { 1691 echo ' '; 1692 } 1693 1694 echo '</td>'; 1695} 1696