r87868 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r87867‎ | r87868 | r87869 >
Date:02:42, 11 May 2011
Author:mah
Status:deferred (Comments)
Tags:
Comment:
main.php contains a bugzilla api client I'm posting about on Wikitech-l
Modified paths:
  • /trunk/tools/bugzilla/client (added) (history)
  • /trunk/tools/bugzilla/client/bugzilla.php (added) (history)
  • /trunk/tools/bugzilla/client/jsonRPCClient.php (added) (history)
  • /trunk/tools/bugzilla/client/main.php (added) (history)

Diff [purge]

Index: trunk/tools/bugzilla/client/bugzilla.php
@@ -0,0 +1,222 @@
 2+#!/usr/bin/php -f
 3+<?php
 4+
 5+require_once "$IP/includes/AutoLoader.php";
 6+require_once 'jsonRPCClient.php';
 7+
 8+class BugzillaBug {
 9+ static private $bugs;
 10+ private $bz = null;
 11+ private $id = null;
 12+ private $data = null;
 13+ private $dependency = null;
 14+
 15+ private function inCache( ) {
 16+ return isset( self::$bugs[$this->id] );
 17+ }
 18+
 19+ private function fromCache( ) {
 20+ $this->bz = self::$bugs[ $this->id ]->bz;
 21+ $this->data = self::$bugs[ $this->id ]->data;
 22+ }
 23+
 24+ public function __construct( $id, $bz, $noFetch = false ) {
 25+ $this->id = $id;
 26+ if( !$this->inCache( ) && !$noFetch ) {
 27+ $this->bz = $bz;
 28+ $this->data = $this->bz->search( array( "id" => $id ) );
 29+ $this->data = $this->data['bugs'][0];
 30+ self::$bugs[$id] = $this;
 31+ } else if( $this->inCache( ) ){
 32+ $this->fromCache( );
 33+ }
 34+ }
 35+
 36+
 37+ static public function newFromQuery( $bz, $data ) {
 38+ $bug = new BugzillaBug( $data['id'], $bz, true );
 39+
 40+ $bug->data = $data;
 41+ return $bug;
 42+ }
 43+
 44+ /**
 45+ * Returns true if the bug is resolvd
 46+ */
 47+ public function isResolved( ) {
 48+ return !$this->data['is_open'];
 49+ }
 50+
 51+ public function isOpen( ) {
 52+ return $this->data['is_open'];
 53+ }
 54+
 55+ public function getPriority( ) {
 56+ $p = $this->data["priority"];
 57+ if( $p == "Lowest" ) return 2;
 58+ if( $p == "Low" ) return 1;
 59+ if( $p == "Normal" ) return 0;
 60+ if( $p == "High" ) return -1;
 61+ if( $p == "Highest" ) return -2;
 62+ }
 63+
 64+ public function getProduct( ) {
 65+ return $this->data["product"];
 66+ }
 67+
 68+ public function getComponent( ) {
 69+ return $this->data["component"];
 70+ }
 71+
 72+ public function getAssignee( ) {
 73+ return $this->data["assigned_to"];
 74+ }
 75+
 76+ public function getPriorityText( ) {
 77+ return $this->data["priority"];
 78+ }
 79+
 80+ public function getStatus( ) {
 81+ return $this->data['status'];
 82+ }
 83+
 84+ public function getID( ) {
 85+ return $this->id;
 86+ }
 87+
 88+ public function getSummary( ) {
 89+ return $this->data['summary'];
 90+ }
 91+
 92+ public function getHistory( ) {
 93+ return $this->bz->__call( "Bug.history", array( "ids" => $this->id ) );
 94+ }
 95+
 96+ /* bz 4 reveals this info more easily */
 97+ public function getDependencies( ) {
 98+ return $this->data['depends_on'];
 99+
 100+ /* Here's what was needed for Bz 3 */
 101+ $dep = array();
 102+ if(!$this->dependency) {
 103+ $hist = $this->getHistory( );
 104+ $changes = $hist['bugs'][0]['history'];
 105+ foreach($changes as $b) {
 106+ foreach($b['changes'] as $i => $desc) {
 107+ if($desc['field_name'] == 'dependson') {
 108+ if($desc['added']) {
 109+ $dep[$desc['added']] = true;
 110+ }
 111+ if($desc['removed']) {
 112+ unset($dep[$desc['removed']]);
 113+ }
 114+ }
 115+ }
 116+ }
 117+ foreach($dep as $id => $none) {
 118+ $this->dependency[] = new BugzillaBug( $id, $this->bz );
 119+ }
 120+ }
 121+
 122+ return $this->dependency;
 123+ }
 124+}
 125+
 126+class BugzillaSearchIterator implements Iterator {
 127+ private $conditions;
 128+ private $bz;
 129+ private $data = array();
 130+ private $limit = 20;
 131+ private $offset = 0;
 132+ private $eol = false;
 133+
 134+ public function __construct( $bz, $conditions ) {
 135+ $this->bz = $bz;
 136+ $this->conditions = $conditions;
 137+
 138+ $this->conditions['limit'] = $this->limit;
 139+ $this->conditions['offset'] = $this->offset;
 140+ }
 141+
 142+ private function fetchNext( ) {
 143+ if( $this->offset == count( $this->data ) && !$this->eol && $this->offset % $this->limit === 0 ) {
 144+ $results = $this->bz->search( $this->conditions );
 145+
 146+ $this->conditions['offset'] += $this->limit;
 147+
 148+ if( count( $results['bugs'] ) < $this->limit ) {
 149+ $this->eol = true;
 150+ }
 151+
 152+ foreach($results['bugs'] as $bug) {
 153+ $this->data[] = BugzillaBug::newFromQuery($this->bz, $bug);
 154+ }
 155+ }
 156+ }
 157+
 158+ public function current( ) {
 159+ return $this->data[$this->offset];
 160+ }
 161+
 162+ public function key ( ) {
 163+ return $this->offset;
 164+ }
 165+
 166+ public function next ( ) {
 167+ $this->fetchNext();
 168+ if($this->offset < count($this->data)) $this->offset++;
 169+ }
 170+
 171+ public function rewind ( ) {
 172+ $this->offset = 0;
 173+ }
 174+
 175+ public function valid ( ) {
 176+ $this->fetchNext();
 177+ return isset( $this->data[ $this->offset ] );
 178+ }
 179+}
 180+
 181+class BugzillaWebClient {
 182+ private $bz = null;
 183+
 184+ public function __construct( $url, $user = null, $password = null, $debug = false ) {
 185+ $this->bz = new jsonRPCClient( $url, $debug );
 186+ if($user && $password) {
 187+ $this->bz->__call( "User.login", array( "login" => $user, "password" => $password ) );
 188+ }
 189+ }
 190+
 191+ public function getById( $id ) {
 192+ return new BugzillaBug( $id, $this->bz );
 193+ }
 194+
 195+ public function getFields( ) {
 196+ /* Weird thing we have to do to keep bz from barfing */
 197+ return $this->bz->__call( "Bug.fields", array( "" => "" ) );
 198+ }
 199+
 200+ public function search( $conditions ) {
 201+ if(is_array($conditions)) {
 202+ return $this->bz->__call( "Bug.search", $conditions );
 203+ } else {
 204+ throw new Exception("Search called without an array of conditions");
 205+ }
 206+ }
 207+
 208+ public function getBugHistory( $id ) {
 209+ $b = $this->getById( $id );
 210+ return $b->getHistory();
 211+ }
 212+
 213+ public function getDependencies( $id ) {
 214+ $b = $this->getById( $id );
 215+ return $b->getDependencies();
 216+ }
 217+
 218+ public function getResolved( $resolution ) {
 219+ if(!is_array($resolution)) $resolution = array($resolution);
 220+ return $this->search(array("resolution" => $resolution, "limit" => 10));
 221+ }
 222+}
 223+
