PHP Classes

PHP Mantis Export to iCal: Export Mantis bug reports in iCal format

Recommend this page to a friend!
  Info   View files Example   View files View files (8)   DownloadInstall with Composer Download .zip   Reputation   Support forum   Blog    
Ratings Unique User Downloads Download Rankings
Not yet rated by the usersTotal: 39 This week: 1All time: 10,855 This week: 571Up
Version License PHP version Categories
icalexport 1.0.0GNU Lesser Genera...5PHP 5, Tools, Project Management
Description 

Author

This package can be used to export Mantis bug reports in iCal format.

It is a plugin for the Mantis Bug Tracker application that allows exporting bug reports as calendar tasks in a iCal media file so those bug reports can be imported to a public calendar or a private calendar in a PC, pad or smartphone.

Innovation Award
PHP Programming Innovation award nominee
March 2020
Number 11
Mantis is a well known bug tracking application written in PHP.

This package is a plugin that allows exporting bugs that need to be fixed in iCal format, so it can be used to plan a schedule to fix those bugs in applications that work like calendars, like for instance Google Calendar.

Manuel Lemos
Picture of Kjell-Inge Gustafsson
  Performance   Level  
Name: Kjell-Inge Gustafsson <contact>
Classes: 15 packages by
Country: Sweden Sweden
Age: ???
All time rank: 4922 in Sweden Sweden
Week rank: 50 Up1 in Sweden Sweden Up
Innovation award
Innovation award
Nominee: 6x

Example

<?php
/**
 * IcalExport, Mantis calendar Export Plugin
 *
 * Adapted for iCalcreator >= 6.27.16
 *
 * @package MantisPlugin
 * @subpackage IcalExport
 * @copyright Copyright (C) 2013-2019 Kjell-Inge Gustafsson, kigkonsult, All rights reserved.
 * @link http://kigkonsult.se/IcalExport
 * @license Subject matter of licence is the software IcalExport.
 * The above copyright, link, package and version notices,
 * this licence notice shall be included in all copies or
 * substantial portions of the IcalExport.
 *
 * IcalExport is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * IcalExport is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with iCalcreator. If not, see <https://www.gnu.org/licenses/>.
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
 * @version 2.0
 * @since 2.0 - 2019-03-25
 *
 * This file is a part of IcalExport.
 */
/*
 * MantisBT Core API's
 */
require_once( 'core.php' );
require_api( 'user_api.php' );
require_api( 'bug_api.php' );
require_api( 'bugnote_api.php' );
require_api( 'file_api.php' );
require_api( 'gpc_api.php' );
require_api( 'relationship_api.php' );
require_api( 'tag_api.php' );
auth_ensure_user_authenticated();
helper_begin_long_process();
ob_clean();

/*
 * get the user currently logged in
 */
$t_user_id = auth_get_current_user_id();
$t_user_name = user_get_name( $t_user_id );
$t_user_email = user_get_email( $t_user_id );
$t_show_tags = access_has_global_level( config_get( 'tag_view_threshold' ));

/*
 * get some config values
 */
// $t_parsed_url = parse_url( $t_url ); // TODO, find site/system unique id??!!
// $t_unique_id = $t_parsed_url['host'];
$t_unique_id = config_get( 'hostname' );
$t_url = config_get( 'path' );
$t_normal_date_format = config_get( 'normal_date_format' );

/*
 * get bug id(s)
 */
$f_bug_id = gpc_get_int( 'id', 0 );
$t_cnt = 0;
if( empty(
$f_bug_id )) {
   
/*
     * Get bug rows according to the current filter
     */
   
require_api( 'filter_api.php' );
   
$t_page_number = 1;
   
$t_per_page = -1;
   
$t_page_count = null;
   
$t_bug_count = null;
   
$t_result = filter_get_bug_rows(
       
$t_page_number,
       
$t_per_page,
       
$t_page_count,
       
$t_bug_count
   
);
   
$t_cnt = count( $t_result );
   
$t_calname = plugin_lang_get( 'x_wr_calname2' );
   
$t_caldesc = plugin_lang_get( 'x_wr_caldesc2' );
   
$t_redirect_url = 'view_all_bug_page.php';
}
else {
   
/*
     * Get bug row according to parameter id
     */
   
bug_ensure_exists( $f_bug_id );
   
$t_result = bug_get( $f_bug_id, true );
    if( ! empty(
$t_result )) {
       
$t_cnt = 1;
       
$t_result = [ $t_result ];
    }
   
$t_calname = plugin_lang_get( 'x_wr_calname1' ) . $f_bug_id;
   
$t_caldesc = plugin_lang_get( 'x_wr_caldesc1' ) . $f_bug_id;
   
$t_redirect_url = 'view.php?id=' . $f_bug_id;
}
/*
 * If no found, return
 */
