mantis-matrix-integration – Rev 3

Subversion Repositories:
Rev:
<?php
/**
 * Matrix Integration
 * Copyright (C) 2024 Wizardry and Steamworks (wizardry.steamworks@outlook.com)
 *     based on: Slack Integration by 2014 Karim Ratib (karim.ratib@gmail.com)
 * License GPLv2
 */

require_once __DIR__ . '/vendor/autoload.php';
use MatrixPhp\MatrixClient;

class MatrixPlugin extends MantisPlugin {
    var $skip = false;

    function register() {
        $this->name = plugin_lang_get( 'title' );
        $this->description = plugin_lang_get( 'description' );
        $this->page = 'config';
        $this->version = '1.0';
        $this->requires = array(
            'MantisCore' => '1.3.0',
        );
        $this->author = 'Wizardry and Steamworks';
        $this->contact = 'wizardry.stemworks@outlook.com';
        $this->url = 'https://grimore.org';
    }

    function install() {
        if (version_compare(PHP_VERSION, '5.3.0', '<')) {
            plugin_error(ERROR_PHP_VERSION, ERROR);
            return false;
        }
        if (!extension_loaded('curl')) {
            plugin_error(ERROR_NO_CURL, ERROR);
            return false;
        }
        return true;
    }

    function config() {
        return array(
            'server' => 'https://matrix.org',
            'username' => 'mantis',
            'skip_bulk' => true,
            'room' => '#general'
        );
    }

    function hooks() {
        return array(
            'EVENT_REPORT_BUG' => 'bug_report_update',
            'EVENT_UPDATE_BUG' => 'bug_report_update',
            'EVENT_BUG_DELETED' => 'bug_deleted',
            'EVENT_BUG_ACTION' => 'bug_action',
            'EVENT_BUGNOTE_ADD' => 'bugnote_add_edit',
            'EVENT_BUGNOTE_EDIT' => 'bugnote_add_edit',
            'EVENT_BUGNOTE_DELETED' => 'bugnote_deleted',
            'EVENT_BUGNOTE_ADD_FORM' => 'bugnote_add_form',
        );
    }

    function bugnote_add_form($event, $bug_id) {
        if ($_SERVER['PHP_SELF'] !== '/bug_update_page.php') return;

        echo '<tr><td class="center" colspan="6">';
        echo '<input ', helper_get_tab_index(), ' name="matrix_skip" type="checkbox" >' . plugin_lang_get('skip') . '</input>';
        echo '</td></tr>';
    }

    function bug_report_update($event, $bug, $bug_id) {
        $this->skip = $this->skip || gpc_get_bool('matrix_skip');

        $project = project_get_name($bug->project_id);
        $url = string_get_bug_view_url_with_fqdn($bug->id);
        //$summary = $this->format_summary($bug);
        $reporter = '@' . user_get_name(auth_get_current_user_id());
        $msg = sprintf(
            plugin_lang_get($event === 'EVENT_REPORT_BUG' ? 'bug_created' : 'bug_updated'),
            $project,
            $reporter,
            $url,
            $bug->id
        );
        $this->notify($msg);
    }

    function bug_action($event, $action, $bug_id) {
        $this->skip = $this->skip || gpc_get_bool('matrix_skip') || plugin_config_get('skip_bulk');

        if ($action !== 'DELETE') {
            $bug = bug_get($bug_id);
            $this->bug_report_update('EVENT_UPDATE_BUG', $bug, $bug_id);
        }
    }

    function bug_deleted($event, $bug_id) {
        $this->skip = $this->skip || gpc_get_bool('matrix_skip');

        $bug = bug_get($bug_id);
        $url = string_get_bug_view_url_with_fqdn($bug->id);
        $project = project_get_name($bug->project_id);
        $reporter = '@' . user_get_name(auth_get_current_user_id());
        //$summary = $this->format_summary($bug);
        $msg = sprintf(
            plugin_lang_get('bug_deleted'), 
            $project, 
            $reporter,
            $url, 
            $bug->id
        );
        $this->notify($msg);
    }

    function bugnote_add_edit($event, $bug_id, $bugnote_id) {
        $this->skip = $this->skip || gpc_get_bool('matrix_skip');

        $bug = bug_get($bug_id);
        $url = string_get_bugnote_view_url_with_fqdn($bug_id, $bugnote_id);
        $project = project_get_name($bug->project_id);
        //$summary = $this->format_summary($bug);
        $reporter = '@' . user_get_name(auth_get_current_user_id());
        //$note = bugnote_get_text($bugnote_id);
        $msg = sprintf(
            plugin_lang_get($event === 'EVENT_BUGNOTE_ADD' ? 'bugnote_created' : 'bugnote_updated'),
            $project, 
            $reporter,
            $url, 
            $bug_id
        );
        $this->notify($msg);
    }

