2022-06-24 12:04:49 +03:00
|
|
|
<?php
|
|
|
|
|
2022-07-01 16:10:30 +03:00
|
|
|
class BugzillaBridge extends BridgeAbstract
|
|
|
|
{
|
|
|
|
const NAME = 'Bugzilla Bridge';
|
|
|
|
const URI = 'https://www.bugzilla.org/';
|
|
|
|
const DESCRIPTION = 'Bridge for any Bugzilla instance';
|
|
|
|
const MAINTAINER = 'Yaman Qalieh';
|
|
|
|
const PARAMETERS = [
|
|
|
|
'global' => [
|
|
|
|
'instance' => [
|
|
|
|
'name' => 'Instance URL',
|
|
|
|
'required' => true,
|
|
|
|
'exampleValue' => 'https://bugzilla.mozilla.org'
|
|
|
|
]
|
|
|
|
],
|
|
|
|
'Bug comments' => [
|
|
|
|
'id' => [
|
|
|
|
'name' => 'Bug tracking ID',
|
|
|
|
'type' => 'number',
|
|
|
|
'required' => true,
|
|
|
|
'title' => 'Insert bug tracking ID',
|
|
|
|
'exampleValue' => 121241
|
|
|
|
],
|
|
|
|
'limit' => [
|
|
|
|
'name' => 'Number of comments to return',
|
|
|
|
'type' => 'number',
|
|
|
|
'required' => false,
|
|
|
|
'title' => 'Specify number of comments to return',
|
|
|
|
'defaultValue' => -1
|
|
|
|
],
|
|
|
|
'skiptags' => [
|
|
|
|
'name' => 'Skip offtopic comments',
|
|
|
|
'type' => 'checkbox',
|
|
|
|
'title' => 'Excludes comments tagged as advocacy, metoo, or offtopic from the feed'
|
|
|
|
]
|
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
const SKIPPED_ACTIVITY = [
|
|
|
|
'cc' => true,
|
|
|
|
'comment_tag' => true
|
|
|
|
];
|
|
|
|
|
|
|
|
const SKIPPED_TAGS = ['advocacy', 'metoo', 'offtopic'];
|
|
|
|
|
|
|
|
private $instance;
|
|
|
|
private $bugid;
|
|
|
|
private $buguri;
|
|
|
|
private $title;
|
|
|
|
|
|
|
|
public function getName()
|
|
|
|
{
|
|
|
|
if (!is_null($this->title)) {
|
|
|
|
return $this->title;
|
|
|
|
}
|
|
|
|
return parent::getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getURI()
|
|
|
|
{
|
|
|
|
return $this->buguri ?? parent::getURI();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function collectData()
|
|
|
|
{
|
|
|
|
$this->instance = rtrim($this->getInput('instance'), '/');
|
|
|
|
$this->bugid = $this->getInput('id');
|
|
|
|
$this->buguri = $this->instance . '/show_bug.cgi?id=' . $this->bugid;
|
|
|
|
|
|
|
|
$url = $this->instance . '/rest/bug/' . $this->bugid;
|
|
|
|
$this->getTitle($url);
|
|
|
|
$this->collectComments($url . '/comment');
|
|
|
|
$this->collectUpdates($url . '/history');
|
|
|
|
|
|
|
|
usort($this->items, function ($a, $b) {
|
|
|
|
return $b['timestamp'] <=> $a['timestamp'];
|
|
|
|
});
|
|
|
|
|
|
|
|
if ($this->getInput('limit') > 0) {
|
|
|
|
$this->items = array_slice($this->items, 0, $this->getInput('limit'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getTitle($url)
|
|
|
|
{
|
|
|
|
// Only request the summary for a faster request
|
2023-04-27 20:24:29 +03:00
|
|
|
$json = self::getJSON($url . '?include_fields=summary');
|
2022-07-01 16:10:30 +03:00
|
|
|
$this->title = 'Bug ' . $this->bugid . ' - ' .
|
|
|
|
$json['bugs'][0]['summary'] . ' - ' .
|
|
|
|
// Remove https://
|
|
|
|
substr($this->instance, 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function collectComments($url)
|
|
|
|
{
|
2023-04-27 20:24:29 +03:00
|
|
|
$json = self::getJSON($url);
|
2022-07-01 16:10:30 +03:00
|
|
|
|
|
|
|
// Array of comments is here
|
|
|
|
if (!isset($json['bugs'][$this->bugid]['comments'])) {
|
|
|
|
returnClientError('Cannot find REST endpoint');
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($json['bugs'][$this->bugid]['comments'] as $comment) {
|
|
|
|
$item = [];
|
|
|
|
if (
|
|
|
|
$this->getInput('skiptags') and
|
|
|
|
array_intersect(self::SKIPPED_TAGS, $comment['tags'])
|
|
|
|
) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$item['categories'] = $comment['tags'];
|
|
|
|
$item['uri'] = $this->buguri . '#c' . $comment['count'];
|
|
|
|
$item['title'] = 'Comment ' . $comment['count'];
|
|
|
|
$item['timestamp'] = $comment['creation_time'];
|
|
|
|
$item['author'] = $this->getUser($comment['creator']);
|
|
|
|
$item['content'] = $comment['text'];
|
|
|
|
if (isset($comment['is_markdown']) and $comment['is_markdown']) {
|
|
|
|
$item['content'] = markdownToHtml($item['content']);
|
|
|
|
}
|
|
|
|
if (!is_null($comment['attachment_id'])) {
|
|
|
|
$item['enclosures'] = [$this->instance . '/attachment.cgi?id=' . $comment['attachment_id']];
|
|
|
|
}
|
|
|
|
$this->items[] = $item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function collectUpdates($url)
|
|
|
|
{
|
2023-04-27 20:24:29 +03:00
|
|
|
$json = self::getJSON($url);
|
2022-07-01 16:10:30 +03:00
|
|
|
|
|
|
|
// Array of changesets which contain an array of changes
|
|
|
|
if (!isset($json['bugs']['0']['history'])) {
|
|
|
|
returnClientError('Cannot find REST endpoint');
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($json['bugs']['0']['history'] as $changeset) {
|
|
|
|
$author = $this->getUser($changeset['who']);
|
|
|
|
$timestamp = $changeset['when'];
|
|
|
|
foreach ($changeset['changes'] as $change) {
|
|
|
|
// Skip updates to the cc list and comment tagging
|
|
|
|
if (isset(self::SKIPPED_ACTIVITY[$change['field_name']])) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$item = [];
|
|
|
|
$item['uri'] = $this->buguri;
|
|
|
|
$item['title'] = 'Updated';
|
|
|
|
$item['timestamp'] = $timestamp;
|
|
|
|
$item['author'] = $author;
|
|
|
|
$item['content'] = ucfirst($change['field_name']) . ': ' .
|
|
|
|
($change['removed'] === '' ? '[nothing]' : $change['removed']) . ' -> ' .
|
|
|
|
($change['added'] === '' ? '[nothing]' : $change['added']);
|
|
|
|
$this->items[] = $item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getUser($user)
|
|
|
|
{
|
|
|
|
// Check if the user endpoint is available
|
2023-04-19 18:53:35 +03:00
|
|
|
if ($this->loadCacheValue($this->instance . 'userEndpointClosed', 86400)) {
|
2022-07-01 16:10:30 +03:00
|
|
|
return $user;
|
|
|
|
}
|
|
|
|
|
|
|
|
$cache = $this->loadCacheValue($this->instance . $user);
|
|
|
|
if (!is_null($cache)) {
|
|
|
|
return $cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
$url = $this->instance . '/rest/user/' . $user . '?include_fields=real_name';
|
|
|
|
try {
|
2023-04-27 20:24:29 +03:00
|
|
|
$json = self::getJSON($url);
|
2022-07-01 16:10:30 +03:00
|
|
|
if (isset($json['error']) and $json['error']) {
|
|
|
|
throw new Exception();
|
|
|
|
}
|
|
|
|
} catch (Exception $e) {
|
|
|
|
$this->saveCacheValue($this->instance . 'userEndpointClosed', true);
|
|
|
|
return $user;
|
|
|
|
}
|
|
|
|
|
|
|
|
$username = $json['users']['0']['real_name'];
|
|
|
|
|
|
|
|
if (empty($username)) {
|
|
|
|
$username = $user;
|
|
|
|
}
|
|
|
|
$this->saveCacheValue($this->instance . $user, $username);
|
|
|
|
return $username;
|
|
|
|
}
|
2023-04-27 20:24:29 +03:00
|
|
|
|
|
|
|
protected static function getJSON($url)
|
|
|
|
{
|
|
|
|
$headers = [
|
|
|
|
'Accept: application/json',
|
|
|
|
];
|
|
|
|
return json_decode(getContents($url, $headers), true);
|
|
|
|
}
|
2022-06-24 12:04:49 +03:00
|
|
|
}
|