MantisBT-Discord

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 1  →  ?path2? @ HEAD
/trunk/.git/logs/HEAD
@@ -1 +1 @@
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584818357 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584814853 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
/trunk/.git/logs/refs/heads/master
@@ -1 +1 @@
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584818357 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584814853 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
/trunk/.git/logs/refs/remotes/origin/HEAD
@@ -1 +1 @@
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584818357 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584814853 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
/trunk/Discord.php
@@ -1,4 +1,5 @@
<?php
 
/**
* Discord Integration
* Copyright (C) Robin van Nunen (robin@vnunen.nl) for Discord modification
@@ -27,26 +28,24 @@
{
$this->name = plugin_lang_get('title');
$this->description = plugin_lang_get('description');
$this->page = 'config_page';
$this->page = 'config';
$this->version = '1.0';
$this->requires = array(
'MantisCore' => '2.0.0',
'MantisCore' => '1.3.0',
);
$this->author = 'Robin van Nunen';
$this->contact = 'robin@vnunen.nl';
$this->author = 'Robin van Nunen & Wizardry and Steamworks';
$this->contact = 'robin@vnunen.nl / office@grimore.org';
$this->url = 'https://github.com/TechGuard/MantisBT-Discord';
}
 
function install()
{
if(version_compare(PHP_VERSION, '5.3.0', '<'))
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
plugin_error(ERROR_PHP_VERSION, ERROR);
 
return false;
}
if(!extension_loaded('curl'))
{
if (!extension_loaded('curl')) {
plugin_error(ERROR_NO_CURL, ERROR);
 
return false;
@@ -64,12 +63,12 @@
'link_names' => true,
'language' => 'english',
'usernames' => array(),
'hook_bug_report' => true,
'hook_bug_update' => true,
'hook_bug_deleted' => true,
'hook_bugnote_add' => true,
'hook_bugnote_edit' => true,
'hook_bugnote_deleted' => true,
'hook_bug_report' => true,
'hook_bug_update' => true,
'hook_bug_deleted' => true,
'hook_bugnote_add' => true,
'hook_bugnote_edit' => true,
'hook_bugnote_deleted' => true,
'columns' => array(
'status',
'handler_id',
@@ -96,8 +95,7 @@
 
function bugnote_add_form($event, $bug_id)
{
if($_SERVER['PHP_SELF'] !== '/bug_update_page.php')
{
if ($_SERVER['PHP_SELF'] !== '/bug_update_page.php') {
return;
}
echo '<tr>';
@@ -112,7 +110,7 @@
 
function bug_report_update($event, $bug, $bug_id)
{
lang_push( plugin_config_get('language') );
lang_push(plugin_config_get('language'));
$this->skip = $this->skip || gpc_get_bool('slack_skip') || $bug->view_state == VS_PRIVATE;
$project = project_get_name($bug->project_id);
$url = string_get_bug_view_url_with_fqdn($bug_id);
@@ -119,34 +117,53 @@
$summary = $this->format_summary($bug);
$reporter = $this->get_user_name(auth_get_current_user_id());
$handler = $this->format_value($bug, 'handler_id');
$msg = sprintf(plugin_lang_get($event === 'EVENT_REPORT_BUG' ? 'bug_created' : 'bug_updated'),
$project, $reporter, $url, $summary, $handler
// TODO: The page anchors do not work.
$msg = sprintf(
plugin_lang_get($event === 'EVENT_REPORT_BUG' ? 'bug_created' : 'bug_updated'),
$project,
$reporter,
$url,
$summary,
$handler
);
$this->notify($msg, $this->get_webhook($project), $this->get_attachment($bug));
 
$attachments = array('color' => hexdec('ef2929'));
$t_columns = (array) plugin_config_get('columns');
foreach ($t_columns as $t_column) {
$title = column_get_title($t_column);
$value = $this->format_value($bug, $t_column);
if ($title && $value) {
$attachments['fallback'] .= $title . ': ' . $value . "\n";
$attachments['fields'][] = array(
'name' => $title,
'value' => $value,
'inline' => !column_is_extended($t_column),
);
}
}
 
$this->notify($msg, $this->get_webhook($project), $attachments);
lang_pop();
}
 
function bug_report($event, $bug, $bug_id)
{
if(plugin_config_get('hook_bug_report', false))
{
$this->bug_report_update($event, $bug, $bug_id);
}
if (plugin_config_get('hook_bug_report', false)) {
$this->bug_report_update($event, $bug, $bug_id);
}
}
 
function bug_update($event, $bug_existing, $bug_updated)
{
if(plugin_config_get('hook_bug_update', false))
{
$this->bug_report_update($event, $bug_updated, $bug_updated->id);
}
if (plugin_config_get('hook_bug_update', false)) {
$this->bug_report_update($event, $bug_updated, $bug_updated->id);
}
}
 
function bug_action($event, $action, $bug_id)
{
$this->skip = $this->skip || gpc_get_bool('slack_skip') || plugin_config_get('skip_bulk');
if($action !== 'DELETE')
{
if ($action !== 'DELETE') {
$bug = bug_get($bug_id);
$this->bug_update('EVENT_UPDATE_BUG', null, $bug);
}
@@ -154,31 +171,32 @@
 
function bug_deleted($event, $bug_id)
{
if(!plugin_config_get('hook_bug_deleted', false))
{
return;
}
if (!plugin_config_get('hook_bug_deleted', false)) {
return;
}
 
lang_push( plugin_config_get('language') );
lang_push(plugin_config_get('language'));
$bug = bug_get($bug_id);
$this->skip = $this->skip || gpc_get_bool('slack_skip') || $bug->view_state == VS_PRIVATE;
$project = project_get_name($bug->project_id);
$reporter = $this->get_user_name(auth_get_current_user_id());
$summary = $this->format_summary($bug);
// TODO: The page anchors do not work.
$msg = sprintf(plugin_lang_get('bug_deleted'), $project, $reporter, $summary);
$this->notify($msg, $this->get_webhook($project));
$attachments = array('color' => hexdec('ef2929'));
$attachments['title'] = $msg;
$this->notify(null, $this->get_webhook($project), $attachments);
lang_pop();
}
 
function bugnote_add_edit($event, $bug_id, $bugnote_id)
{
$type = ($event === 'EVENT_BUGNOTE_ADD') ? 'add' : 'edit';
if(!plugin_config_get('hook_bugnote_' . $type, false))
{
return;
}
$type = ($event === 'EVENT_BUGNOTE_ADD') ? 'add' : 'edit';
if (!plugin_config_get('hook_bugnote_' . $type, false)) {
return;
}
 
lang_push( plugin_config_get('language') );
lang_push(plugin_config_get('language'));
$bug = bug_get($bug_id);
$bugnote = bugnote_get($bugnote_id);
$this->skip = $this->skip || gpc_get_bool('slack_skip') || $bug->view_state == VS_PRIVATE || $bugnote->view_state == VS_PRIVATE;
@@ -187,30 +205,27 @@
$summary = $this->format_summary($bug);
$reporter = $this->get_user_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, $summary
// TODO: The page anchors do not work.
$msg = sprintf(
plugin_lang_get($event === 'EVENT_BUGNOTE_ADD' ? 'bugnote_created' : 'bugnote_updated'),
$project,
$reporter,
$url,
$summary
);
$this->notify($msg, $this->get_webhook($project), $this->get_text_attachment($this->bbcode_to_slack($note)));
$attachments = array('color' => hexdec("3366ff"));
$attachments['title'] = $msg . ' : ' . $this->bbcode_to_discord($note);
$this->notify(null, $this->get_webhook($project), $attachments);
lang_pop();
}
 
function get_text_attachment($text)
{
$attachment = array('color' => '#3AA3E3', 'mrkdwn_in' => array('pretext', 'text', 'fields'));
$attachment['fallback'] = "$text\n";
$attachment['text'] = $text;
 
return $attachment;
}
 
function bugnote_deleted($event, $bug_id, $bugnote_id)
{
if(!plugin_config_get('hook_bugnote_deleted', false))
{
return;
}
if (!plugin_config_get('hook_bugnote_deleted', false)) {
return;
}
 
lang_push( plugin_config_get('language') );
lang_push(plugin_config_get('language'));
$bug = bug_get($bug_id);
$bugnote = bugnote_get($bugnote_id);
$this->skip = $this->skip || gpc_get_bool('slack_skip') || $bug->view_state == VS_PRIVATE || $bugnote->view_state == VS_PRIVATE;
@@ -218,8 +233,11 @@
$url = string_get_bug_view_url_with_fqdn($bug_id);
$summary = $this->format_summary($bug);
$reporter = $this->get_user_name(auth_get_current_user_id());
// TODO: The page anchors do not work.
$msg = sprintf(plugin_lang_get('bugnote_deleted'), $project, $reporter, $url, $summary);
$this->notify($msg, $this->get_webhook($project));
$attachments = array('color' => hexdec("3366ff"));
$attachments['title'] = $msg;
$this->notify(null, $this->get_webhook($project), $attachments);
lang_pop();
}
 
@@ -232,232 +250,223 @@
 
function format_text($bug, $text)
{
$t = string_display_line_links($this->bbcode_to_slack($text));
$t = string_display_line_links($this->bbcode_to_discord($text));
 
return strip_tags(html_entity_decode($t));
}
 
function get_attachment($bug)
function format_value($bug, $field_name)
{
if($bug->status == FEEDBACK)
{
$color = '#75507b';
$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 $this->get_user_name($bug->reporter_id, true);
},
'handler_id' => function ($bug) {
return empty($bug->handler_id) ? plugin_lang_get('no_user') : $this->get_user_name($bug->handler_id, true);
},
'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);
};
}
else if($bug->status == ACKNOWLEDGED)
{
$color = '#f57900';
if (isset($values[$field_name])) {
$func = $values[$field_name];
 
return $func($bug);
} else {
return false;
}
else if($bug->status == CONFIRMED)
{
$color = '#fce94f';
}
else if($bug->status == ASSIGNED)
{
$color = '#729fcf';
}
else if($bug->status == RESOLVED)
{
$color = '#8ae234';
}
else if($bug->status == CLOSED)
{
$color = '#8ae234';
}
else
{
$color = '#ef2929';
}
$attachment = array('fallback' => '', 'color' => $color, 'mrkdwn_in' => array('pretext', 'text', 'fields'));
$t_columns = (array) plugin_config_get('columns');
foreach($t_columns as $t_column)
{
$title = column_get_title($t_column);
$value = $this->format_value($bug, $t_column);
if($title && $value)
{
$attachment['fallback'] .= $title . ': ' . $value . "\n";
$attachment['fields'][] = array(
'title' => $title,
'value' => $value,
'short' => !column_is_extended($t_column),
);
}
}
 
return $attachment;
}
 
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 $this->get_user_name($bug->reporter_id, true); },
'handler_id' => function($bug) { return empty($bug->handler_id) ? plugin_lang_get('no_user') : $this->get_user_name($bug->handler_id, true); },
'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 get_webhook($project)
{
$webhooks = plugin_config_get('url_webhooks');
 
return array_key_exists($project, $webhooks) ? $webhooks[ $project ] : plugin_config_get('url_webhook');
return array_key_exists($project, $webhooks) ? $webhooks[$project] : plugin_config_get('url_webhook');
}
 
function notify($msg, $webhook, $attachment = false)
function notify($msg, $webhook, $attachments)
{
if($this->skip)
{
if ($this->skip) {
return;
}
if(empty($webhook))
{
if (empty($webhook)) {
return;
}
$url = sprintf('%s', trim($webhook));
if(substr($url, -strlen('/slack')) != '/slack')
{
$url .= '/slack';
 
$payload['content'] = $msg;
if ($attachments != null) {
$payload['embeds'] = array($attachments);
}
 
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$payload = array(
'text' => $msg,
);
if($attachment)
{
$payload['attachments'] = array($attachment);
}
$data = array('payload' => json_encode($payload));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$result = curl_exec($ch);
if($result !== 'ok')
{
trigger_error(curl_errno($ch) . ': ' . curl_error($ch), E_USER_WARNING);
$ch = curl_init($webhook);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json; charset=utf-8']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
$result = curl_exec($ch);
if (curl_getinfo($ch, CURLINFO_HTTP_CODE) !== 204 && $result !== 'ok') {
trigger_error(curl_errno($ch) . ': ' . curl_error($ch) . ": ", E_USER_WARNING);
echo '<div class="center"><pre>' . json_encode($payload, JSON_PRETTY_PRINT) . '</pre></div>';
echo '<div class="center">' . $result . '</div>';
plugin_error('ERROR_CURL', E_USER_ERROR);
}
curl_close($ch);
}
 
function bbcode_to_slack($bbtext)
function bbcode_to_discord($bbtext)
{
$bbtags = array(
'[b]' => '*','[/b]' => '* ',
'[i]' => '_','[/i]' => '_ ',
'[u]' => '_','[/u]' => '_ ',
'[s]' => '~','[/s]' => '~ ',
'[sup]' => '','[/sup]' => '',
'[sub]' => '','[/sub]' => '',
$bbextended = array(
"/\[code(.*?)\](.*?)\[\/code\]/is" => "`$2`",
"/\[list(.*?)\](.*?)\[\/list\]/is" => "$2",
"/\[color(.*?)\](.*?)\[\/color\]/is" => "$2",
"/\[size=(.*?)\](.*?)\[\/size\]/is" => "$2",
"/\[highlight(.*?)\](.*?)\[\/highlight\]/is" => "$2",
"/\[url](.*?)\[\/url]/i" => "$1",
"/\[url=(.*?)\](.*?)\[\/url\]/i" => "$1",
"/\[email=(.*?)\](.*?)\[\/email\]/i" => "$1",
"/\[img\]([^[]*)\[\/img\]/i" => "$1",
);
foreach ($bbextended as $match => $replacement) {
$bbtext = preg_replace($match, $replacement, $bbtext);
}
$bbtags = array(
'[b]' => '*', '[/b]' => '** ',
'[i]' => '*', '[/i]' => '* ',
'[u]' => '__', '[/u]' => '__ ',
'[s]' => '~~', '[/s]' => '~~ ',
'[sup]' => '', '[/sup]' => '',
'[sub]' => '', '[/sub]' => '',
 
'[list]' => '','[/list]' => "\n",
'[*]' => '• ',
'[list]' => '', '[/list]' => "\n",
'[*]' => '• ',
 
'[hr]' => "\n———\n",
'[hr]' => "\n———\n",
 
'[left]' => '','[/left]' => '',
'[right]' => '','[/right]' => '',
'[center]' => '','[/center]' => '',
'[justify]' => '','[/justify]' => '',
);
$bbtext = str_ireplace(array_keys($bbtags), array_values($bbtags), $bbtext);
$bbextended = array(
"/\[code(.*?)\](.*?)\[\/code\]/is" => "```$2```",
"/\[color(.*?)\](.*?)\[\/color\]/is" => "$2",
"/\[size=(.*?)\](.*?)\[\/size\]/is" => "$2",
"/\[highlight(.*?)\](.*?)\[\/highlight\]/is" => "$2",
"/\[url](.*?)\[\/url]/i" => "<$1>",
"/\[url=(.*?)\](.*?)\[\/url\]/i" => "<$1|$2>",
"/\[email=(.*?)\](.*?)\[\/email\]/i" => "<mailto:$1|$2>",
"/\[img\]([^[]*)\[\/img\]/i" => "<$1>",
);
foreach($bbextended as $match => $replacement)
{
$bbtext = preg_replace($match, $replacement, $bbtext);
}
$bbtext = preg_replace_callback("/\[quote(=)?(.*?)\](.*?)\[\/quote\]/is",
function($matches)
{
if(!empty($matches[2]))
{
$result = "\n> _*" . $matches[2] . "* wrote:_\n> \n";
}
$lines = explode("\n", $matches[3]);
foreach($lines as $line)
{
$result .= "> " . $line . "\n";
}
'[left]' => '', '[/left]' => '',
'[right]' => '', '[/right]' => '',
'[center]' => '', '[/center]' => '',
'[justify]' => '', '[/justify]' => '',
);
$bbtext = str_ireplace(array_keys($bbtags), array_values($bbtags), $bbtext);
$bbtext = preg_replace_callback(
"/\[quote(=)?(.*?)\](.*?)\[\/quote\]/is",
function ($matches) {
if (!empty($matches[2])) {
$result = "\n> _*" . $matches[2] . "* wrote:_\n> \n";
}
$lines = explode("\n", $matches[3]);
foreach ($lines as $line) {
$result .= "> " . $line . "\n";
}
 
return $result;
}, $bbtext);
return $result;
},
$bbtext
);
 
return $bbtext;
}
return $bbtext;
}
 
function get_user_name($user_id, $discord = false)
{
$user = user_get_row($user_id);
$username = $user['username'];
if(!$discord || !plugin_config_get('link_names'))
{
if (!$discord || !plugin_config_get('link_names')) {
return $username;
}
$usernames = plugin_config_get('usernames');
if(array_key_exists($username, $usernames))
{
if (array_key_exists($username, $usernames)) {
return '<@' . $usernames[$username] . '>';
}
return $username;
}
 
}
}
/trunk/lang/strings_english.txt
@@ -24,20 +24,21 @@
$s_plugin_Discord_config = 'Configuration';
$s_plugin_Discord_url_webhook = 'Default Discord Webhook URL';
$s_plugin_Discord_url_webhooks = 'Additional Discord Webhook URLs';
$s_plugin_Discord_bot_name = 'Discord Bot Name';
$s_plugin_Discord_bot_icon = 'Discord Bot Icon';
//$s_plugin_Discord_bot_name = 'Discord Bot Name';
//$s_plugin_Discord_bot_icon = 'Discord Bot Icon';
$s_plugin_Discord_skip_bulk = 'Skip notification on bulk actions';
$s_plugin_Discord_link_names = 'Turn user names into Discord links (may cause excess Discord notifications)';
$s_plugin_Discord_default_channel = 'Default Discord Channel';
$s_plugin_Discord_channels = 'Discord Channels';
$s_plugin_Discord_usernames = 'Discord Usernames';
//$s_plugin_Discord_default_channel = 'Default Discord Channel';
//$s_plugin_Discord_channels = 'Discord Channels';
//$s_plugin_Discord_usernames = 'Discord Usernames';
$s_plugin_Discord_language = 'Language';
$s_plugin_Discord_columns = 'Discord Columns';
$s_plugin_Discord_bug_created = '[%s] %s created <%s|%s>. (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s updated <%s|%s>. (%s)';
$s_plugin_Discord_bug_created = '[%s] %s created __%s__ (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s updated __%s__ (%s)';
$s_plugin_Discord_bug_deleted = '[%s] %s deleted %s.';
$s_plugin_Discord_bugnote_created = "[%s] %s commented on <%s|%s> saying:";
$s_plugin_Discord_bugnote_updated = "[%s] %s edited a comment on <%s|%s> saying:";
$s_plugin_Discord_bugnote_deleted = "[%s] %s deleted a comment on <%s|%s>.";
$s_plugin_Discord_bugnote_created = "[%s] %s commented on __%s__";
$s_plugin_Discord_bugnote_updated = "[%s] %s edited a comment on __%s__";
$s_plugin_Discord_bugnote_deleted = "[%s] %s deleted a comment on __%s__";
$s_plugin_Discord_no_user = '(no one)';
$s_plugin_Discord_unknown_field = '(don\'t know how to render field "%s")';
$s_plugin_Discord_skip = 'Skip Discord notification';
/trunk/lang/strings_french.txt
@@ -26,20 +26,21 @@
$s_plugin_Discord_config = 'Configuration';
$s_plugin_Discord_url_webhook = 'URL de webhook Discord de défaut';
$s_plugin_Discord_url_webhooks = 'URLs de webhook Discord additionnels';
$s_plugin_Discord_bot_name = 'Nom du bot Discord';
$s_plugin_Discord_bot_icon = 'Icône du bot Discord';
//$s_plugin_Discord_bot_name = 'Nom du bot Discord';
//$s_plugin_Discord_bot_icon = 'Icône du bot Discord';
$s_plugin_Discord_skip_bulk = 'Ne pas envoyer de notification pour les actions en bloc';
$s_plugin_Discord_link_names = 'Convertir les noms d\'utilisateurs en liens Discord (peut causer des notifications excessives dans Discord)';
$s_plugin_Discord_default_channel = 'Channel Discord de défault';
$s_plugin_Discord_channels = 'Correspondances des channels';
$s_plugin_Discord_usernames = 'Correspondances des noms d\'utilisateurs';
//$s_plugin_Discord_default_channel = 'Channel Discord de défault';
//$s_plugin_Discord_channels = 'Correspondances des channels';
//$s_plugin_Discord_usernames = 'Correspondances des noms d\'utilisateurs';
$s_plugin_Discord_language = 'Langue';
$s_plugin_Discord_columns = 'Champs de bogues';
$s_plugin_Discord_bug_created = '[%s] %s a crée <%s|%s>. (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s a modifié <%s|%s>. (%s)';
$s_plugin_Discord_bug_created = '[%s] %s a crée __%s__ (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s a modifié __%s__ (%s)';
$s_plugin_Discord_bug_deleted = '[%s] %s a effacé %s.';
$s_plugin_Discord_bugnote_created = "[%s] %s a commenté sur <%s|%s> pour dire:";
$s_plugin_Discord_bugnote_updated = "[%s] %s a modifié un commentaire sur <%s|%s> pour dire:";
$s_plugin_Discord_bugnote_deleted = "[%s] %s a effacé un commentaire sur <%s|%s>.";
$s_plugin_Discord_bugnote_created = "[%s] %s a commenté sur <%s>.";
$s_plugin_Discord_bugnote_updated = "[%s] %s a modifié un commentaire sur __%s__";
$s_plugin_Discord_bugnote_deleted = "[%s] %s a effacé un commentaire sur __%s__";
$s_plugin_Discord_no_user = '(personne)';
$s_plugin_Discord_unknown_field = '(incapable de visualiser le champ "%s")';
$s_plugin_Discord_skip = 'Ne pas envoyer de notification sur Discord';
/trunk/lang/strings_german.txt
@@ -26,17 +26,18 @@
$s_plugin_Discord_config = 'Konfiguration';
$s_plugin_Discord_url_webhook = 'Default Discord Webhook URL';
$s_plugin_Discord_url_webhooks = 'Additional Discord Webhook URLs';
$s_plugin_Discord_bot_name = 'Discord Bot Name';
$s_plugin_Discord_bot_icon = 'Discord Bot Icon';
$s_plugin_Discord_default_channel = 'Standard Discord Channel';
$s_plugin_Discord_channels = 'Discord Channels';
//$s_plugin_Discord_bot_name = 'Discord Bot Name';
//$s_plugin_Discord_bot_icon = 'Discord Bot Icon';
//$s_plugin_Discord_default_channel = 'Standard Discord Channel';
//$s_plugin_Discord_channels = 'Discord Channels';
$s_plugin_Discord_language = 'Sprache';
$s_plugin_Discord_columns = 'Discord Spalten';
$s_plugin_Discord_bug_created = '[%s] %s erstellte <%s|%s>. (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s aktualisierte <%s|%s>. (%s)';
$s_plugin_Discord_bug_created = '[%s] %s erstellte __%s__ (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s aktualisierte __%s__ (%s)';
$s_plugin_Discord_bug_deleted = '[%s] %s löschte %s.';
$s_plugin_Discord_bugnote_created = "[%s] %s kommentierte den Eintrag <%s|%s>:";
$s_plugin_Discord_bugnote_updated = "[%s] %s bearbeitete einen Kommentar im Eintrag <%s|%s>:";
$s_plugin_Discord_bugnote_deleted = "[%s] %s löschte einen Kommentar im Eintrag <%s|%s>.";
$s_plugin_Discord_bugnote_created = "[%s] %s kommentierte den Eintrag __%s__";
$s_plugin_Discord_bugnote_updated = "[%s] %s bearbeitete einen Kommentar im Eintrag __%s__";
$s_plugin_Discord_bugnote_deleted = "[%s] %s löschte einen Kommentar im Eintrag __%s__";
$s_plugin_Discord_no_user = '(niemand)';
$s_plugin_Discord_unknown_field = '(Es liegt keine Information vor, wie das Feld "%s" ausgegeben werden kann.)';
 
/trunk/lang/strings_russian.txt
@@ -25,20 +25,21 @@
$s_plugin_Discord_config = 'Настройка';
$s_plugin_Discord_url_webhook = 'Discord Webhook URL по умолчанию';
$s_plugin_Discord_url_webhooks = 'Доплнительные Discord Webhook URLы';
$s_plugin_Discord_bot_name = 'Имя Discord-бота';
$s_plugin_Discord_bot_icon = 'Иконка Discord-бота';
//$s_plugin_Discord_bot_name = 'Имя Discord-бота';
//$s_plugin_Discord_bot_icon = 'Иконка Discord-бота';
$s_plugin_Discord_skip_bulk = 'Пропускать оповещения о групповых действиях';
$s_plugin_Discord_link_names = 'Делать имена пользователей ссылками (это может привести к большому количеству оповещений Discord)';
$s_plugin_Discord_default_channel = 'Каналы Discord по умолчанию';
$s_plugin_Discord_channels = 'Каналы Discord';
$s_plugin_Discord_usernames = 'Пользователи Discord';
//$s_plugin_Discord_default_channel = 'Каналы Discord по умолчанию';
//$s_plugin_Discord_channels = 'Каналы Discord';
//$s_plugin_Discord_usernames = 'Пользователи Discord';
$s_plugin_Discord_language = 'язык';
$s_plugin_Discord_columns = 'Колонки Discord';
$s_plugin_Discord_bug_created = '[%s] %s создал <%s|%s>. (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s изменил <%s|%s>. (%s)';
$s_plugin_Discord_bug_created = '[%s] %s создал __%s__ (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s изменил __%s__ (%s)';
$s_plugin_Discord_bug_deleted = '[%s] %s удалил %s.';
$s_plugin_Discord_bugnote_created = "[%s] %s прокомментировал <%s|%s>:";
$s_plugin_Discord_bugnote_updated = "[%s] %s изменил комментарий к <%s|%s>:";
$s_plugin_Discord_bugnote_deleted = "[%s] %s удалил комментарий к <%s|%s>.";
$s_plugin_Discord_bugnote_created = "[%s] %s прокомментировал __%s__";
$s_plugin_Discord_bugnote_updated = "[%s] %s изменил комментарий к __%s__";
$s_plugin_Discord_bugnote_deleted = "[%s] %s удалил комментарий к __%s__";
$s_plugin_Discord_no_user = '(никто)';
$s_plugin_Discord_unknown_field = '(не знаю, как выводить поле "%s")';
$s_plugin_Discord_skip = 'Пропустить оповещение в Discord';
File deleted
/trunk/pages/config_page.php
/trunk/pages/config.php
@@ -1,8 +1,8 @@
<?php
 
/**
* Discord Integration
* Copyright (C) Robin van Nunen (robin@vnunen.nl) for Discord modification
* Copyright (C) Karim Ratib (karim@meedan.com) for original source
* Copyright (C) 2014 Karim Ratib (karim.ratib@gmail.com)
*
* Discord Integration is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License 2
@@ -19,41 +19,162 @@
* or see http://www.gnu.org/licenses/.
*/
 
