MantisBT-Discord

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ HEAD  →  ?path2? @ 1
/trunk/.git/logs/HEAD
@@ -1 +1 @@
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584814853 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584818357 +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> 1584814853 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584818357 +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> 1584814853 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
0000000000000000000000000000000000000000 f56aebcdc20adb95c26f96e346c82fee7faa85be root <root@mail.grimore.org> 1584818357 +0000 clone: from https://github.com/TechGuard/MantisBT-Discord.git
/trunk/Discord.php
@@ -1,5 +1,4 @@
<?php
 
/**
* Discord Integration
* Copyright (C) Robin van Nunen (robin@vnunen.nl) for Discord modification
@@ -28,24 +27,26 @@
{
$this->name = plugin_lang_get('title');
$this->description = plugin_lang_get('description');
$this->page = 'config';
$this->page = 'config_page';
$this->version = '1.0';
$this->requires = array(
'MantisCore' => '1.3.0',
'MantisCore' => '2.0.0',
);
$this->author = 'Robin van Nunen & Wizardry and Steamworks';
$this->contact = 'robin@vnunen.nl / office@grimore.org';
$this->author = 'Robin van Nunen';
$this->contact = 'robin@vnunen.nl';
$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;
@@ -63,12 +64,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',
@@ -95,7 +96,8 @@
 
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>';
@@ -110,7 +112,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);
@@ -117,53 +119,34 @@
$summary = $this->format_summary($bug);
$reporter = $this->get_user_name(auth_get_current_user_id());
$handler = $this->format_value($bug, 'handler_id');
// 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
$msg = sprintf(plugin_lang_get($event === 'EVENT_REPORT_BUG' ? 'bug_created' : 'bug_updated'),
$project, $reporter, $url, $summary, $handler
);
 
$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);
$this->notify($msg, $this->get_webhook($project), $this->get_attachment($bug));
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);
}
@@ -171,32 +154,31 @@
 
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);
$attachments = array('color' => hexdec('ef2929'));
$attachments['title'] = $msg;
$this->notify(null, $this->get_webhook($project), $attachments);
$this->notify($msg, $this->get_webhook($project));
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;
@@ -205,27 +187,30 @@
$summary = $this->format_summary($bug);
$reporter = $this->get_user_name(auth_get_current_user_id());
$note = bugnote_get_text($bugnote_id);
// TODO: The page anchors do not work.
$msg = sprintf(
plugin_lang_get($event === 'EVENT_BUGNOTE_ADD' ? 'bugnote_created' : 'bugnote_updated'),
$project,
$reporter,
$url,
$summary
$msg = sprintf(plugin_lang_get($event === 'EVENT_BUGNOTE_ADD' ? 'bugnote_created' : 'bugnote_updated'),
$project, $reporter, $url, $summary
);
$attachments = array('color' => hexdec("3366ff"));
$attachments['title'] = $msg . ' : ' . $this->bbcode_to_discord($note);
$this->notify(null, $this->get_webhook($project), $attachments);
$this->notify($msg, $this->get_webhook($project), $this->get_text_attachment($this->bbcode_to_slack($note)));
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;
@@ -233,11 +218,8 @@
$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);
$attachments = array('color' => hexdec("3366ff"));
$attachments['title'] = $msg;
$this->notify(null, $this->get_webhook($project), $attachments);
$this->notify($msg, $this->get_webhook($project));
lang_pop();
}
 
@@ -250,223 +232,232 @@
 
function format_text($bug, $text)
{
$t = string_display_line_links($this->bbcode_to_discord($text));
$t = string_display_line_links($this->bbcode_to_slack($text));
 
return strip_tags(html_entity_decode($t));
}
 
function format_value($bug, $field_name)
function get_attachment($bug)
{
$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($bug->status == FEEDBACK)
{
$color = '#75507b';
}
if (isset($values[$field_name])) {
$func = $values[$field_name];
else if($bug->status == ACKNOWLEDGED)
{
$color = '#f57900';
}
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 $func($bug);
} else {
return false;
}
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, $attachments)
function notify($msg, $webhook, $attachment = false)
{
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);
}
 
$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>';
$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);
plugin_error('ERROR_CURL', E_USER_ERROR);
}
curl_close($ch);
}
 
function bbcode_to_discord($bbtext)
function bbcode_to_slack($bbtext)
{
$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]' => '',
$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);
$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);
$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";
}
 
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,21 +24,20 @@
$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_language = 'Language';
$s_plugin_Discord_default_channel = 'Default Discord Channel';
$s_plugin_Discord_channels = 'Discord Channels';
$s_plugin_Discord_usernames = 'Discord Usernames';
$s_plugin_Discord_columns = 'Discord Columns';
$s_plugin_Discord_bug_created = '[%s] %s created __%s__ (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s updated __%s__ (%s)';
$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_deleted = '[%s] %s deleted %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_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_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,21 +26,20 @@
$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_language = 'Langue';
$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_columns = 'Champs de bogues';
$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_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_deleted = '[%s] %s a effacé %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_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_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,18 +26,17 @@
$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_language = 'Sprache';
$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_columns = 'Discord Spalten';
$s_plugin_Discord_bug_created = '[%s] %s erstellte __%s__ (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s aktualisierte __%s__ (%s)';
$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_deleted = '[%s] %s löschte %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_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_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,21 +25,20 @@
$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_language = 'язык';
$s_plugin_Discord_default_channel = 'Каналы Discord по умолчанию';
$s_plugin_Discord_channels = 'Каналы Discord';
$s_plugin_Discord_usernames = 'Пользователи Discord';
$s_plugin_Discord_columns = 'Колонки Discord';
$s_plugin_Discord_bug_created = '[%s] %s создал __%s__ (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s изменил __%s__ (%s)';
$s_plugin_Discord_bug_created = '[%s] %s создал <%s|%s>. (%s)';
$s_plugin_Discord_bug_updated = '[%s] %s изменил <%s|%s>. (%s)';
$s_plugin_Discord_bug_deleted = '[%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_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_no_user = '(никто)';
$s_plugin_Discord_unknown_field = '(не знаю, как выводить поле "%s")';
$s_plugin_Discord_skip = 'Пропустить оповещение в Discord';
File deleted
/trunk/pages/config_edit.php
/trunk/pages/config.php
@@ -1,8 +1,8 @@
<?php
 
/**
* Discord Integration
* Copyright (C) 2014 Karim Ratib (karim.ratib@gmail.com)
* Copyright (C) Robin van Nunen (robin@vnunen.nl) for Discord modification
* Copyright (C) Karim Ratib (karim@meedan.com) for original source
*
* Discord Integration is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License 2
@@ -19,162 +19,41 @@
* or see http://www.gnu.org/licenses/.
*/
 