if( empty( $t_cnt )) {
   
require_api( 'print_api.php' );
   
print_header_redirect( $t_redirect_url );
}

/*
 * properties that we want to export are 'protected'
 */
$t_columns = array_keys( getClassProperties( 'BugData', 'protected' ));
/*
 * Ignored fields, these will be skipped
 */
$t_ignore = [ '_stats', 'bug_text_id', ];

/*
 * iCalcreator loader setup
 */
require_once( 'CalendarLoader.php' );
$t_calendarLoader = new CalendarLoader( $t_unique_id, $t_normal_date_format, $t_user_name, $t_calname, $t_caldesc );

/*
 * export each bug/row into an Vcalendar vtodo object instance
 */
$t_cnt = 0;
foreach(
$t_result as $t_ix => $t_bug ) {
    if( ! isset(
$t_bug->id )) {
        continue;
    }
   
$t_cnt += 1;

   
/*
     * Initiate a new Vtodo with
     * SEQUENCE property set from number of rows in table bug_history (+1)
     */
   
$t_last_updated = $t_eta = $t_due = null;
   
$t_created = ( isset( $t_bug->date_submitted )) ? $t_bug->date_submitted : time();
   
$t_calendarLoader->initNewVtodo(
       
$t_created,
       
$t_url,
       
$t_bug->id,
       
get_bug_history_count( $t_bug->id ),
       
$t_user_email
   
);

    foreach(
$t_columns as $t_ix2 => $t_element ) {
        if(
in_array( $t_element, $t_ignore )) {
            continue;
        }
       
$t_value = $t_bug->{$t_element};
       
/*
         * Ignore empty values
         */
       
if( empty( $t_value )) {
            continue;
        }
        switch(
$t_element ) {
            case
'id':
               
$t_calendarLoader->updateDescriptions( $t_element, $t_value );
                break;
            case
'project_id':
               
$t_calendarLoader->updateDescriptions( 'project', project_get_name( $t_value ));
                break;
           
/*
             * Set iCal component ATTENDEE property
             */
           
case 'reporter_id':
               
$t_value2 = user_get_email( $t_value );
               
$t_calendarLoader->updateAttendee(
                   
$t_value2,
                   
user_get_name( $t_value ),
                    [
'DELEGATED-FROM' => true ]
                );
               
$t_calendarLoader->updateDescriptions( 'reporter', $t_value2 );
                break;
           
/*
             * Set iCal component ORGANIZER/ATTENDEE/DTSTART property
             */
           
case 'handler_id':
               
$t_calendarLoader->updateAttendee(
                   
user_get_email( $t_value ),
                   
user_get_name( $t_value ),
                    [
'ROLE' => 'CHAIR' ]
                );
               
$t_dtstart = get_assignment_start_date( $t_bug->id, $t_value );
                if( empty(
$t_dtstart )) {
                   
$t_dtstart = $t_bug->date_submitted;
                }
               
$t_calendarLoader->setDtstart( $t_dtstart );
                break;
           
/*
             * Set iCal component CATEGORIES property
             */
           
case 'category_id':
               
$t_category_name = category_get_name( $t_value );
               
$t_calendarLoader->setCategories( [ $t_category_name ] );
               
$t_calendarLoader->updateDescriptions( 'category', $t_category_name );
                break;
           
/*
             * already fixed
             */
           
case 'date_submitted':
                break;
           
/*
             * Save for later use
             */
           
case 'last_updated':
               
$t_last_updated = $t_value;
                break;
           
/*
             * Save for later use
             */
           
case 'eta':
               
$t_eta = $t_value;
               
$t_calendarLoader->updateDescriptions( $t_element, get_enum_element( $t_element, $t_value ));
                break;
           
/*
             * Set iCal component DUE property
             */
           
case 'due_date':
                if( !
date_is_null( $t_value )) {
                   
$t_due = $t_value;
                   
$t_calendarLoader->setDue( $t_value );
                }
                break;
           
/*
             * Set iCal component PRIORITY property
             */
           
case 'priority':
               
$t_calendarLoader->setPriority( $t_value, get_enum_element( $t_element, $t_value ));
                break;
           
/*
             * Set iCal component STATUS property parameter
             */
           
case 'resolution':
               
$t_calendarLoader->setResolution( $t_element, get_enum_element( $t_element, $t_value ));
                break;
           
/*
             * Set iCal component CLASS property
             */
           
case 'view_state':
               
$t_calendarLoader->setClass( $t_value );
                break;
           
/*
             * Used as iCal component STATUS property parameter
             */
           
case 'severity':
               
$t_calendarLoader->setSeverity( $t_element, get_enum_element( $t_element, $t_value ));
                break;
           
/*
             * Used as iCal component PRIORITY property parameter
             */
           
case 'reproducibility':
               
$t_calendarLoader->setReproducibility( $t_element, get_enum_element( $t_element, $t_value ));
                break;
           
/*
             * Set as iCal component STATUS property parameter
             */
           
case 'status':
               
$t_calendarLoader->setStatus( $t_value, get_enum_element( $t_element, $t_value ));
                break;
            case
'projection':
               
$t_calendarLoader->updateDescriptions( $t_element, get_enum_element( $t_element, $t_value ));
                break;
           
/*
             * Set iCal component SUMMARY property
             */
           
case 'summary':
               
$t_calendarLoader->setSummary( $t_value );
                break;
            default:
               
$t_calendarLoader->updateDescriptions( $t_element, $t_value );
                break;
        }
// end switch( $t_element )
   
} // end foreach( $t_columns as $t_ix2 => $t_element )



    /*
     * Set iCal component LAST-MODIFIED property
     */
   
if( ! empty( $t_last_updated ) && ( $t_last_updated > $t_created )) {
       
$t_calendarLoader->setLastmodified( $t_last_updated );
    }

   
/*
     * Create an iCal DUE date property, based on created (above),
     * only if mantis due is not set and eta is set,
     */
   
if( empty( $t_due ) && ! empty( $t_eta )) {
       
$t_calendarLoader->setDue( $t_created, $t_eta );
    }

   
/*
     * Export each mantis bug report bugnote as an iCal COMMENT
     */
   
$t_bugnot_users = [];
    foreach(
        (array)
bugnote_get_all_visible_bugnotes(
           
$t_bug->id,
           
current_user_get_pref( 'bugnote_order' ),
           
0,
           
$t_user_id
       
)
        as
$t_bugnote ) {
        if((
BUGNOTE == $t_bugnote->note_type )&&
           (
VS_PRIVATE != $t_bugnote->view_state )) {
           
$t_name = user_get_name( $t_bugnote->reporter_id );
           
$t_email = user_get_email( $t_bugnote->reporter_id );
           
$t_calendarLoader->setComment(
               
$t_bugnote->note,
                [
                   
'id' => $t_bugnote->id,
                   
'type' => 'bugnote',
                   
'date-submitted' => date( $t_normal_date_format, $t_bugnote->date_submitted ),
                   
'name' => $t_name,
                ]
            );
            if( isset(
$t_bugnot_users[$t_email] )) {
               
$t_bugnot_users[$t_email]['id'][] = $t_bugnote->id;
            }
            else {
               
$t_bugnot_users[$t_email] = ['name' => $t_name, 'id' => [$t_bugnote->id]];
            }
        }
    }
// end foreach
   
foreach( $t_bugnot_users as $t_email => $t_data ) {
       
$t_calendarLoader->updateAttendee(
           
$t_email,
           
$t_data['name'],
            [
'x-bugnote' => implode( ',', $t_data['id'] ) ]
        );
    }

   
/*
     * Export each mantis bug monitors as iCal ATTENDEEs
     */
   
foreach( ( array) bug_get_monitors( $t_bug->id ) as $t_monitor_id ) {
       
$t_calendarLoader->updateAttendee(
           
user_get_email( $t_monitor_id ),
           
user_get_name( $t_monitor_id ),
            [
'x-role' => 'monitor' ]
        );
    }

   
/*
     * Export each mantis bug report relations as an iCal RELATED-TOs
     */
   
foreach( ( array) relationship_get_all( $t_bug->id, $t_is_different_projects ) as $t_relationship ) {
        if(
$t_bug->id == $t_relationship->src_bug_id ) {
           
$t_reltype = 'PARENT';
           
$t_rel_bug_id = $t_relationship->dest_bug_id;
        }
        else {
           
$t_reltype = 'CHILD';
           
$t_rel_bug_id = $t_relationship->src_bug_id;
        }
       
$t_rel_bug = bug_get( $t_rel_bug_id );
       
$date_submitted = $t_rel_bug->date_submitted;
       
$t_calendarLoader->setRelatedto(
           
CalendarLoader::renderUID( $date_submitted, $t_rel_bug_id, $t_unique_id ),
            [
               
'RELTYPE' => $t_reltype,
               
'x-type' => relationship_get_name_for_api( $t_relationship->type ),
               
'x-id' => $t_rel_bug_id,
               
'x-date-submitted' =>
                   
CalendarLoader::renderDate( $date_submitted, null, $t_normal_date_format ),
               
'x-summary' => $t_rel_bug->summary,
               
'x-url' => CalendarLoader::renderURL( $t_url, $t_rel_bug_id )
            ]
        );
    }

   
/*
     * export each mantis bug report tag(s) as (additional) iCal CATEGORIES
     */
   
if( $t_show_tags ) {
        foreach( (array)
tag_bug_get_attached( $t_bug->id ) as $t_tag ) {
           
$t_calendarLoader->setCategories(
               
$t_tag['name'],
                [
                   
'date-submitted' => date( $t_normal_date_format, $t_tag['date_attached'] ),
                   
'name' => user_get_name( $t_tag['user_attached'] ),
                   
'origin' => 'tags',
                ]
            );
        }
    }

   
/*
     * Export each mantis bug report attachments as iCal ATTACHs (link)
     */
   
$t_calendarLoader->setAttachments(
        (array)
file_get_visible_attachments( $t_bug->id ),
       
$t_url
   
);

   
/*
     * Close Vtodo
     */
   
$t_calendarLoader->closeVtodo();

}
// end foreach( $t_result as $t_bug )