Property changes on: trunk/tools/bugzilla/client/bugzilla.php
___________________________________________________________________
Added: svn:eol-syle
1224 + native
Index: trunk/tools/bugzilla/client/jsonRPCClient.php
@@ -0,0 +1,159 @@
 2+<?php
 3+/*
 4+ COPYRIGHT
 5+
 6+Copyright 2007 Sergio Vaccaro <sergio@inservibile.org>
 7+
 8+This file is part of JSON-RPC PHP.
 9+
 10+JSON-RPC PHP is free software; you can redistribute it and/or modify
 11+it under the terms of the GNU General Public License as published by
 12+the Free Software Foundation; either version 2 of the License, or
 13+(at your option) any later version.
 14+
 15+JSON-RPC PHP is distributed in the hope that it will be useful,
 16+but WITHOUT ANY WARRANTY; without even the implied warranty of
 17+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 18+GNU General Public License for more details.
 19+
 20+You should have received a copy of the GNU General Public License
 21+along with JSON-RPC PHP; if not, write to the Free Software
 22+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 23+*/
 24+
 25+/**
 26+ * The object of this class are generic jsonRPC 1.0 clients
 27+ * http://json-rpc.org/wiki/specification
 28+ *
 29+ * @author sergio <jsonrpcphp@inservibile.org>
 30+ */
 31+
 32+class jsonRPCClient {
 33+
 34+ /**
 35+ * Debug state
 36+ *
 37+ * @var boolean
 38+ */
 39+ private $debug = false;
 40+
 41+ /**
 42+ * The server URL
 43+ *
 44+ * @var string
 45+ */
 46+ private $url;
 47+ /**
 48+ * The request id
 49+ *
 50+ * @var integer
 51+ */
 52+ private $id;
 53+ /**
 54+ * If true, notifications are performed instead of requests
 55+ *
 56+ * @var boolean
 57+ */
 58+ private $notification = false;
 59+
 60+ private $cookieJar = array();
 61+
 62+ /**
 63+ * Takes the connection parameters
 64+ *
 65+ * @param string $url
 66+ * @param boolean $debug
 67+ */
 68+ public function __construct($url,$debug = false) {
 69+ // server URL
 70+ $this->url = $url;
 71+ // proxy
 72+ empty($proxy) ? $this->proxy = '' : $this->proxy = $proxy;
 73+ // debug state
 74+ if($debug) $this->debug = true;
 75+ // message id
 76+ $this->id = 1;
 77+ }
 78+
 79+ /**
 80+ * Sets the notification state of the object. In this state, notifications are performed, instead of requests.
 81+ *
 82+ * @param boolean $notification
 83+ */
 84+ public function setRPCNotification($notification) {
 85+ empty($notification) ?
 86+ $this->notification = false
 87+ :
 88+ $this->notification = true;
 89+ }
 90+
 91+ /**
 92+ * Performs a jsonRCP request and gets the results as an array
 93+ *
 94+ * @param string $method
 95+ * @param array $params
 96+ * @return array
 97+ */
 98+ public function __call($method, $params = null) {
 99+ // sets notification or request task
 100+ if ($this->notification) {
 101+ $currentId = NULL;
 102+ } else {
 103+ $currentId = $this->id;
 104+ }
 105+ // prepares the request
 106+ $request = array(
 107+ 'version' => '1.1',
 108+ 'method' => $method,
 109+ );
 110+ if( $params ) {
 111+ $request['params'] = $params;
 112+ }
 113+ $request = json_encode($request);
 114+ $this->debug && $this->debug='***** Request *****'."\n".$request."\n".'***** End Of request *****'."\n\n";
 115+
 116+ // performs the HTTP POST
 117+ $h = MWHttpRequest::factory($this->url, array('method' => "POST", 'postData' => $request));
 118+ $h->setHeader('Content-Type', "application/json");
 119+ if(!$this->cookieJar) $this->cookieJar = $h->getCookieJar();
 120+ $h->setCookieJar($this->cookieJar);
 121+ $status = $h->execute();
 122+ $this->cookieJar = $h->getCookieJar();
 123+
 124+ $response = $h->getContent();
 125+
 126+ if ( $status->isOk() ) {
 127+ $this->debug && $this->debug.='***** Server response *****'."\n".$response.'***** End of server response *****'."\n";
 128+ $response = json_decode($response,true);
 129+ } else {
 130+ throw new Exception(html_entity_decode(preg_replace("#<[^<>]*>#", "", $h->getContent())));
 131+ }
 132+
 133+ // debug output
 134+ if ($this->debug) {
 135+ echo $this->debug;
 136+ }
 137+
 138+ // final checks and return
 139+ if (!$this->notification) {
 140+ // check
 141+ if (isset($response['id']) && $response['id'] != $currentId) {
 142+ throw new Exception('Incorrect response id (request id: '.$currentId.', response id: '.$response['id'].')');
 143+ }
 144+ if (isset($response['error']) && !is_null($response['error'])) {
 145+ $err = $response['error'];
 146+ if(isset($err['message']) && isset($err['code'])) {
 147+ throw new Exception($err['message'], $err['code']);
 148+ } else if(isset($err['message'])) {
 149+ throw new Exception('Request error: '.$err['message']);
 150+ } else {
 151+ throw new Exception('Request error: '.var_export($err, true));
 152+ }
 153+ }
 154+
 155+ return $response['result'];
 156+ } else {
 157+ return true;
 158+ }
 159+ }
 160+}