    function bugnote_deleted($event, $bug_id, $bugnote_id) {
        $this->skip = $this->skip || gpc_get_bool('matrix_skip');

        $bug = bug_get($bug_id);
        $project = project_get_name($bug->project_id);
        $url = string_get_bug_view_url_with_fqdn($bug->id);
        //$summary = $this->format_summary($bug);
        $reporter = '@' . user_get_name(auth_get_current_user_id());
        $msg = sprintf(
            plugin_lang_get('bugnote_deleted'),
            $project,
            $reporter,
            $url,
            $bug->id
        );
        $this->notify($msg);
    }

    function format_summary($bug) {
        $summary = bug_format_id($bug->id) . ': ' . string_display_line_links($bug->summary);
        return strip_tags(html_entity_decode($summary));
    }

    function format_text($bug, $text) {
        $t = string_display_line_links($text);
        return strip_tags(html_entity_decode($t));
    }

    function format_value($bug, $field_name) {
        $self = $this;
        $values = array(
            'id' => function($bug) { return sprintf('<%s|%s>', string_get_bug_view_url_with_fqdn($bug->id), $bug->id); },
            'project_id' => function($bug) { return project_get_name($bug->project_id); },
            'reporter_id' => function($bug) { return '@' . user_get_name($bug->reporter_id); },
            'handler_id' => function($bug) { return empty($bug->handler_id) ? plugin_lang_get('no_user') : ('@' . user_get_name($bug->handler_id)); },
            'duplicate_id' => function($bug) { return sprintf('<%s|%s>', string_get_bug_view_url_with_fqdn($bug->duplicate_id), $bug->duplicate_id); },
            'priority' => function($bug) { return get_enum_element( 'priority', $bug->priority ); },
            'severity' => function($bug) { return get_enum_element( 'severity', $bug->severity ); },
            'reproducibility' => function($bug) { return get_enum_element( 'reproducibility', $bug->reproducibility ); },
            'status' => function($bug) { return get_enum_element( 'status', $bug->status ); },
            'resolution' => function($bug) { return get_enum_element( 'resolution', $bug->resolution ); },
            'projection' => function($bug) { return get_enum_element( 'projection', $bug->projection ); },
            'category_id' => function($bug) { return category_full_name( $bug->category_id, false ); },
            'eta' => function($bug) { return get_enum_element( 'eta', $bug->eta ); },
            'view_state' => function($bug) { return $bug->view_state == VS_PRIVATE ? lang_get('private') : lang_get('public'); },
            'sponsorship_total' => function($bug) { return sponsorship_format_amount( $bug->sponsorship_total ); },
            'os' => function($bug) { return $bug->os; },
            'os_build' => function($bug) { return $bug->os_build; },
            'platform' => function($bug) { return $bug->platform; },
            'version' => function($bug) { return $bug->version; },
            'fixed_in_version' => function($bug) { return $bug->fixed_in_version; },
            'target_version' => function($bug) { return $bug->target_version; },
            'build' => function($bug) { return $bug->build; },
            'summary' => function($bug) use($self) { return $self->format_summary($bug); },
            'last_updated' => function($bug) { return date( config_get( 'short_date_format' ), $bug->last_updated ); },
            'date_submitted' => function($bug) { return date( config_get( 'short_date_format' ), $bug->date_submitted ); },
            'due_date' => function($bug) { return date( config_get( 'short_date_format' ), $bug->due_date ); },
            'description' => function($bug) use($self) { return $self->format_text( $bug, $bug->description ); },
            'steps_to_reproduce' => function($bug) use($self) { return $self->format_text( $bug, $bug->steps_to_reproduce ); },
            'additional_information' => function($bug) use($self) { return $self->format_text( $bug, $bug->additional_information ); },
        );
        // Discover custom fields.
        $t_related_custom_field_ids = custom_field_get_linked_ids( $bug->project_id );
        foreach ( $t_related_custom_field_ids as $t_id ) {
            $t_def = custom_field_get_definition( $t_id );
            $values['custom_' . $t_def['name']] = function($bug) use ($t_id) {
                return custom_field_get_value( $t_id, $bug->id );
            };
        }
        if (isset($values[$field_name])) {
            $func = $values[$field_name];
            return $func($bug);
        }
        else {
            return FALSE;
        }
    }

    function notify($msg) {
        if ($this->skip) return;
        
        $client = new MatrixClient(plugin_config_get('server'));
        $token = $client->login(
            plugin_config_get('username'),
            plugin_config_get('password')
        );
        
        $room = $client->joinRoom(plugin_config_get('room'));
        $response = $room->sendHtml($msg);
    }
}