if( empty( $t_cnt )) {
   
require_api( 'print_api.php' );
   
print_header_redirect( $t_redirect_url );
}
$t_calendarLoader->returnCalendar();
exit();

/**
 * Return (first) startdate for bug assignment from bug_history
 *
 * @param int $p_bug_id
 * @param int $p_user_id
 * @return int|bool timestamp or false (not found)
 */
function get_assignment_start_date( $p_bug_id, $p_user_id ) {
    static
$t_fmt_query =
       
'SELECT date_modified FROM {bug_history} WHERE bug_id=%s AND field_name=%s AND new_value=%s ORDER BY 1';
    static
$t_fmt_handler_id = 'handler_id';
   
$t_query = sprintf( $t_fmt_query, db_param(), db_param(), db_param());
   
$t_result = db_query( $t_query, [ $p_bug_id, $t_fmt_handler_id, $p_user_id ] );
   
$t_rows = db_num_rows( $t_result );
    return ( empty(
$t_rows )) ? false : (int) db_result( $t_result );
}
/**
 * Return number of rows (+1) in database table bug_history for bug_id as sequence number
 *
 * @param int $p_bug_id
 * @return int
 */
function get_bug_history_count( $p_bug_id ) {
    static
$t_fmt_query = 'SELECT COUNT(*) AS %s FROM {bug_history} WHERE bug_id=%s';
    static
$t_fmt_antal = 'antal';
   
$t_query = sprintf( $t_fmt_query, $t_fmt_antal, db_param());
   
$t_result = db_query( $t_query, [ $p_bug_id ] );
   
$t_rows = db_num_rows( $t_result );
    if( empty(
$t_rows )) {
       
$t_result = 1;
    }
    else {
       
$row = db_fetch_array( $t_result );
       
$t_result = (int) $row[$t_fmt_antal] + 1;
    }
    return
$t_result;
}