Property changes on: trunk/tools/bugzilla/client/jsonRPCClient.php
___________________________________________________________________
Added: svn:eol-syle
1161 + native
Index: trunk/tools/bugzilla/client/main.php
@@ -0,0 +1,134 @@
 2+#!/usr/bin/php
 3+<?php
 4+
 5+define('MEDIAWIKI', true);
 6+$IP = "/home/mah/work/code/mediawiki/mw-svn"; # root of your mw installation ... we use the HTTPClient class
 7+
 8+require_once 'bugzilla.php';
 9+$u = parse_ini_file(getenv('HOME')."/.bugzilla.ini");
 10+$bz = new BugzillaWebClient( $u['url'].'/jsonrpc.cgi', $u['email'], $u['password'], $u['debug']);
 11+#$iter = new BugzillaSearchIterator( $bz, array( 'id' => $id ) );
 12+
 13+$terms = array(
 14+ "component" => array(
 15+ # From Mobile:
 16+ 'android', 'iphone', 'server',
 17+
 18+ # From MediaWiki:
 19+ 'API', 'Blocking', 'Categories', 'Change Tagging', 'Database', 'Deleting', 'Device compatibility', 'DjVu',
 20+ 'Documentation', 'Email', 'Export/Import', 'General/Unknown', 'History/Diffs', 'Images and files', 'Installation',
 21+ 'Internationalization', 'Javascript', 'Language converter', 'Maintenance scripts', 'Modern skin', 'Page editing',
 22+ 'Page protection', 'Page rendering', 'Recent changes', 'Redirects', 'Resource Loader', 'Revision deletion', 'Search',
 23+ 'Special pages', 'Syndication', 'Templates', 'Unit tests', 'Uploading', 'User interface', 'User login', 'User preferences',
 24+ 'Vector Skin', 'Watchlist',
 25+
 26+ # From WMF extensions
 27+ "AbuseFilter",
 28+ "AntiSpoof",
 29+ "ArticleAssessmentPilot",
 30+ "ArticleFeedback",
 31+ "CategoryTree",
 32+ "CentralAuth",
 33+ "CentralNotice",
 34+ "CharInsert",
 35+ "CheckUser",
 36+ "Cite",
 37+ "ClickTracking",
 38+ "ClientSide",
 39+ "CodeReview",
 40+ "Collection",
 41+ "CommunityVoice",
 42+ "ConfirmEdit",
 43+ "ContactPage",
 44+ "ContributionTracking",
 45+ "DismissableSiteNotice",
 46+ "Donation","Form",
 47+ "DynamicPageList",
 48+ "FundraiserPortal",
 49+ "Gadgets",
 50+ "GlobalBlocking",
 51+ "GlobalUsage",
 52+ "ImageMap",
 53+ "Inputbox",
 54+ "Installation",
 55+ "Internationalization",
 56+ "LabeledSectionTransclusion",
 57+ "LandingCheck",
 58+ "LiquidThreads",
 59+ "LocalisationUpdate",
 60+ "Lucene Search",
 61+ "Narayam",
 62+ "NewUserMessage",
 63+ "Nuke",
 64+ "OAI",
 65+ "OggHandler",
 66+ "Oversight",
 67+ "PagedTiffHandler",
 68+ "ParserFunctions",
 69+ "PdfHandler",
 70+ "PhotoCommons",
 71+ "Poem",
 72+ "PrefStats",
 73+ "PrefSwitch",
 74+ "PrefSwitch",
 75+ "ProofreadPage",
 76+ "Quiz",
 77+ "RSS",
 78+ "ReaderFeedback",
 79+ "Renameuser",
 80+ "SecurePoll",
 81+ "SiteMatrix",
 82+ "Spam Blacklist",
 83+ "Syndication",
 84+ "SyntaxHighlight (GeSHi)",
 85+ "TitleBlacklist",
 86+ "TitleKey",
 87+ "TorBlock",
 88+ "UploadWizard",
 89+ "UploadWizard",
 90+ "UsabilityInitiative",
 91+ "Use","SpecialCite",
 92+ "UserDailyContribs",
 93+ "UsernameBlacklist",
 94+ "VariablePage",
 95+ "Vector",
 96+ "WikiEditor",
 97+ "WikiHiero",
 98+ "WikimediaMobile",
 99+ "[other]",
 100+
 101+ # From Security
 102+ "General",
 103+
 104+ # From Wikimedia Tools
 105+ 'PhotoCommons', 'WikiSnaps',
 106+
 107+ # From Wikipedia
 108+ # 'AcaWiki', 'Bugzilla',
 109+ 'DNS', 'Downloads', 'Extension setup', 'Fundraising Requirements',
 110+ 'Interwiki links', 'IRC', 'Language setup', 'lucene-search-2', 'Mailing lists', 'OTRS', 'Prototype server',
 111+ #'Site logos', 'Site requests',
 112+ 'SSL related', 'Subversion', 'Usage Statistics', 'User survey', 'WAP mobile gateway',
 113+ #'wikibugs IRC bot'
 114+ ),
 115+ "product" => array("MediaWiki", "MediaWiki extensions", "Security", "Wikimedia", "Wikimedia Tools", "Wikipedia Mobile"),
 116+ "severity" => array("blocker", "critical", "major", "normal", "minor", "trivial"),
 117+ "status" => array("UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED"),
 118+ "priority" => array("Highest", "High", "Normal"),
 119+);
 120+
 121+$bugList = array();
 122+$iter = new BugzillaSearchIterator( $bz, $terms );
 123+foreach($iter as $bug) {
 124+ $bugList[$bug->getAssignee()][] = $bug;
 125+}
 126+
 127+foreach($bugList as $assignee => $bugs) {
 128+# $message = "$assignee\n";
 129+ $message = "";
 130+ foreach($bugs as $bug) {
 131+ $message .= " http://bugzilla.wikimedia.org/{$bug->getID()}\n";
 132+# $message .= " {$bug->getPriorityText()} {$bug->getStatus()} {$bug->getSummary()}\n";
 133+ }
 134+ echo $message;
 135+}
Property changes on: trunk/tools/bugzilla/client/main.php
___________________________________________________________________
Added: svn:executable
1136 + *
Added: svn:eol-syle
2137 + native

Comments

#Comment by 😂 (talk | contribs)   02:57, 11 May 2011

Don't need the svn:executable.

Status & tagging log