2 # MantisBT - A PHP based bugtracking system
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.
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.
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/>.
21 * @subpackage CustomFunctionAPI
22 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
23 * @copyright Copyright (C) 2002 - 2010 MantisBT Team - mantisbt-dev@lists.sourceforge.net
24 * @link http://www.mantisbt.org
27 * @uses bugnote_api.php
28 * @uses category_api.php
29 * @uses columns_api.php
30 * @uses config_api.php
31 * @uses constant_inc.php
32 * @uses custom_field_api.php
33 * @uses helper_api.php
34 * @uses history_api.php
38 * @uses prepare_api.php
40 * @uses string_api.php
41 * @uses utility_api.php
42 * @uses version_api.php
45 require_api( 'bug_api.php' );
46 require_api( 'bugnote_api.php' );
47 require_api( 'category_api.php' );
48 require_api( 'columns_api.php' );
49 require_api( 'config_api.php' );
50 require_api( 'constant_inc.php' );
51 require_api( 'custom_field_api.php' );
52 require_api( 'helper_api.php' );
53 require_api( 'history_api.php' );
54 require_api( 'html_api.php' );
55 require_api( 'icon_api.php' );
56 require_api( 'lang_api.php' );
57 require_api( 'prepare_api.php' );
58 require_api( 'print_api.php' );
59 require_api( 'string_api.php' );
60 require_api( 'utility_api.php' );
61 require_api( 'version_api.php' );
63 # ## Custom Function API ###
64 # Checks the provided bug and determines whether it should be included in the changelog
66 # returns true: to include, false: to exclude.
67 function custom_function_default_changelog_include_issue( $p_issue_id ) {
68 $t_issue = bug_get( $p_issue_id );
70 return( ( $t_issue->resolution
>= config_get( 'bug_resolution_fixed_threshold' ) &&
71 $t_issue->resolution
< config_get( 'bug_resolution_not_fixed_threshold' ) &&
72 $t_issue->status
>= config_get( 'bug_resolved_status_threshold' ) ) );
75 # Prints one entry in the changelog.
76 function custom_function_default_changelog_print_issue( $p_issue_id, $p_issue_level = 0 ) {
79 $t_bug = bug_get( $p_issue_id );
81 if( $t_bug->category_id
) {
82 $t_category_name = category_get_name( $t_bug->category_id
);
84 $t_category_name = '';
87 $t_category = is_blank( $t_category_name ) ?
'' : '<b>[' . string_display_line( $t_category_name ) . ']</b> ';
88 echo utf8_str_pad( '', $p_issue_level * 6, ' ' ), '- ', string_get_bug_view_link( $p_issue_id ), ': ', $t_category, string_display_line_links( $t_bug->summary
);
90 if( $t_bug->handler_id
!= 0 ) {
91 echo ' (', prepare_user_name( $t_bug->handler_id
), ')';
94 if( !isset( $t_status[$t_bug->status
] ) ) {
95 $t_status[$t_bug->status
] = get_enum_element( 'status', $t_bug->status
);
97 echo ' - ', $t_status[$t_bug->status
], '.<br />';
100 # Checks the provided bug and determines whether it should be included in the roadmap or not.
101 # returns true: to include, false: to exclude.
102 function custom_function_default_roadmap_include_issue( $p_issue_id ) {
106 # Prints one entry in the roadmap.
107 function custom_function_default_roadmap_print_issue( $p_issue_id, $p_issue_level = 0 ) {
110 $t_bug = bug_get( $p_issue_id );
112 if( bug_is_resolved( $p_issue_id ) ) {
113 $t_strike_start = '<strike>';
114 $t_strike_end = '</strike>';
116 $t_strike_start = $t_strike_end = '';
119 if( $t_bug->category_id
) {
120 $t_category_name = category_get_name( $t_bug->category_id
);
122 $t_category_name = '';
125 $t_category = is_blank( $t_category_name ) ?
'' : '<b>[' . string_display_line( $t_category_name ) . ']</b> ';
127 echo utf8_str_pad( '', $p_issue_level * 6, ' ' ), '- ', $t_strike_start, string_get_bug_view_link( $p_issue_id ), ': ', $t_category, string_display_line_links( $t_bug->summary
);
129 if( $t_bug->handler_id
!= 0 ) {
130 echo ' (', prepare_user_name( $t_bug->handler_id
), ')';
133 if( !isset( $t_status[$t_bug->status
] ) ) {
134 $t_status[$t_bug->status
] = get_enum_element( 'status', $t_bug->status
);
136 echo ' - ', $t_status[$t_bug->status
], $t_strike_end, '.<br />';
139 # format the bug summary.
140 function custom_function_default_format_issue_summary( $p_issue_id, $p_context = 0 ) {
141 switch( $p_context ) {
142 case SUMMARY_CAPTION
:
143 $t_string = bug_format_id( $p_issue_id ) . ': ' . string_attribute( bug_get_field( $p_issue_id, 'summary' ) );
146 $t_string = bug_format_id( $p_issue_id ) . ': ' . string_display_line_links( bug_get_field( $p_issue_id, 'summary' ) );
149 $t_string = bug_format_id( $p_issue_id ) . ': ' . string_attribute( bug_get_field( $p_issue_id, 'summary' ) );
152 $t_string = string_attribute( bug_get_field( $p_issue_id, 'summary' ) );
158 # Register a checkin in source control by adding a history entry and a note
159 # This can be overriden to do extra work.
160 # The issue status/resolution would only be set if the issue is fixed, and hence $p_fixed is passed as true.
161 function custom_function_default_checkin( $p_issue_id, $p_comment, $p_file, $p_new_version, $p_fixed ) {
162 if( bug_exists( $p_issue_id ) ) {
163 history_log_event_special( $p_issue_id, CHECKIN
, $p_file, $p_new_version );
165 if( VS_PRIVATE
== config_get( 'source_control_notes_view_status' ) ) {
168 bugnote_add( $p_issue_id, $p_comment, 0, $t_private );
170 $t_status = config_get( 'source_control_set_status_to' );
171 if(( OFF
!= $t_status ) && $p_fixed ) {
172 bug_set_field( $p_issue_id, 'status', $t_status );
173 bug_set_field( $p_issue_id, 'resolution', config_get( 'source_control_set_resolution_to' ) );
178 # Hook to validate field issue data before updating
179 # Verify that the proper fields are set with the appropriate values before proceeding
180 # to change the status.
181 # In case of invalid data, this function should call trigger_error()
182 # p_issue_id is the issue number that can be used to get the existing state
183 # p_new_issue_data is an object (BugData) with the appropriate fields updated
184 function custom_function_default_issue_update_validate( $p_issue_id, $p_new_issue_data, $p_bugnote_text ) {
187 # Hook to notify after an issue has been updated.
188 # In case of errors, this function should call trigger_error()
189 # p_issue_id is the issue number that can be used to get the existing state
190 function custom_function_default_issue_update_notify( $p_issue_id ) {
193 # Hook to validate field settings before creating an issue
194 # Verify that the proper fields are set before proceeding to create an issue
195 # In case of errors, this function should call trigger_error()
196 # p_new_issue_data is an object (BugData) with the appropriate fields updated
197 function custom_function_default_issue_create_validate( $p_new_issue_data ) {
200 # Hook to notify after aa issue has been created.
201 # In case of errors, this function should call trigger_error()
202 # p_issue_id is the issue number that can be used to get the existing state
203 function custom_function_default_issue_create_notify( $p_issue_id ) {
206 # Hook to validate field settings before deleting an issue.
207 # Verify that the issue can be deleted before the actual deletion.
208 # In the case that the issue should not be deleted, this function should
209 # call trigger_error().
210 # p_issue_id is the issue number that can be used to get the existing state
211 function custom_function_default_issue_delete_validate( $p_issue_id ) {
214 # Hook to notify after an issue has been deleted.
215 # p_issue_data is the issue data (BugData) that reflects the last status of the
216 # issue before it was deleted.
217 function custom_function_default_issue_delete_notify( $p_issue_data ) {
220 # Hook for authentication
221 # can MantisBT update the password
222 function custom_function_default_auth_can_change_password() {
223 $t_can_change = array(
229 if( in_array( config_get( 'login_method' ), $t_can_change ) ) {
236 # returns an array of the column names to be displayed.
237 # The column names to use are those of the field names in the bug table.
238 # In addition, you can use the following:
239 # - "selection" for selection checkboxes.
240 # - "edit" for icon to open the edit page.
241 # - "custom_xxxx" were xxxx is the name of the custom field that is valid for the
242 # current project. In case of "All Projects, the field will be empty where it is
244 # $p_columns_target: see COLUMNS_TARGET_* in constant_inc.php
245 # $p_user_id: The user id or null for current logged in user.
246 function custom_function_default_get_columns_to_view( $p_columns_target = COLUMNS_TARGET_VIEW_PAGE
, $p_user_id = null ) {
247 $t_project_id = helper_get_current_project();
249 if( $p_columns_target == COLUMNS_TARGET_CSV_PAGE
) {
250 $t_columns = config_get( 'csv_columns', $t_project_id, $p_user_id );
251 } else if( $p_columns_target == COLUMNS_TARGET_EXCEL_PAGE
) {
252 $t_columns = config_get( 'excel_columns', $t_project_id, $p_user_id );
253 } else if( $p_columns_target == COLUMNS_TARGET_VIEW_PAGE
) {
254 $t_columns = config_get( 'view_issues_page_columns', $t_project_id, $p_user_id );
256 $t_columns = config_get( 'print_issues_page_columns', $t_project_id, $p_user_id );
259 $t_columns = columns_remove_invalid( $t_columns, columns_get_all( $t_project_id ) );
264 # Print the title of a column given its name.
265 # $p_column: custom_xxx for custom field xxx, or otherwise field name as in bug table.
266 # $p_columns_target: see COLUMNS_TARGET_* in constant_inc.php
267 function custom_function_default_print_column_title( $p_column, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE
) {
268 global $t_sort, $t_dir;
270 $t_custom_field = column_get_custom_field_name( $p_column );
271 if( $t_custom_field !== null ) {
272 if( COLUMNS_TARGET_CSV_PAGE
!= $p_columns_target ) {
276 $t_field_id = custom_field_get_id_from_name( $t_custom_field );
277 if( $t_field_id === false ) {
278 echo '@', $t_custom_field, '@';
280 $t_def = custom_field_get_definition( $t_field_id );
281 $t_custom_field = lang_get_defaulted( $t_def['name'] );
283 if( COLUMNS_TARGET_CSV_PAGE
!= $p_columns_target ) {
284 print_view_bug_sort_link( $t_custom_field, $p_column, $t_sort, $t_dir, $p_columns_target );
285 print_sort_icon( $t_dir, $t_sort, $p_column );
287 echo $t_custom_field;
291 if( COLUMNS_TARGET_CSV_PAGE
!= $p_columns_target ) {
295 $t_plugin_columns = columns_get_plugin_columns();
297 $t_function = 'print_column_title_' . $p_column;
298 if( function_exists( $t_function ) ) {
299 $t_function( $t_sort, $t_dir, $p_columns_target );
301 } else if ( isset( $t_plugin_columns[ $p_column ] ) ) {
302 $t_column_object = $t_plugin_columns[ $p_column ];
303 print_column_title_plugin( $p_column, $t_column_object, $t_sort, $t_dir, $p_columns_target );
307 print_view_bug_sort_link( column_get_title( $p_column ), $p_column, $t_sort, $t_dir, $p_columns_target );
308 print_sort_icon( $t_dir, $t_sort, $p_column );
314 # Print the value of the custom field (if the field is applicable to the project of
315 # the specified issue and the current user has read access to it.
316 # see custom_function_default_print_column_title() for rules about column names.
317 # $p_column: name of field to show in the column.
318 # $p_row: the row from the bug table that belongs to the issue that we should print the values for.
319 # $p_columns_target: see COLUMNS_TARGET_* in constant_inc.php
320 function custom_function_default_print_column_value( $p_column, $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE
) {
321 if( COLUMNS_TARGET_CSV_PAGE
== $p_columns_target ) {
322 $t_column_start = '';
324 $t_column_empty = '';
326 $t_column_start = '<td>';
327 $t_column_end = '</td>';
328 $t_column_empty = ' ';
331 $t_custom_field = column_get_custom_field_name( $p_column );
332 if( $t_custom_field !== null ) {
333 echo $t_column_start;
335 $t_field_id = custom_field_get_id_from_name( $t_custom_field );
336 if( $t_field_id === false ) {
337 echo '@', $t_custom_field, '@';
339 $t_issue_id = $p_bug->id
;
340 $t_project_id = $p_bug->project_id
;
342 if( custom_field_is_linked( $t_field_id, $t_project_id ) ) {
343 $t_def = custom_field_get_definition( $t_field_id );
344 print_custom_field_value( $t_def, $t_field_id, $t_issue_id );
346 // field is not linked to project
347 echo $t_column_empty;
352 $t_plugin_columns = columns_get_plugin_columns();
354 if( $p_columns_target != COLUMNS_TARGET_CSV_PAGE
) {
355 $t_function = 'print_column_' . $p_column;
357 $t_function = 'csv_format_' . $p_column;
360 if( function_exists( $t_function ) ) {
361 if( $p_columns_target != COLUMNS_TARGET_CSV_PAGE
) {
362 $t_function( $p_bug, $p_columns_target );
364 $t_function( $p_bug->$p_column );
367 } else if ( isset( $t_plugin_columns[ $p_column ] ) ) {
368 $t_column_object = $t_plugin_columns[ $p_column ];
369 print_column_plugin( $t_column_object, $p_bug, $p_columns_target );
372 if( isset( $p_bug->$p_column ) ) {
373 echo $t_column_start . string_display_line( $p_bug->$p_column ) . $t_column_end;
375 echo $t_column_start . '@' . $p_column . '@' . $t_column_end;
381 # Construct an enumeration for all versions for the current project.
382 # The enumeration will be empty if current project is ALL PROJECTS.
383 # Enumerations format is: "abc|lmn|xyz"
384 # To use this in a custom field type "=versions" in the possible values field.
385 function custom_function_default_enum_versions() {
386 $t_versions = version_get_all_rows( helper_get_current_project() );
389 foreach( $t_versions as $t_version ) {
390 $t_enum[] = $t_version['version'];
393 $t_possible_values = implode( '|', $t_enum );
395 return $t_possible_values;
398 # Construct an enumeration for released versions for the current project.
399 # The enumeration will be empty if current project is ALL PROJECTS.
400 # Enumerations format is: "abc|lmn|xyz"
401 # To use this in a custom field type "=released_versions" in the possible values field.
402 function custom_function_default_enum_released_versions() {
403 $t_versions = version_get_all_rows( helper_get_current_project() );
406 foreach( $t_versions as $t_version ) {
407 if( $t_version['released'] == 1 ) {
408 $t_enum[] = $t_version['version'];
412 $t_possible_values = implode( '|', $t_enum );
414 return $t_possible_values;
417 # Construct an enumeration for released versions for the current project.
418 # The enumeration will be empty if current project is ALL PROJECTS.
419 # Enumerations format is: "abc|lmn|xyz"
420 # To use this in a custom field type "=future_versions" in the possible values field.
421 function custom_function_default_enum_future_versions() {
422 $t_versions = version_get_all_rows( helper_get_current_project() );
425 foreach( $t_versions as $t_version ) {
426 if( $t_version['released'] == 0 ) {
427 $t_enum[] = $t_version['version'];
431 $t_possible_values = implode( '|', $t_enum );
433 return $t_possible_values;
436 # Construct an enumeration for all categories for the current project.
437 # The enumeration will be empty if current project is ALL PROJECTS.
438 # Enumerations format is: "abc|lmn|xyz"
439 # To use this in a custom field type "=categories" in the possible values field.
440 function custom_function_default_enum_categories() {
441 $t_categories = category_get_all_rows( helper_get_current_project() );
444 foreach( $t_categories as $t_category ) {
445 $t_enum[] = $t_category['category'];
448 $t_possible_values = implode( '|', $t_enum );
450 return $t_possible_values;
453 # This function prints the custom buttons on the current view page based on specified bug id
454 # and the context. The printing of the buttons will typically call html_button() from
455 # html_api.php. For each button, this function needs to generate the enclosing '<td>' and '</td>'.
456 function custom_function_default_print_bug_view_page_custom_buttons( $p_bug_id ) {