form_security_validate('plugin_Discord_config');
auth_reauthenticate();
access_ensure_global_level(config_get('manage_plugin_threshold'));
/**
* Sets plugin config option if value is different from current/default
*
* @param string $p_name option name
* @param string $p_value value to set
*
* @return void
*/
function config_set_if_needed($p_name, $p_value)
{
if($p_value != plugin_config_get($p_name))
{
plugin_config_set($p_name, $p_value);
}
}
 
$t_redirect_url = plugin_page('config_page', true);
layout_page_header(null, $t_redirect_url);
layout_page_begin();
html_page_top(plugin_lang_get('title'));
 
config_set_if_needed('url_webhook', gpc_get_string('url_webhook'));
config_set_if_needed('skip_bulk', gpc_get_bool('skip_bulk'));
config_set_if_needed('link_names', gpc_get_bool('link_names'));
config_set_if_needed('language', gpc_get_string('language'));
print_manage_menu();
 
config_set_if_needed('hook_bug_report', gpc_get_bool('hook_bug_report'));
config_set_if_needed('hook_bug_update', gpc_get_bool('hook_bug_update'));
config_set_if_needed('hook_bug_deleted', gpc_get_bool('hook_bug_deleted'));
config_set_if_needed('hook_bugnote_add', gpc_get_bool('hook_bugnote_add'));
config_set_if_needed('hook_bugnote_edit', gpc_get_bool('hook_bugnote_edit'));
config_set_if_needed('hook_bugnote_deleted', gpc_get_bool('hook_bugnote_deleted'));
?>
 
