| <?php |
| /******************************************************************************* |
| * Copyright (c) 2013, 2014 Eclipse Foundation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Wayne Beaton (Eclipse Foundation)- initial API and implementation |
| *******************************************************************************/ |
| |
| class BugzillaClient { |
| var $host; |
| var $cookieFile; |
| var $loggedIn = false; |
| |
| /** |
| * This is the pattern that we look for to verify that the |
| * attempt to login as succeeded. Since we're parsing web pages, |
| * we look for an occurance of "Log out" (assuming that we can |
| * only log out if we have previously logged in). |
| * |
| * @var string |
| */ |
| var $loggedInPattern = '/<a href="index.cgi\?logout=1">Log( | )out<\/a>/'; |
| var $bugCreatedPattern = '/Bug (\d+)+ Submitted/'; |
| var $attachmentCreatedPattern = '/Attachment (\d+) added to Bug (\d+)/'; |
| |
| function __construct($host) { |
| $this->host = $host; |
| $this->cookieFile = tempnam(null, 'bugzilla'); |
| } |
| |
| function isLoggedIn() { |
| return $this->loggedIn; |
| } |
| |
| function login($user, $password) { |
| if ($this->isLoggedIn()) return; |
| |
| $query = new BugzillaPostQuery($this, "index.cgi"); |
| $result = $query |
| ->setData('Bugzilla_login', $user) |
| ->setData('Bugzilla_password', $password) |
| ->setData('GoAheadAndLogIn', '1') |
| ->execute(); |
| |
| /* |
| * If the value that we get back from the server contains the |
| * "loggedInPattern", then we were successful. Otherwise, obviously, |
| * we were not successful. In this event, extract the error message |
| * from the title and pass it back as the message in an exception. |
| */ |
| if(!preg_match($this->loggedInPattern, $result->contents)) { |
| if (preg_match('/<title>(.*)<\/title>/', $result->contents, $matches)) { |
| $message = $matches[1]; |
| } else $message = 'Unknown error'; |
| throw new BugzillaInvalidCredentialsException($message); |
| } |
| |
| $this->loggedIn = true; |
| |
| return $this; |
| } |
| |
| function logout() { |
| // TODO Should we throw an exception? |
| if (!$this->isLoggedIn()) return; |
| |
| $query = new BugzillaPostQuery($this, "index.cgi"); |
| $query |
| ->setData('logout', '1') |
| ->execute(); |
| |
| $this->loggedIn = false; |
| } |
| |
| function startBug($product, $component, $summary) { |
| return new BugBuilder($this, $product, $component, $summary); |
| } |
| } |
| |
| class BugzillaInvalidCredentialsException extends Exception {} |
| |
| class BugBuilder { |
| var $client; |
| var $product; |
| var $component; |
| var $summary; |
| var $body = array(); |
| var $cc = array(); |
| |
| function __construct($client, $product, $component, $summary) { |
| $this->client = $client; |
| $this->product = $product; |
| $this->component = $component; |
| $this->summary = $summary; |
| } |
| |
| function addParagraph($paragraph) { |
| $this->body[] = $paragraph; |
| return $this; |
| } |
| |
| function addCC($email) { |
| $this->cc[] = $email; |
| return $this; |
| } |
| |
| function create() { |
| // Recent versions of Bugzilla require a token when creating |
| // a bug. Attempt to get the token. |
| // FIXME Only do this if the Bugzilla version requires it. |
| $query = new BugzillaGetQuery($this->client, 'enter_bug.cgi'); |
| $queryFormResult = $query->execute(); |
| |
| $query = new BugzillaPostQuery($this->client, 'post_bug.cgi'); |
| $result = $query |
| ->setData('form_name', 'enter_bug') |
| ->setData('token', $queryFormResult->getToken()) |
| ->setData('product', $this->product) |
| ->setData('component', $this->component) |
| ->setData('cc', join(',', $this->cc)) |
| ->setData('short_desc', $this->summary) |
| ->setData('comment', join('\n\n', $this->body)) |
| ->setData('op_sys', 'All') |
| ->setData('rep_platform', 'All') |
| ->setData('bug_severity', 'normal') |
| ->setData('priority', 'Normal') |
| ->setData('version', 'unspecified') |
| ->execute(); |
| |
| if (preg_match($this->client->bugCreatedPattern, $result->contents, $matches)) { |
| return new Bug($this->client, $matches[1]); |
| } |
| |
| if (preg_match('/<title>(.*)<\/title>/ims', $result->contents, $matches)) { |
| $message = preg_replace('/\s+/', ' ', $matches[1]); |
| } else $message = 'Unknown error'; |
| |
| // TODO Make custom exception |
| throw new Exception($message); |
| } |
| } |
| |
| class AttachmentBuilder { |
| var $bug; |
| var $file; |
| var $description = 'A file'; |
| |
| function __construct($bug) { |
| $this->bug = $bug; |
| } |
| |
| function setFile($file) { |
| $this->file = $file; |
| return $this; |
| } |
| |
| function setDescription($description) { |
| $this->description = $description; |
| return $this; |
| } |
| |
| function create() { |
| $query = new BugzillaGetQuery($this->bug->client, 'attachment.cgi'); |
| $queryFormResult = $query |
| ->setData('bugid', $this->bug->id) |
| ->setData('action', 'enter') |
| ->execute(); |
| |
| $query = new BugzillaPostQuery($this->bug->client, 'attachment.cgi'); |
| $result = $query |
| ->setData('form_name', 'enter_bug') |
| ->setData('token', $queryFormResult->getToken()) |
| ->setData('bugid', $this->bug->id) |
| ->setData('action', 'insert') |
| ->setData('data', "@$this->file") |
| ->setData('description', $this->description) |
| ->setData('contenttypemethod', 'autodetect') |
| ->execute(); |
| |
| if (preg_match($this->bug->client->attachmentCreatedPattern, $result->contents, $matches)) { |
| return new Attachment($this->bug, $matches[1]); |
| } |
| |
| if (preg_match('/<title>(.*)<\/title>/ims', $result->contents, $matches)) { |
| $message = preg_replace('/\s+/', ' ', $matches[1]); |
| } else $message = 'Unknown error'; |
| |
| // TODO Make custom exception |
| throw new Exception($message); |
| } |
| } |
| |
| class Bug { |
| var $client; |
| var $id; |
| |
| function __construct($client, $id) { |
| $this->client = $client; |
| $this->id = $id; |
| } |
| |
| function getId() { |
| return $this->id; |
| } |
| |
| function startAttachment() { |
| return new AttachmentBuilder($this); |
| } |
| } |
| |
| class Attachment { |
| var $bug; |
| var $id; |
| |
| function __construct($bug, $id) { |
| $this->bug = $bug; |
| $this->id = $id; |
| } |
| } |
| |
| /** |
| * Instances of this class are used to build and execute a POST query |
| * against Bugzilla. |
| * |
| * @internal |
| */ |
| class BugzillaPostQuery { |
| var $client; |
| var $resource; |
| var $parameters = array(); |
| |
| function __construct($client, $resource) { |
| $this->client = $client; |
| $this->resource = $resource; |
| } |
| |
| function setData($key, $value) { |
| $this->parameters[$key] = $value; |
| return $this; |
| } |
| |
| function getUrl() { |
| return $this->client->host . '/' . $this->resource; |
| } |
| |
| function getDefaultOptions() { |
| return array( |
| CURLOPT_USERAGENT => "Eclipse", |
| CURLOPT_COOKIEFILE => $this->client->cookieFile, |
| CURLOPT_COOKIEJAR => $this->client->cookieFile, |
| // CURLOPT_VERBOSE => 1, |
| CURLOPT_RETURNTRANSFER => 1, |
| CURLOPT_URL => $this->getUrl() |
| ); |
| } |
| |
| function getOptions() { |
| $options = $this->getDefaultOptions(); |
| $options[CURLOPT_POST] = TRUE; |
| $options[CURLOPT_POSTFIELDS] = $this->parameters; |
| return $options; |
| } |
| |
| function execute() { |
| $curl = curl_init($this->client->host); |
| curl_setopt_array($curl, $this->getOptions()); |
| $contents = curl_exec($curl); |
| curl_close($curl); |
| return new QueryResult($contents); |
| } |
| |
| } |
| |
| class QueryResult { |
| var $contents; |
| |
| function __construct($contents) { |
| $this->contents = $contents; |
| } |
| |
| function getToken() { |
| if (preg_match('/<input type="hidden" name="token" value="(\w+)">/', $this->contents, $matches)) |
| return $matches[1]; |
| return null; |
| } |
| } |
| |
| class BugzillaGetQuery extends BugzillaPostQuery { |
| function getUrl() { |
| return parent::getUrl() . '?' . $this->getParameters(); |
| } |
| |
| function getOptions() { |
| $options = $this->getDefaultOptions(); |
| $options[CURLOPT_HTTPGET] = TRUE; |
| return $options; |
| } |
| |
| function getParameters() { |
| $parameters = array(); |
| foreach($this->parameters as $key => $value) $parameters[] = "$key=$value"; |
| return join('&', $parameters); |
| } |
| } |
| |
| ?> |