1# 2# BZ::Client.pm - Web services client for the Bugzilla server 3# 4 5package BZ::Client; 6 7use BZ::Client::XMLRPC(); 8use HTTP::Cookies(); 9 10our $VERSION = '1.04'; 11 12 13sub new($%) { 14 my $class = shift; 15 my $self = { @_ }; 16 bless($self, ref($class) || $class); 17 return $self; 18} 19 20sub url($;$) { 21 my $self = shift; 22 if (@_) { 23 $self->{'url'} = shift; 24 } else { 25 return $self->{'url'}; 26 } 27} 28 29sub user($;$) { 30 my $self = shift; 31 if (@_) { 32 $self->{'user'} = shift; 33 } else { 34 return $self->{'user'}; 35 } 36} 37 38sub password($;$) { 39 my $self = shift; 40 if (@_) { 41 $self->{'password'} = shift; 42 } else { 43 return $self->{'password'}; 44 } 45} 46 47sub error($$;$$) { 48 my($self, $message, $http_code, $xmlrpc_code) = @_; 49 require BZ::Client::Exception; 50 BZ::Client::Exception->throw(message => $message, 51 http_code => $http_code, 52 xmlrpc_code => $xmlrpc_code); 53} 54 55sub log($$$) { 56 my($self, $level, $msg) = @_; 57 my $logger = $self->logger(); 58 if ($logger) { 59 &$logger($level, $msg); 60 } 61} 62 63sub logger($;$) { 64 my($self) = shift; 65 if (@_) { 66 $self->{'logger'} = shift; 67 } else { 68 return $self->{'logger'}; 69 } 70} 71 72sub logDirectory($;$) { 73 my($self) = shift; 74 if (@_) { 75 $self->{'logDirectory'} = shift; 76 } else { 77 return $self->{'logDirectory'}; 78 } 79} 80 81sub xmlrpc($;$) { 82 my $self = shift; 83 if (@_) { 84 $self->{'xmlrpc'} = shift; 85 } else { 86 my $xmlrpc = $self->{'xmlrpc'}; 87 if (!$xmlrpc) { 88 my $url = $self->url() || $self->error("The Bugzilla servers URL is not set."); 89 $xmlrpc = BZ::Client::XMLRPC->new("url" => $url); 90 $xmlrpc->logDirectory($self->logDirectory()); 91 $xmlrpc->logger($self->logger()); 92 $self->xmlrpc($xmlrpc); 93 } 94 return $xmlrpc; 95 } 96} 97 98sub login($) { 99 my $self = shift; 100 my $user = $self->user() || $self->error("The Bugzilla servers user name is not set."); 101 my $password = $self->password() || $self->error("The Bugzilla servers password is not set."); 102 103 my $params = { "login" => $user, 104 "password" => $password, 105 "remember" => BZ::Client::XMLRPC::boolean->new(0) }; 106 my $cookies = HTTP::Cookies->new(); 107 my $response = $self->_api_call("User.login", $params, $cookies); 108 if (!defined($response->{'id'}) || $response->{'id'} !~ /^\d+$/s) { 109 $self->error("Server did not return a valid user ID."); 110 } 111 $self->{"cookies"} = $cookies; 112 return; 113} 114 115sub logout($) { 116 my $self = shift; 117 my $cookies = $self->{"cookies"}; 118 if ($cookies) { 119 $self->{"cookies"} = undef; 120 my $xmlrpc = $self->xmlrpc(); 121 $xmlrpc->request("methodName" => "User.logout", params => [] ); 122 } 123} 124 125sub is_logged_in($) { 126 my $self = shift; 127 return $self->{"cookies"} ? 1 : 0; 128} 129 130sub api_call($$$) { 131 my($self, $methodName, $params) = @_; 132 if (!$self->is_logged_in()) { 133 $self->login(); 134 } 135 return $self->_api_call($methodName, $params); 136} 137 138sub _api_call($$$;$) { 139 my($self, $methodName, $params, $cookies) = @_; 140 $self->log("debug", "BZ::Client::_api_call, sending request for method $methodName to " . $self->url()); 141 my $xmlrpc = $self->xmlrpc(); 142 if ($cookies) { 143 $xmlrpc->user_agent()->cookie_jar($cookies); 144 } 145 my $response = $xmlrpc->request("methodName" => $methodName, params => [ $params ] ); 146 if (!$response) { 147 $self->error("Empty response from server."); 148 } 149 if (ref($response) ne "HASH") { 150 $self->error("Invalid response from server: $response"); 151 } 152 $self->log("debug", "BZ::Client::_api_call, got response for method $methodName"); 153 return $response; 154} 155 1561; 157 158=pod 159 160=head1 NAME 161 162 BZ::Client - A client for the Bugzilla web services API. 163 164=head1 SYNOPSIS 165 166 my $client = BZ::Client->new("url" => $url, 167 "user" => $user, 168 "password" => $password); 169 $client->login(); 170 171=head1 CLASS METHODS 172 173This section lists the class methods of BZ::Client. 174 175=head1 new 176 177 my $client = BZ::Client->new("url" => $url, 178 "user" => $user, 179 "password" => $password); 180 181The new method constructs a new instance of BZ::Client. Whenever you 182want to connect to the Bugzilla server, you must first create a 183Bugzilla client. The methods input is a hash of parameters. 184 185=over 186 187=item url 188 189The Bugzilla servers URL, for example C<https://bugzilla.mozilla.org/>. 190 191=item user 192 193The user name to use when logging in to the Bugzilla server. Typically, 194this will be your email address. 195 196=item password 197 198The password to use when logging in to the Bugzilla server. 199 200=back 201 202=head1 INSTANCE METHODS 203 204This section lists the methods, which an instance of BZ::Client can 205perform. 206 207=head2 url 208 209 my $url = $client->url(); 210 $client->url($url); 211 212Returns or sets the Bugzilla servers URL. 213 214=head2 user 215 216 my $user = $client->user(); 217 $client->user($user); 218 219Returns or sets the user name to use when logging in to the Bugzilla 220server. Typically, this will be your email address. 221 222=head2 password 223 224 my $password = $client->password(); 225 $client->password($password); 226 227Returns or sets the password to use when logging in to the Bugzilla server. 228 229=head2 login 230 231Used to login to the Bugzilla server. There is no need to call this method 232explicitly: It is done automatically, whenever required. 233 234=head2 api_call 235 236 my $response = $client->api_call($methodName, $params); 237 238Used by subclasses of L<BZ::Client::API> to invoke methods of the Bugzilla 239API. Takes a method name and a hash ref of parameters as input. Returns a 240hash ref of named result objects. 241 242=head1 SEE ALSO 243 244 L<BZ::Client::Exception> 245 246