form_security_purge('plugin_Discord_config');
<br />
 
html_operation_successful($t_redirect_url);
layout_page_end();
<form action="<?php echo plugin_page('config_edit') ?>" method="post">
<?php echo form_security_field('plugin_Discord_config_edit') ?>
<table class="width75" cellspacing="1">
 
<tr>
<td class="form-title" colspan="3">
<?php echo plugin_lang_get('title') . ' : ' . plugin_lang_get('config') ?>
</td>
</tr>
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('url_webhook') ?>
</td>
<td colspan="2">
<input size="80" type="text" name="url_webhook" value="<?php echo plugin_config_get('url_webhook') ?>" />
</td>
</tr>
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('url_webhooks') ?>
</td>
<td colspan="2">
<p>
Specifies the mapping between Mantis project names and Discord webhooks.
</p>
<p>
Option name is <strong>plugin_Discord_url_webhooks</strong> and is an array of 'Mantis project name' => 'Discord webhook'.
Array options must be set using the <a href="adm_config_report.php">Configuration Report</a> screen.
The current value of this option is:
<pre><?php var_export(plugin_config_get('url_webhooks')) ?></pre>
</p>
</td>
</tr>
 
<!--
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('bot_name') ?>
</td>
<td colspan="2">
<input type="text" name="bot_name" value="<?php echo plugin_config_get('bot_name') ?>" />
</td>
</tr>
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('bot_icon') ?>
</td>
<td colspan="2">
<p>
Can be either a URL pointing to small image or an emoji of the form :emoji:</br>
Defaults to the Mantis logo.
</p>
<input type="text" name="bot_icon" value="<?php echo plugin_config_get('bot_icon') ?>" />
</td>
</tr>
-->
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('skip_bulk') ?>
</td>
<td colspan="2">
<input type="checkbox" name="skip_bulk" <?php if (plugin_config_get('skip_bulk')) echo "checked"; ?> />
</td>
</tr>
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('link_names') ?>
</td>
<td colspan="2">
<input type="checkbox" name="link_names" <?php if (plugin_config_get('link_names')) echo "checked"; ?> />
</td>
</tr>
 
