Enhanced HttpError to now include the original request URI if possible.
This commit is contained in:
@@ -39,6 +39,7 @@ from anyjson import simplejson
|
||||
from model import JsonModel
|
||||
from errors import UnknownLinkType
|
||||
from errors import HttpError
|
||||
from errors import InvalidJsonError
|
||||
|
||||
URITEMPLATE = re.compile('{[^}]*}')
|
||||
VARNAME = re.compile('[a-zA-Z0-9_-]+')
|
||||
@@ -108,10 +109,12 @@ def build(serviceName, version,
|
||||
requested_url = uritemplate.expand(discoveryServiceUrl, params)
|
||||
logging.info('URL being requested: %s' % requested_url)
|
||||
resp, content = http.request(requested_url)
|
||||
if resp.status > 400:
|
||||
raise HttpError(resp, content, requested_url)
|
||||
try:
|
||||
service = simplejson.loads(content)
|
||||
except ValueError, e:
|
||||
raise HttpError(resp, content)
|
||||
raise InvalidJsonError()
|
||||
|
||||
fn = os.path.join(os.path.dirname(__file__), 'contrib',
|
||||
serviceName, 'future.json')
|
||||
|
||||
@@ -22,9 +22,10 @@ class Error(Exception):
|
||||
class HttpError(Error):
|
||||
"""HTTP data was invalid or unexpected."""
|
||||
|
||||
def __init__(self, resp, content):
|
||||
def __init__(self, resp, content, uri=None):
|
||||
self.resp = resp
|
||||
self.content = content
|
||||
self.uri = uri
|
||||
|
||||
def _get_reason(self):
|
||||
"""Calculate the reason for the error from the response content.
|
||||
@@ -40,11 +41,20 @@ class HttpError(Error):
|
||||
return reason
|
||||
|
||||
def __repr__(self):
|
||||
return '<HttpError %s "%s">' % (self.resp.status, self._get_reason())
|
||||
if self.uri:
|
||||
return '<HttpError %s when requesting %s returned "%s">' % (
|
||||
self.resp.status, self.uri, self._get_reason())
|
||||
else:
|
||||
return '<HttpError %s "%s">' % (self.resp.status, self._get_reason())
|
||||
|
||||
__str__ = __repr__
|
||||
|
||||
|
||||
class InvalidJsonError(Error):
|
||||
"""The JSON returned could not be parsed."""
|
||||
pass
|
||||
|
||||
|
||||
class UnknownLinkType(Error):
|
||||
"""Link type unknown or unexpected."""
|
||||
pass
|
||||
|
||||
@@ -16,6 +16,7 @@ import httplib2
|
||||
import os
|
||||
|
||||
from model import JsonModel
|
||||
from errors import HttpError
|
||||
|
||||
|
||||
class HttpRequest(object):
|
||||
@@ -67,6 +68,9 @@ class HttpRequest(object):
|
||||
resp, content = http.request(self.uri, self.method,
|
||||
body=self.body,
|
||||
headers=self.headers)
|
||||
|
||||
if resp.status >= 300:
|
||||
raise HttpError(resp, content, self.uri)
|
||||
return self.postproc(resp, content)
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.anyjson</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/anyjson.py">/home/jcgregorio/projects/apiary/apiclient/anyjson.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/anyjson.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/anyjson.py</a></font></td></tr></table>
|
||||
<p><tt>Utility module to import a JSON module<br>
|
||||
<br>
|
||||
Hides all the messy details of exactly where<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.contrib</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/contrib/__init__.py">/home/jcgregorio/projects/apiary/apiclient/contrib/__init__.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/contrib/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/contrib/__init__.py</a></font></td></tr></table>
|
||||
<p></p>
|
||||
<p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
@@ -17,6 +17,5 @@
|
||||
<font color="#ffffff" face="helvetica, arial"><big><strong>Package Contents</strong></big></font></td></tr>
|
||||
|
||||
<tr><td bgcolor="#aa55cc"><tt> </tt></td><td> </td>
|
||||
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="apiclient.contrib.buzz.html"><strong>buzz</strong> (package)</a><br>
|
||||
</td><td width="25%" valign=top></td><td width="25%" valign=top></td><td width="25%" valign=top></td></tr></table></td></tr></table>
|
||||
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top></td><td width="25%" valign=top></td><td width="25%" valign=top></td><td width="25%" valign=top></td></tr></table></td></tr></table>
|
||||
</body></html>
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.discovery</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/discovery.py">/home/jcgregorio/projects/apiary/apiclient/discovery.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/discovery.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/discovery.py</a></font></td></tr></table>
|
||||
<p><tt>Client for discovery based APIs<br>
|
||||
<br>
|
||||
A client library for Google's discovery based APIs.</tt></p>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.errors</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/errors.py">/home/jcgregorio/projects/apiary/apiclient/errors.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/errors.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/errors.py</a></font></td></tr></table>
|
||||
<p><tt>Errors for the library.<br>
|
||||
<br>
|
||||
All exceptions defined by the library<br>
|
||||
@@ -36,6 +36,7 @@ should be defined in this file.</tt></p>
|
||||
</font></dt><dd>
|
||||
<dl>
|
||||
<dt><font face="helvetica, arial"><a href="apiclient.errors.html#HttpError">HttpError</a>
|
||||
</font></dt><dt><font face="helvetica, arial"><a href="apiclient.errors.html#InvalidJsonError">InvalidJsonError</a>
|
||||
</font></dt><dt><font face="helvetica, arial"><a href="apiclient.errors.html#UnknownLinkType">UnknownLinkType</a>
|
||||
</font></dt></dl>
|
||||
</dd>
|
||||
@@ -120,7 +121,7 @@ Data descriptors inherited from <a href="exceptions.html#BaseException">exceptio
|
||||
</dl>
|
||||
<hr>
|
||||
Methods defined here:<br>
|
||||
<dl><dt><a name="HttpError-__init__"><strong>__init__</strong></a>(self, resp, content)</dt></dl>
|
||||
<dl><dt><a name="HttpError-__init__"><strong>__init__</strong></a>(self, resp, content, uri<font color="#909090">=None</font>)</dt></dl>
|
||||
|
||||
<dl><dt><a name="HttpError-__repr__"><strong>__repr__</strong></a>(self)</dt></dl>
|
||||
|
||||
@@ -155,6 +156,67 @@ Use of negative indices is not supported.</tt></dd
|
||||
|
||||
<dl><dt><a name="HttpError-__unicode__"><strong>__unicode__</strong></a>(...)</dt></dl>
|
||||
|
||||
<hr>
|
||||
Data descriptors inherited from <a href="exceptions.html#BaseException">exceptions.BaseException</a>:<br>
|
||||
<dl><dt><strong>__dict__</strong></dt>
|
||||
</dl>
|
||||
<dl><dt><strong>args</strong></dt>
|
||||
</dl>
|
||||
<dl><dt><strong>message</strong></dt>
|
||||
</dl>
|
||||
</td></tr></table> <p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
<tr bgcolor="#ffc8d8">
|
||||
<td colspan=3 valign=bottom> <br>
|
||||
<font color="#000000" face="helvetica, arial"><a name="InvalidJsonError">class <strong>InvalidJsonError</strong></a>(<a href="apiclient.errors.html#Error">Error</a>)</font></td></tr>
|
||||
|
||||
<tr bgcolor="#ffc8d8"><td rowspan=2><tt> </tt></td>
|
||||
<td colspan=2><tt>The JSON returned could not be parsed.<br> </tt></td></tr>
|
||||
<tr><td> </td>
|
||||
<td width="100%"><dl><dt>Method resolution order:</dt>
|
||||
<dd><a href="apiclient.errors.html#InvalidJsonError">InvalidJsonError</a></dd>
|
||||
<dd><a href="apiclient.errors.html#Error">Error</a></dd>
|
||||
<dd><a href="exceptions.html#Exception">exceptions.Exception</a></dd>
|
||||
<dd><a href="exceptions.html#BaseException">exceptions.BaseException</a></dd>
|
||||
<dd><a href="__builtin__.html#object">__builtin__.object</a></dd>
|
||||
</dl>
|
||||
<hr>
|
||||
Data descriptors inherited from <a href="apiclient.errors.html#Error">Error</a>:<br>
|
||||
<dl><dt><strong>__weakref__</strong></dt>
|
||||
<dd><tt>list of weak references to the object (if defined)</tt></dd>
|
||||
</dl>
|
||||
<hr>
|
||||
Methods inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
|
||||
<dl><dt><a name="InvalidJsonError-__init__"><strong>__init__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__init__">__init__</a>(...) initializes x; see x.__class__.__doc__ for signature</tt></dd></dl>
|
||||
|
||||
<hr>
|
||||
Data and other attributes inherited from <a href="exceptions.html#Exception">exceptions.Exception</a>:<br>
|
||||
<dl><dt><strong>__new__</strong> = <built-in method __new__ of type object><dd><tt>T.<a href="#InvalidJsonError-__new__">__new__</a>(S, ...) -> a new object with type S, a subtype of T</tt></dl>
|
||||
|
||||
<hr>
|
||||
Methods inherited from <a href="exceptions.html#BaseException">exceptions.BaseException</a>:<br>
|
||||
<dl><dt><a name="InvalidJsonError-__delattr__"><strong>__delattr__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__delattr__">__delattr__</a>('name') <==> del x.name</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__getattribute__"><strong>__getattribute__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__getattribute__">__getattribute__</a>('name') <==> x.name</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__getitem__"><strong>__getitem__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__getitem__">__getitem__</a>(y) <==> x[y]</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__getslice__"><strong>__getslice__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__getslice__">__getslice__</a>(i, j) <==> x[i:j]<br>
|
||||
<br>
|
||||
Use of negative indices is not supported.</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__reduce__"><strong>__reduce__</strong></a>(...)</dt></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__repr__"><strong>__repr__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__repr__">__repr__</a>() <==> repr(x)</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__setattr__"><strong>__setattr__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__setattr__">__setattr__</a>('name', value) <==> x.name = value</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__setstate__"><strong>__setstate__</strong></a>(...)</dt></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__str__"><strong>__str__</strong></a>(...)</dt><dd><tt>x.<a href="#InvalidJsonError-__str__">__str__</a>() <==> str(x)</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="InvalidJsonError-__unicode__"><strong>__unicode__</strong></a>(...)</dt></dl>
|
||||
|
||||
<hr>
|
||||
Data descriptors inherited from <a href="exceptions.html#BaseException">exceptions.BaseException</a>:<br>
|
||||
<dl><dt><strong>__dict__</strong></dt>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.appengine</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/ext/appengine.py">/home/jcgregorio/projects/apiary/apiclient/ext/appengine.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/appengine.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/appengine.py</a></font></td></tr></table>
|
||||
<p><tt>Utilities for Google App Engine<br>
|
||||
<br>
|
||||
Utilities for making it easier to use the<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.authtools</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/ext/authtools.py">/home/jcgregorio/projects/apiary/apiclient/ext/authtools.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/authtools.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/authtools.py</a></font></td></tr></table>
|
||||
<p><tt>Command-line tools for authenticating via OAuth 1.0<br>
|
||||
<br>
|
||||
Do the OAuth 1.0 Three Legged Dance for<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.django_orm</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/ext/django_orm.py">/home/jcgregorio/projects/apiary/apiclient/ext/django_orm.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/django_orm.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/django_orm.py</a></font></td></tr></table>
|
||||
<p></p>
|
||||
<p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.<a href="apiclient.ext.html"><font color="#ffffff">ext</font></a>.file</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/ext/file.py">/home/jcgregorio/projects/apiary/apiclient/ext/file.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/file.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/file.py</a></font></td></tr></table>
|
||||
<p><tt>Utilities for OAuth.<br>
|
||||
<br>
|
||||
Utilities for making it easier to work with OAuth 1.0 credentials.</tt></p>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.ext</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/ext/__init__.py">/home/jcgregorio/projects/apiary/apiclient/ext/__init__.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/ext/__init__.py</a></font></td></tr></table>
|
||||
<p></p>
|
||||
<p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong>apiclient</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/__init__.py">/home/jcgregorio/projects/apiary/apiclient/__init__.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/__init__.py</a></font></td></tr></table>
|
||||
<p></p>
|
||||
<p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
@@ -19,11 +19,12 @@
|
||||
<tr><td bgcolor="#aa55cc"><tt> </tt></td><td> </td>
|
||||
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="apiclient.anyjson.html">anyjson</a><br>
|
||||
<a href="apiclient.contrib.html"><strong>contrib</strong> (package)</a><br>
|
||||
</td><td width="25%" valign=top><a href="apiclient.discovery.html">discovery</a><br>
|
||||
<a href="apiclient.errors.html">errors</a><br>
|
||||
</td><td width="25%" valign=top><a href="apiclient.ext.html"><strong>ext</strong> (package)</a><br>
|
||||
<a href="apiclient.discovery.html">discovery</a><br>
|
||||
</td><td width="25%" valign=top><a href="apiclient.errors.html">errors</a><br>
|
||||
<a href="apiclient.ext.html"><strong>ext</strong> (package)</a><br>
|
||||
<a href="apiclient.http.html">http</a><br>
|
||||
</td><td width="25%" valign=top><a href="apiclient.model.html">model</a><br>
|
||||
</td><td width="25%" valign=top><a href="apiclient.json.html">json</a><br>
|
||||
<a href="apiclient.model.html">model</a><br>
|
||||
<a href="apiclient.oauth.html">oauth</a><br>
|
||||
</td></tr></table></td></tr></table>
|
||||
</td><td width="25%" valign=top></td></tr></table></td></tr></table>
|
||||
</body></html>
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.http</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/http.py">/home/jcgregorio/projects/apiary/apiclient/http.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/http.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/http.py</a></font></td></tr></table>
|
||||
<p><tt>Classes to encapsulate a single HTTP request.<br>
|
||||
<br>
|
||||
The classes implement a command pattern, with every<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.model</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/model.py">/home/jcgregorio/projects/apiary/apiclient/model.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/model.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/model.py</a></font></td></tr></table>
|
||||
<p><tt><a href="#Model">Model</a> objects for requests and responses.<br>
|
||||
<br>
|
||||
Each API may support one or more serializations, such<br>
|
||||
@@ -22,10 +22,11 @@ for converting between the wire format and th
|
||||
<font color="#ffffff" face="helvetica, arial"><big><strong>Modules</strong></big></font></td></tr>
|
||||
|
||||
<tr><td bgcolor="#aa55cc"><tt> </tt></td><td> </td>
|
||||
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="logging.html">logging</a><br>
|
||||
<td width="100%"><table width="100%" summary="list"><tr><td width="25%" valign=top><a href="gflags.html">gflags</a><br>
|
||||
</td><td width="25%" valign=top><a href="logging.html">logging</a><br>
|
||||
</td><td width="25%" valign=top><a href="simplejson.html">simplejson</a><br>
|
||||
</td><td width="25%" valign=top><a href="urllib.html">urllib</a><br>
|
||||
</td><td width="25%" valign=top></td></tr></table></td></tr></table><p>
|
||||
</td></tr></table></td></tr></table><p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
<tr bgcolor="#ee77aa">
|
||||
<td colspan=3 valign=bottom> <br>
|
||||
@@ -40,10 +41,15 @@ for converting between the wire format and th
|
||||
</font></dt><dd>
|
||||
<dl>
|
||||
<dt><font face="helvetica, arial"><a href="apiclient.model.html#JsonModel">JsonModel</a>
|
||||
</font></dt><dd>
|
||||
<dl>
|
||||
<dt><font face="helvetica, arial"><a href="apiclient.model.html#LoggingJsonModel">LoggingJsonModel</a>
|
||||
</font></dt></dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
@@ -97,6 +103,63 @@ Returns:<br>
|
||||
Raises:<br>
|
||||
apiclient.errors.HttpError if a non 2xx response is received.</tt></dd></dl>
|
||||
|
||||
<hr>
|
||||
Data descriptors inherited from <a href="apiclient.model.html#Model">Model</a>:<br>
|
||||
<dl><dt><strong>__dict__</strong></dt>
|
||||
<dd><tt>dictionary for instance variables (if defined)</tt></dd>
|
||||
</dl>
|
||||
<dl><dt><strong>__weakref__</strong></dt>
|
||||
<dd><tt>list of weak references to the object (if defined)</tt></dd>
|
||||
</dl>
|
||||
</td></tr></table> <p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
<tr bgcolor="#ffc8d8">
|
||||
<td colspan=3 valign=bottom> <br>
|
||||
<font color="#000000" face="helvetica, arial"><a name="LoggingJsonModel">class <strong>LoggingJsonModel</strong></a>(<a href="apiclient.model.html#JsonModel">JsonModel</a>)</font></td></tr>
|
||||
|
||||
<tr bgcolor="#ffc8d8"><td rowspan=2><tt> </tt></td>
|
||||
<td colspan=2><tt>A printable <a href="#JsonModel">JsonModel</a> class that supports logging response info.<br> </tt></td></tr>
|
||||
<tr><td> </td>
|
||||
<td width="100%"><dl><dt>Method resolution order:</dt>
|
||||
<dd><a href="apiclient.model.html#LoggingJsonModel">LoggingJsonModel</a></dd>
|
||||
<dd><a href="apiclient.model.html#JsonModel">JsonModel</a></dd>
|
||||
<dd><a href="apiclient.model.html#Model">Model</a></dd>
|
||||
<dd><a href="__builtin__.html#object">__builtin__.object</a></dd>
|
||||
</dl>
|
||||
<hr>
|
||||
Methods defined here:<br>
|
||||
<dl><dt><a name="LoggingJsonModel-request"><strong>request</strong></a>(self, headers, path_params, query_params, body_value)</dt><dd><tt>An overloaded request method that will output debug info if requested.<br>
|
||||
<br>
|
||||
Args:<br>
|
||||
headers: dict, request headers<br>
|
||||
path_params: dict, parameters that appear in the request path<br>
|
||||
query_params: dict, parameters that appear in the query<br>
|
||||
body_value: <a href="__builtin__.html#object">object</a>, the request body as a Python <a href="__builtin__.html#object">object</a>, which must be<br>
|
||||
serializable by simplejson.<br>
|
||||
Returns:<br>
|
||||
A tuple of (headers, path_params, query, body)<br>
|
||||
<br>
|
||||
headers: dict, request headers<br>
|
||||
path_params: dict, parameters that appear in the request path<br>
|
||||
query: string, query part of the request URI<br>
|
||||
body: string, the body serialized as JSON</tt></dd></dl>
|
||||
|
||||
<dl><dt><a name="LoggingJsonModel-response"><strong>response</strong></a>(self, resp, content)</dt><dd><tt>An overloaded response method that will output debug info if requested.<br>
|
||||
<br>
|
||||
Args:<br>
|
||||
resp: An httplib2.Response <a href="__builtin__.html#object">object</a>.<br>
|
||||
content: A string representing the response body.<br>
|
||||
<br>
|
||||
Returns:<br>
|
||||
The body de-serialized as a Python <a href="__builtin__.html#object">object</a>.</tt></dd></dl>
|
||||
|
||||
<hr>
|
||||
Methods inherited from <a href="apiclient.model.html#JsonModel">JsonModel</a>:<br>
|
||||
<dl><dt><a name="LoggingJsonModel-__init__"><strong>__init__</strong></a>(self, data_wrapper<font color="#909090">=False</font>)</dt><dd><tt>Construct a <a href="#JsonModel">JsonModel</a><br>
|
||||
<br>
|
||||
Args:<br>
|
||||
data_wrapper: boolean, wrap requests and responses in a data wrapper</tt></dd></dl>
|
||||
|
||||
<hr>
|
||||
Data descriptors inherited from <a href="apiclient.model.html#Model">Model</a>:<br>
|
||||
<dl><dt><strong>__dict__</strong></dt>
|
||||
@@ -162,7 +225,8 @@ Data descriptors defined here:<br>
|
||||
<font color="#ffffff" face="helvetica, arial"><big><strong>Data</strong></big></font></td></tr>
|
||||
|
||||
<tr><td bgcolor="#55aa55"><tt> </tt></td><td> </td>
|
||||
<td width="100%"><strong>__author__</strong> = 'jcgregorio@google.com (Joe Gregorio)'</td></tr></table><p>
|
||||
<td width="100%"><strong>FLAGS</strong> = <gflags.FlagValues instance><br>
|
||||
<strong>__author__</strong> = 'jcgregorio@google.com (Joe Gregorio)'</td></tr></table><p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
<tr bgcolor="#7799ee">
|
||||
<td colspan=3 valign=bottom> <br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="apiclient.html"><font color="#ffffff">apiclient</font></a>.oauth</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/apiclient/oauth.py">/home/jcgregorio/projects/apiary/apiclient/oauth.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/oauth.py">/usr/local/google/home/jcgregorio/projects/apiclient/apiclient/oauth.py</a></font></td></tr></table>
|
||||
<p><tt>Utilities for OAuth.<br>
|
||||
<br>
|
||||
Utilities for making it easier to work with OAuth.</tt></p>
|
||||
|
||||
@@ -54,8 +54,9 @@ Args:<br>
|
||||
useCase: string, One of CommerceSearchUseCase, ProductSearchUseCase<br>
|
||||
debug_searchRequest: boolean, Google Internal<br>
|
||||
facets_useGcsConfig: boolean, Whether to return facet information as configured in the GCS account<br>
|
||||
boostBy: string, Boosting specification<br>
|
||||
debug_enableLogging: boolean, Google Internal<br>
|
||||
boostBy: string, Boosting specification<br>
|
||||
safe: boolean, Whether safe search is enabled. Default: true<br>
|
||||
maxResults: integer, Maximum number of results to return<br>
|
||||
categories_enabled: boolean, Whether to return category information<br>
|
||||
categories_useGcsConfig: boolean, This parameter is currently ignored<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong>httplib2</strong></big></big> (version $Rev$)</font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/httplib2/__init__.py">/home/jcgregorio/projects/apiary/httplib2/__init__.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/httplib2/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/httplib2/__init__.py</a></font></td></tr></table>
|
||||
<p></p>
|
||||
<p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="httplib2.html"><font color="#ffffff">httplib2</font></a>.socks</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/httplib2/socks.py">/home/jcgregorio/projects/apiary/httplib2/socks.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/httplib2/socks.py">/usr/local/google/home/jcgregorio/projects/apiclient/httplib2/socks.py</a></font></td></tr></table>
|
||||
<p><tt>SocksiPy - Python SOCKS module.<br>
|
||||
Version 1.00<br>
|
||||
<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="oauth2client.html"><font color="#ffffff">oauth2client</font></a>.appengine</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/oauth2client/appengine.py">/home/jcgregorio/projects/apiary/oauth2client/appengine.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/appengine.py">/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/appengine.py</a></font></td></tr></table>
|
||||
<p><tt>Utilities for Google App Engine<br>
|
||||
<br>
|
||||
Utilities for making it easier to use OAuth 2.0 on Google App Engine.</tt></p>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="oauth2client.html"><font color="#ffffff">oauth2client</font></a>.client</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/oauth2client/client.py">/home/jcgregorio/projects/apiary/oauth2client/client.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/client.py">/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/client.py</a></font></td></tr></table>
|
||||
<p><tt>An OAuth 2.0 client<br>
|
||||
<br>
|
||||
Tools for interacting with OAuth 2.0 protected<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="oauth2client.html"><font color="#ffffff">oauth2client</font></a>.django_orm</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/oauth2client/django_orm.py">/home/jcgregorio/projects/apiary/oauth2client/django_orm.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/django_orm.py">/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/django_orm.py</a></font></td></tr></table>
|
||||
<p><tt>OAuth 2.0 utilities for Django.<br>
|
||||
<br>
|
||||
Utilities for using OAuth 2.0 in conjunction with<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="oauth2client.html"><font color="#ffffff">oauth2client</font></a>.file</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/oauth2client/file.py">/home/jcgregorio/projects/apiary/oauth2client/file.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/file.py">/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/file.py</a></font></td></tr></table>
|
||||
<p><tt>Utilities for OAuth.<br>
|
||||
<br>
|
||||
Utilities for making it easier to work with OAuth 2.0<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong>oauth2client</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/oauth2client/__init__.py">/home/jcgregorio/projects/apiary/oauth2client/__init__.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/__init__.py</a></font></td></tr></table>
|
||||
<p></p>
|
||||
<p>
|
||||
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="section">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="oauth2client.html"><font color="#ffffff">oauth2client</font></a>.tools</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/oauth2client/tools.py">/home/jcgregorio/projects/apiary/oauth2client/tools.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/tools.py">/usr/local/google/home/jcgregorio/projects/apiclient/oauth2client/tools.py</a></font></td></tr></table>
|
||||
<p><tt>Command-line tools for authenticating via OAuth 2.0<br>
|
||||
<br>
|
||||
Do the OAuth 2.0 Web Server dance for a command line application. Stores the<br>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<td valign=bottom> <br>
|
||||
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong>uritemplate</strong></big></big></font></td
|
||||
><td align=right valign=bottom
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/jcgregorio/projects/apiary/uritemplate/__init__.py">/home/jcgregorio/projects/apiary/uritemplate/__init__.py</a></font></td></tr></table>
|
||||
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/usr/local/google/home/jcgregorio/projects/apiclient/uritemplate/__init__.py">/usr/local/google/home/jcgregorio/projects/apiclient/uritemplate/__init__.py</a></font></td></tr></table>
|
||||
<p><tt># Early, and incomplete implementation of -04.<br>
|
||||
#</tt></p>
|
||||
<p>
|
||||
|
||||
@@ -21,18 +21,12 @@ from apiclient.model import LoggingJsonModel
|
||||
|
||||
|
||||
FLAGS = gflags.FLAGS
|
||||
|
||||
FLAGS.dump_request_response = True
|
||||
logger = logging.getLogger()
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
def main(argv):
|
||||
try:
|
||||
argv = FLAGS(argv)
|
||||
except gflags.FlagsError, e:
|
||||
print '%s\\nUsage: %s ARGS\\n%s' % (e, argv[0], FLAGS)
|
||||
sys.exit(1)
|
||||
|
||||
service = build('translate', 'v2',
|
||||
developerKey='AIzaSyAQIKv_gwnob-YNrXV2stnY86GSGY81Zr0',
|
||||
model=LoggingJsonModel())
|
||||
|
||||
@@ -35,6 +35,7 @@ except ImportError:
|
||||
from apiclient.discovery import build, key2param
|
||||
from apiclient.http import HttpMock
|
||||
from apiclient.errors import HttpError
|
||||
from apiclient.errors import InvalidJsonError
|
||||
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
|
||||
@@ -56,8 +57,8 @@ class DiscoveryErrors(unittest.TestCase):
|
||||
try:
|
||||
buzz = build('buzz', 'v1', self.http)
|
||||
self.fail("should have raised an exception over malformed JSON.")
|
||||
except HttpError, e:
|
||||
self.assertEqual(e.content, "{\n")
|
||||
except InvalidJsonError:
|
||||
pass
|
||||
|
||||
|
||||
class Discovery(unittest.TestCase):
|
||||
|
||||
@@ -27,42 +27,7 @@ import httplib2
|
||||
from apiclient.errors import HttpError
|
||||
|
||||
|
||||
def fake_response(data, headers):
|
||||
return httplib2.Response(headers), data
|
||||
|
||||
|
||||
class Error(unittest.TestCase):
|
||||
"""Test handling of error bodies."""
|
||||
|
||||
def test_json_body(self):
|
||||
"""Test a nicely formed, expected error response."""
|
||||
resp, content = fake_response(json_error_content,
|
||||
{'status':'400', 'content-type': 'application/json'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "country is required">')
|
||||
|
||||
def test_bad_json_body(self):
|
||||
"""Test handling of bodies with invalid json."""
|
||||
resp, content = fake_response('{',
|
||||
{'status':'400', 'content-type': 'application/json'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "{">')
|
||||
|
||||
def test_missing_message_json_body(self):
|
||||
"""Test handling of bodies with missing expected 'message' element."""
|
||||
resp, content = fake_response('{}',
|
||||
{'status':'400', 'content-type': 'application/json'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "{}">')
|
||||
|
||||
def test_non_json(self):
|
||||
"""Test handling of non-JSON bodies"""
|
||||
resp, content = fake_response('NOT OK', {'status':'400'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "Ok">')
|
||||
|
||||
|
||||
json_error_content = """
|
||||
JSON_ERROR_CONTENT = """
|
||||
{
|
||||
"error": {
|
||||
"errors": [
|
||||
@@ -80,3 +45,43 @@ json_error_content = """
|
||||
}
|
||||
"""
|
||||
|
||||
def fake_response(data, headers):
|
||||
return httplib2.Response(headers), data
|
||||
|
||||
|
||||
class Error(unittest.TestCase):
|
||||
"""Test handling of error bodies."""
|
||||
|
||||
def test_json_body(self):
|
||||
"""Test a nicely formed, expected error response."""
|
||||
resp, content = fake_response(JSON_ERROR_CONTENT,
|
||||
{'status':'400', 'content-type': 'application/json'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "country is required">')
|
||||
|
||||
def test_bad_json_body(self):
|
||||
"""Test handling of bodies with invalid json."""
|
||||
resp, content = fake_response('{',
|
||||
{'status':'400', 'content-type': 'application/json'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "{">')
|
||||
|
||||
def test_with_uri(self):
|
||||
"""Test handling of passing in the request uri."""
|
||||
resp, content = fake_response('{',
|
||||
{'status':'400', 'content-type': 'application/json'})
|
||||
error = HttpError(resp, content, 'http://example.org')
|
||||
self.assertEqual(str(error), '<HttpError 400 when requesting http://example.org returned "{">')
|
||||
|
||||
def test_missing_message_json_body(self):
|
||||
"""Test handling of bodies with missing expected 'message' element."""
|
||||
resp, content = fake_response('{}',
|
||||
{'status':'400', 'content-type': 'application/json'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "{}">')
|
||||
|
||||
def test_non_json(self):
|
||||
"""Test handling of non-JSON bodies"""
|
||||
resp, content = fake_response('NOT OK', {'status':'400'})
|
||||
error = HttpError(resp, content)
|
||||
self.assertEqual(str(error), '<HttpError 400 "Ok">')
|
||||
|
||||
Reference in New Issue
Block a user