Details

IcalExport

Export selected [MantisBT] issues

as iCal calendar tasks (i.e. TODOs)

in a iCal media file (extension .ics)

for import into - public calendars - business/organization calendars - private calendars in a PC, pad or smartphone - etc

IcalExport requires - PHP >= 5.6 - [MantisBT] v2.20.0 - Icalcreator for iCal management.

[iCal]: http://en.wikipedia.org/wiki/ICalendar

[Mantisbt]: https://mantisbt.org/

[Icalcreator]: https://github.com/iCalcreator/iCalcreator/

[rfc2445]: https://tools.ietf.org/html/rfc2445

[rfc5545]: https://tools.ietf.org/html/rfc5545


  Files folder image Files  
File Role Description
Files folder imagedocs (2 files)
Files folder imagelang (2 files)
Files folder imagepages (2 files)
Plain text file IcalExport.php Class Class source
Accessible without login Plain text file README.md Doc. Documentation

  Files folder image Files  /  docs  
File Role Description
  Accessible without login Plain text file lgpl.txt Doc. Documentation
  Accessible without login Plain text file README.txt Doc. Documentation

  Files folder image Files  /  lang  
File Role Description
  Accessible without login Plain text file strings_english.txt Doc. Documentation
  Accessible without login Plain text file strings_swedish.txt Doc. Documentation

  Files folder image Files  /  pages  
File Role Description
  Plain text file CalendarLoader.php Class Class source
  Accessible without login Plain text file IcalExport.php Example Example script

 Version Control Unique User Downloads Download Rankings  
 100%
Total:39
This week:1
All time:10,855
This week:571Up