<!--
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('default_channel') ?>
</td>
<td colspan="2">
<input type="text" name="default_channel" value="<?php echo plugin_config_get('default_channel') ?>" />
</td>
</tr>
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('channels') ?>
</td>
<td colspan="2">
<p>
Specifies the mapping between Mantis project names and Discord #channels.
</p>
<p>
Option name is <strong>plugin_Discord_channels</strong> and is an array of 'Mantis project name' => 'Discord channel name'.
Array options must be set using the <a href="adm_config_report.php">Configuration Report</a> screen.
The current value of this option is:<pre><?php var_export(plugin_config_get('channels')) ?></pre>
</p>
</td>
</tr>
-->
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('columns') ?>
</td>
<td colspan="2">
<p>
Specifies the bug fields that should be attached to the Discord notifications.
</p>
<p>
Option name is <strong>plugin_Discord_columns</strong> and is an array of bug column names.
Array options must be set using the <a href="adm_config_report.php">Configuration Report</a> screen.
<?php
$t_columns = columns_get_all($t_project_id);
$t_all = implode(', ', $t_columns);
?>
Available column names are:<div><textarea name="all_columns" readonly="readonly" cols="80" rows="5"><?php echo $t_all ?></textarea></div>
The current value of this option is:
<pre><?php var_export(plugin_config_get('columns')) ?></pre>
</p>
</td>
</tr>
 
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo plugin_lang_get('language') ?>
</td>
<td colspan="2">
<input type="text" name="language" value="<?php echo plugin_config_get('language') ?>" />
</td>
</tr>
 