auth_reauthenticate();
form_security_validate('plugin_Discord_config');
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);
}
}
 
html_page_top(plugin_lang_get('title'));
$t_redirect_url = plugin_page('config_page', true);
layout_page_header(null, $t_redirect_url);
layout_page_begin();
 
print_manage_menu();
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'));
 
?>
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'));
 
<br />
form_security_purge('plugin_Discord_config');
 
<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();
html_operation_successful($t_redirect_url);
layout_page_end();
/trunk/pages/config_page.php
@@ -0,0 +1,184 @@
<?php
/**
* Discord Integration
* Copyright (C) Robin van Nunen (robin@vnunen.nl) for Discord modification
* Copyright (C) Karim Ratib (karim@meedan.com) for original source
*
* 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/.
*/
 
access_ensure_global_level( config_get( 'manage_plugin_threshold' ) );
 
layout_page_header( plugin_lang_get( 'title' ) );
 
layout_page_begin( 'manage_overview_page.php' );
 
print_manage_menu( 'manage_plugin_page.php' );
 
?>
 
<div class="col-md-12 col-xs-12">
<div class="space-10"></div>
<div class="form-container">
<form action="<?php echo plugin_page( 'config' ) ?>" method="post">
<fieldset>
<div class="widget-box widget-color-blue2">
<div class="widget-header widget-header-small">
<h4 class="widget-title lighter">
<i class="ace-icon fa fa-exchange"></i>
<?php echo plugin_lang_get( 'title' ) ?>
</h4>
</div>
 
<?php echo form_security_field( 'plugin_Discord_config' ) ?>
<div class="widget-body">
<div class="widget-main no-padding">
<div class="table-responsive">
<table class="table table-bordered table-condensed table-striped">
 
<tr>
<td class="category">
<?php echo plugin_lang_get( 'url_webhook' ) ?>
</td>
<td>
<input size="80" type="text" name="url_webhook" value="<?php echo plugin_config_get( 'url_webhook' )?>" />
</td>
</tr>
 
<tr>
<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>
<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>
<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>
<td class="category">
<?php echo lang_get( 'language' ) ?>
</td>
<td>
<select id="language" name="language" class="input-sm">
<?php print_language_option_list( plugin_config_get('language') ) ?>
</select>
</td>
</tr>
 
<tr>
<td class="category">
<?php echo plugin_lang_get( 'actions' ) ?>
</td>
<td>
<table>
<thead>
<tr>
<th style="width: 64px; text-align: center;"><?=plugin_lang_get('enabled')?></th>
<th><?=plugin_lang_get('action')?></th>
</tr>
</thead>
<tbody>
<?php
foreach(['hook_bug_report', 'hook_bug_update', 'hook_bug_deleted', 'hook_bugnote_add', 'hook_bugnote_edit', 'hook_bugnote_deleted'] as $name)
{
echo '
<tr>
<td style="text-align: center;"><input type="checkbox" id="' . $name . '" name="' . $name . '" ' . (plugin_config_get($name) ? 'checked' : '') . '/></td>
<td><label for="' . $name . '">' . plugin_lang_get($name) . '</label></td>
</tr>';
}
?>
</tbody>
</table>
</td>
</tr>
 
<tr>
<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 echo preg_replace('/[0-9]+ => /', '', var_export(plugin_config_get( 'columns' ), true)) ?></pre>
</p>
</td>
</tr>
 
<tr>
<td class="category">
<?php echo plugin_lang_get( 'usernames' )?>
</td>
<td colspan="2">
<p>
Specifies the mapping between Mantis and Discord user names.
</p>
<p>
Option name is <strong>plugin_Discord_usernames</strong> and is an array of 'Mantis user name' => 'Discord user 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( 'usernames' ))?></pre>
</p>
</td>
</tr>
 
</table>
</div>
</div>
<div class="widget-toolbox padding-8 clearfix">
<input type="submit" class="btn btn-primary btn-white btn-round" value="<?php echo plugin_lang_get( 'action_update' ) ?>" />
</div>
</div>
</div>
</fieldset>
</form>
</div>
</div>
 
<?php
layout_page_end();