Skip to content

Commit 8401753

Browse files
dominikdavidhicks
authored andcommitted
Issue #12013: Improved ImportExportXml plugin
Improvements made to the importing and exporting features of this plugin: * Added support for custom fields, bugnotes and attachments * Added support for dates (date submitted, last updated) - keep dates as given in import file * Added function to easily retrieve the contents of a file (file_api.php) Signed-off-by: David Hicks <hickseydr@optusnet.com.au>
1 parent 3c6e93b commit 8401753

File tree

9 files changed

+378
-28
lines changed

9 files changed

+378
-28
lines changed

Diff for: bug_update.php

+1
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@
311311
if ( $t_bug_note->note &&
312312
config_get( 'reassign_on_feedback' ) &&
313313
$t_existing_bug->status === config_get( 'bug_feedback_status' ) &&
314+
$t_updated_bug->handler_id !== auth_get_current_user_id() &&
314315
$t_updated_bug->reporter_id === auth_get_current_user_id() ) {
315316
if ( $t_updated_bug->handler_id !== NO_USER ) {
316317
$t_updated_bug->status = config_get( 'bug_assigned_status' );

Diff for: core/bug_api.php

+11-3
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class BugData {
108108

109109
# omitted:
110110
# var $bug_text_id
111-
protected $profile_id;
111+
protected $profile_id = 0;
112112

113113
# extended info
114114
protected $description = '';
@@ -310,7 +310,14 @@ function create() {
310310

311311
# check due_date format
312312
if( is_blank( $this->due_date ) ) {
313-
$this_due_date = date_get_null();
313+
$this->due_date = date_get_null();
314+
}
315+
# check date submitted and last modified
316+
if( is_blank( $this->date_submitted ) ) {
317+
$this->date_submitted = db_now();
318+
}
319+
if( is_blank( $this->last_updated ) ) {
320+
$this->last_updated = db_now();
314321
}
315322

316323
$t_bug_table = db_get_table( 'bug' );
@@ -374,7 +381,8 @@ function create() {
374381
" . db_param() . ',' . db_param() . ',' . db_param() . ',' . db_param() . ",
375382
" . db_param() . ',' . db_param() . ',' . db_param() . ',' . db_param() . ')';
376383

377-
db_query_bound( $query, Array( $this->project_id, $this->reporter_id, $this->handler_id, $this->duplicate_id, $this->priority, $this->severity, $this->reproducibility, $t_status, $this->resolution, $this->projection, $this->category_id, db_now(), db_now(), $this->eta, $t_text_id, $this->os, $this->os_build, $this->platform, $this->version, $this->build, $this->profile_id, $this->summary, $this->view_state, $this->sponsorship_total, $this->sticky, $this->fixed_in_version, $this->target_version, $this->due_date ) );
384+
db_query_bound( $query, Array( $this->project_id, $this->reporter_id, $this->handler_id, $this->duplicate_id, $this->priority, $this->severity, $this->reproducibility, $t_status, $this->resolution, $this->projection, $this->category_id, $this->date_submitted, $this->last_updated, $this->eta, $t_text_id, $this->os, $this->os_build, $this->platform, $this->version, $this->build, $this->profile_id, $this->summary, $this->view_state, $this->sponsorship_total, $this->sticky, $this->fixed_in_version, $this->target_version, $this->due_date ) );
385+
378386

379387
$this->id = db_insert_id( $t_bug_table );
380388

Diff for: core/bugnote_api.php

+11-4
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,19 @@ function bugnote_is_user_reporter( $p_bugnote_id, $p_user_id ) {
136136
* @param string $p_attr
137137
* @param int $p_user_id user id
138138
* @param bool $p_send_email generate email?
139+
* @param int $p_date_submitted date submitted (defaults to now())
140+
* @param int $p_last_modified last modification date (defaults to now())
141+
* @param bool $p_skip_bug_update skip bug last modification update (useful when importing bugs/bugnotes)
139142
* @return false|int false or indicating bugnote id added
140143
* @access public
141144
*/
142-
function bugnote_add( $p_bug_id, $p_bugnote_text, $p_time_tracking = '0:00', $p_private = false, $p_type = 0, $p_attr = '', $p_user_id = null, $p_send_email = TRUE ) {
145+
function bugnote_add( $p_bug_id, $p_bugnote_text, $p_time_tracking = '0:00', $p_private = false, $p_type = 0, $p_attr = '', $p_user_id = null, $p_send_email = TRUE, $p_date_submitted = 0, $p_last_modified = 0, $p_skip_bug_update = FALSE ) {
143146
$c_bug_id = db_prepare_int( $p_bug_id );
144147
$c_time_tracking = helper_duration_to_minutes( $p_time_tracking );
145148
$c_private = db_prepare_bool( $p_private );
146149
$c_type = db_prepare_int( $p_type );
150+
$c_date_submitted = $p_date_submitted <= 0 ? db_now() : db_prepare_int( $p_date_submitted );
151+
$c_last_modified = $p_last_modified <= 0 ? db_now() : db_prepare_int( $p_last_modified );
147152

148153
$t_bugnote_text_table = db_get_table( 'bugnote_text' );
149154
$t_bugnote_table = db_get_table( 'bugnote' );
@@ -181,7 +186,7 @@ function bugnote_add( $p_bug_id, $p_bugnote_text, $p_time_tracking = '0:00', $p_
181186
}
182187

183188
# Check for private bugnotes.
184-
if( $p_private && access_has_bug_level( config_get( 'set_view_status_threshold' ), $p_bug_id, $c_user_id ) ) {
189+
if( $c_private && access_has_bug_level( config_get( 'set_view_status_threshold' ), $p_bug_id, $c_user_id ) ) {
185190
$t_view_state = VS_PRIVATE;
186191
} else {
187192
$t_view_state = VS_PUBLIC;
@@ -192,13 +197,15 @@ function bugnote_add( $p_bug_id, $p_bugnote_text, $p_time_tracking = '0:00', $p_
192197
(bug_id, reporter_id, bugnote_text_id, view_state, date_submitted, last_modified, note_type, note_attr, time_tracking )
193198
VALUES
194199
(" . db_param() . ', ' . db_param() . ',' . db_param() . ', ' . db_param() . ', ' . db_param() . ',' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ' )';
195-
db_query_bound( $query, Array( $c_bug_id, $c_user_id, $t_bugnote_text_id, $t_view_state, db_now(), db_now(), $c_type, $p_attr, $c_time_tracking ) );
200+
db_query_bound( $query, Array( $c_bug_id, $c_user_id, $t_bugnote_text_id, $t_view_state, $c_date_submitted, $c_last_modified, $c_type, $p_attr, $c_time_tracking ) );
196201

197202
# get bugnote id
198203
$t_bugnote_id = db_insert_id( $t_bugnote_table );
199204

200205
# update bug last updated
201-
bug_update_date( $p_bug_id );
206+
if ( !$p_skip_bug_update ) {
207+
bug_update_date( $p_bug_id );
208+
}
202209

203210
# log new bug
204211
history_log_event_special( $p_bug_id, BUGNOTE_ADDED, bugnote_format_id( $t_bugnote_id ) );

Diff for: core/constant_inc.php

+1
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
define( 'ERROR_CUSTOM_FIELD_IN_USE', 1302 );
303303
define( 'ERROR_CUSTOM_FIELD_INVALID_VALUE', 1303 );
304304
define( 'ERROR_CUSTOM_FIELD_INVALID_DEFINITION', 1304 );
305+
define( 'ERROR_CUSTOM_FIELD_NOT_LINKED_TO_PROJECT', 1305 );
305306

306307
# ERROR_LDAP_*
307308
define( 'ERROR_LDAP_AUTH_FAILED', 1400 );

Diff for: core/file_api.php

+112-3
Original file line numberDiff line numberDiff line change
@@ -628,12 +628,19 @@ function file_is_name_unique( $p_name, $p_bug_id ) {
628628
*
629629
* @param integer $p_bug_id the bug id
630630
* @param array $p_file the uploaded file info, as retrieved from gpc_get_file()
631+
* @param string $p_table table ('bug' or 'doc')
632+
* @param string $p_title file title
633+
* @param string $p_desc file description
634+
* @param int $p_user_id user id
635+
* @param int $p_date_added date added
636+
* @param bool $p_skip_bug_update skip bug last modification update (useful when importing bug attachments)
631637
*/
632-
function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '', $p_user_id = null ) {
638+
function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc = '', $p_user_id = null, $p_date_added = 0, $p_skip_bug_update = false ) {
633639

634640
file_ensure_uploaded( $p_file );
635641
$t_file_name = $p_file['name'];
636642
$t_tmp_file = $p_file['tmp_name'];
643+
$c_date_added = $p_date_added <= 0 ? db_now() : db_prepare_int( $p_date_added );
637644

638645
if( !file_type_check( $t_file_name ) ) {
639646
trigger_error( ERROR_FILE_NOT_ALLOWED, ERROR );
@@ -728,13 +735,15 @@ function file_add( $p_bug_id, $p_file, $p_table = 'bug', $p_title = '', $p_desc
728735
$query = "INSERT INTO $t_file_table
729736
(" . $p_table . "_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content, user_id)
730737
VALUES
731-
($c_id, '$c_title', '$c_desc', '$c_unique_name', '$c_new_file_name', '$c_file_path', $c_file_size, '$c_file_type', '" . db_now() . "', $c_content, $c_user_id)";
738+
($c_id, '$c_title', '$c_desc', '$c_unique_name', '$c_new_file_name', '$c_file_path', $c_file_size, '$c_file_type', '" . $c_date_added . "', $c_content, $c_user_id)";
732739
db_query( $query );
733740

734741
if( 'bug' == $p_table ) {
735742

736743
# updated the last_updated date
737-
$result = bug_update_date( $p_bug_id );
744+
if ( !$p_skip_bug_update ) {
745+
$result = bug_update_date( $p_bug_id );
746+
}
738747

739748
# log new bug
740749
history_log_event_special( $p_bug_id, FILE_ADDED, $t_file_name );
@@ -868,3 +877,103 @@ function file_get_extension( $p_filename ) {
868877
}
869878
return $t_extension;
870879
}
880+
881+
/**
882+
* Get file content
883+
*
884+
* @param int $p_file_id file id
885+
* @param string $p_type file type (either 'bug' or 'doc')
886+
* @return array|bool array containing file type and content or false on failure to retrieve file
887+
*/
888+
function file_get_content( $p_file_id, $p_type = 'bug' ) {
889+
# we handle the case where the file is attached to a bug
890+
# or attached to a project as a project doc.
891+
$query = '';
892+
switch ( $p_type ) {
893+
case 'bug':
894+
$t_bug_file_table = db_get_table( 'mantis_bug_file_table' );
895+
$query = "SELECT *
896+
FROM $t_bug_file_table
897+
WHERE id=" . db_param();
898+
break;
899+
case 'doc':
900+
$t_project_file_table = db_get_table( 'mantis_project_file_table' );
901+
$query = "SELECT *
902+
FROM $t_project_file_table
903+
WHERE id=" . db_param();
904+
break;
905+
default:
906+
return false;
907+
}
908+
$result = db_query_bound( $query, Array( $p_file_id ) );
909+
$row = db_fetch_array( $result );
910+
911+
if ( $f_type == 'bug' ) {
912+
$t_project_id = bug_get_field( $row['bug_id'], 'project_id' );
913+
} else {
914+
$t_project_id = $row['bug_id'];
915+
}
916+
917+
# If finfo is available (always true for PHP >= 5.3.0) we can use it to determine the MIME type of files
918+
$finfo_available = false;
919+
if ( class_exists( 'finfo' ) ) {
920+
$t_info_file = config_get( 'fileinfo_magic_db_file' );
921+
922+
if ( is_blank( $t_info_file ) ) {
923+
$finfo = new finfo( FILEINFO_MIME );
924+
} else {
925+
$finfo = new finfo( FILEINFO_MIME, $t_info_file );
926+
}
927+
928+
if ( $finfo ) {
929+
$finfo_available = true;
930+
}
931+
}
932+
933+
$t_content_type = $row['file_type'];
934+
935+
switch ( config_get( 'file_upload_method' ) ) {
936+
case DISK:
937+
$t_local_disk_file = file_normalize_attachment_path( $row['diskfile'], $t_project_id );
938+
939+
if ( file_exists( $t_local_disk_file ) ) {
940+
if ( $finfo_available ) {
941+
$t_file_info_type = $finfo->file( $t_local_disk_file );
942+
943+
if ( $t_file_info_type !== false ) {
944+
$t_content_type = $t_file_info_type;
945+
}
946+
}
947+
return array( 'type' => $t_content_type, 'content' => file_get_contents( $t_local_disk_file ) );
948+
}
949+
break;
950+
case FTP:
951+
$t_local_disk_file = file_normalize_attachment_path( $row['diskfile'], $t_project_id );
952+
953+
if ( !file_exists( $t_local_disk_file ) ) {
954+
$ftp = file_ftp_connect();
955+
file_ftp_get ( $ftp, $t_local_disk_file, $row['diskfile'] );
956+
file_ftp_disconnect( $ftp );
957+
}
958+
959+
if ( $finfo_available ) {
960+
$t_file_info_type = $finfo->file( $t_local_disk_file );
961+
962+
if ( $t_file_info_type !== false ) {
963+
$t_content_type = $t_file_info_type;
964+
}
965+
}
966+
return array( 'type' => $t_content_type, 'content' => file_get_contents( $t_local_disk_file ) );
967+
break;
968+
default:
969+
if ( $finfo_available ) {
970+
$t_file_info_type = $finfo->buffer( $row['content'] );
971+
972+
if ( $t_file_info_type !== false ) {
973+
$t_content_type = $t_file_info_type;
974+
}
975+
}
976+
return array( 'type' => $t_content_type, 'content' => $row['content'] );
977+
break;
978+
}
979+
}

Diff for: lang/strings_english.txt

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ $MANTIS_ERROR[ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE] = 'This is a duplicate name.';
238238
$MANTIS_ERROR[ERROR_CUSTOM_FIELD_IN_USE] = 'At least one project still uses this field.';
239239
$MANTIS_ERROR[ERROR_CUSTOM_FIELD_INVALID_VALUE] = 'Invalid value for field "%1$s".';
240240
$MANTIS_ERROR[ERROR_CUSTOM_FIELD_INVALID_DEFINITION] = 'Invalid custom field definition.';
241+
$MANTIS_ERROR[ERROR_CUSTOM_FIELD_NOT_LINKED_TO_PROJECT] = 'Custom field "%1$s" (id %2$s) not linked to currently active project.';
241242
$MANTIS_ERROR[ERROR_LDAP_AUTH_FAILED] = 'LDAP Authentication Failed.';
242243
$MANTIS_ERROR[ERROR_LDAP_SERVER_CONNECT_FAILED] = 'LDAP Server Connection Failed.';
243244
$MANTIS_ERROR[ERROR_LDAP_UPDATE_FAILED] = 'LDAP Record Update has failed.';

Diff for: plugins/XmlImportExport/ImportXml.php

+24-5
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,42 @@ public function import( ) {
102102

103103
echo " Done\n";
104104

105+
// replace references in bug description and additional information
105106
$importedIssues = $this->itemsMap_->getall( 'issue' );
106107
printf( "Processing cross-references for %s issues...", count( $importedIssues ) );
107108
foreach( $importedIssues as $oldId => $newId ) {
108109
$bugData = bug_get( $newId, true );
109110

110111
$bugLinkRegexp = '/(^|[^\w])(' . preg_quote( $this->source_->issuelink, '/' ) . ')(\d+)\b/e';
111-
$replacement = '"\\1" . $this->getReplacementString( "\\2", "\\3" )';
112-
113-
$bugData->description = preg_replace( $bugLinkRegexp, $replacement, $bugData->description );
114-
bug_update( $newId, $bugData, true, true );
112+
// replace links in description
113+
preg_match_all( $bugLinkRegexp, $bugData->description, $matches );
114+
if ( is_array( $matches[3] && count( $matches[3] ) > 0 ) ) {
115+
$content_replaced = true;
116+
foreach ( $matches[3] as $old_id ) {
117+
$bugData->description = str_replace( $this->source_->issuelink . $old_id, $this->getReplacementString( $this->source_->issuelink, $old_id ), $bugData->description);
118+
}
119+
}
120+
// replace links in additional information
121+
preg_match_all( $bugLinkRegexp, $bugData->additional_information, $matches );
122+
if ( is_array( $matches[3] && count( $matches[3] ) > 0 ) ) {
123+
$content_replaced = true;
124+
foreach ( $matches[3] as $old_id ) {
125+
$bugData->additional_information = str_replace( $this->source_->issuelink . $old_id, $this->getReplacementString( $this->source_->issuelink, $old_id ), $bugData->additional_information);
126+
}
127+
}
128+
if ( $content_replaced ) {
129+
// only update bug if necessary (otherwise last update date would be unnecessarily overwritten)
130+
$bugData->update( true );
131+
}
115132
}
133+
134+
// @todo: replace references within bugnotes
116135
echo " Done\n";
117136
}
118137

119138
/**
120139
* Compute and return the new link
121-
*
140+
*
122141
*/
123142
private function getReplacementString( $oldLinkTag, $oldId ) {
124143
$linkTag = config_get( 'bug_link_tag' );

0 commit comments

Comments
 (0)