<tr>
<td class="center" colspan="3">
<input type="submit" class="button" value="<?php echo lang_get('change_configuration') ?>" />
</td>
</tr>
 
</table>
</form>
 
<?php
html_page_bottom();
/trunk/pages/config_edit.php
@@ -0,0 +1,64 @@
<?php
/**
* Discord Integration
* Copyright (C) 2014 Karim Ratib (karim.ratib@gmail.com)
*
* Discord Integration is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License 2
* as published by the Free Software Foundation.
*
* Discord Integration 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Discord Integration; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
* or see http://www.gnu.org/licenses/.
*/
 
form_security_validate( 'plugin_Discord_config_edit' );
 
auth_reauthenticate( );
access_ensure_global_level( config_get( 'manage_plugin_threshold' ) );
 
$f_url_webhook = gpc_get_string( 'url_webhook' );
#$f_bot_name = gpc_get_string( 'bot_name' );
#$f_bot_icon = gpc_get_string( 'bot_icon' );
$f_skip_bulk = gpc_get_bool( 'skip_bulk' );
$f_link_names = gpc_get_bool( 'link_names' );
#$f_default_channel = gpc_get_string( 'default_channel' );
$f_language = gpc_get_string( 'language' );
 
if( plugin_config_get( 'url_webhook' ) != $f_url_webhook ) {
plugin_config_set( 'url_webhook', $f_url_webhook );
}
 
#if( plugin_config_get( 'bot_name' ) != $f_bot_name ) {
# plugin_config_set( 'bot_name', $f_bot_name );
#}
 
#if( plugin_config_get( 'bot_icon' ) != $f_bot_icon ) {
# plugin_config_set( 'bot_icon', $f_bot_icon );
#}
 
if( plugin_config_get( 'skip_bulk' ) != $f_skip_bulk ) {
plugin_config_set( 'skip_bulk', $f_skip_bulk );
}
 
if( plugin_config_get( 'link_names' ) != $f_link_names ) {
plugin_config_set( 'link_names', $f_link_names );
}
 
#if( plugin_config_get( 'default_channel' ) != $f_default_channel ) {
# plugin_config_set( 'default_channel', $f_default_channel );
#}
 
if( plugin_config_get( 'language' ) != $f_language ) {
plugin_config_set( 'language', $f_language );
}
 
form_security_purge( 'plugin_Discord_config_edit' );
 
print_successful_redirect( plugin_page( 'config', true ) );