| Index: reviewbot/rietveld.py
 | 
| ===================================================================
 | 
| --- reviewbot/rietveld.py	(revision 0)
 | 
| +++ reviewbot/rietveld.py	(revision 0)
 | 
| @@ -0,0 +1,90 @@
 | 
| +# Copyright (c) 2013 The Chromium Authors. All rights reserved.
 | 
| +# Use of this source code is governed by a BSD-style license that can be
 | 
| +# found in the LICENSE file.
 | 
| +
 | 
| +from oauth2client.client import SignedJwtAssertionCredentials
 | 
| +import httplib2
 | 
| +import model.app_config
 | 
| +import urllib
 | 
| +import util
 | 
| +
 | 
| +
 | 
| +EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
 | 
| +
 | 
| +
 | 
| +class RietveldRequestError(Exception):
 | 
| +  """Raised on request errors."""
 | 
| +  pass
 | 
| +
 | 
| +
 | 
| +class Rietveld(object):
 | 
| +  """Implements a Python API to access rietveld via HTTP.
 | 
| +
 | 
| +  Authentication is handled via an OAuth2 access token minted from an RSA key
 | 
| +  associated with a service account (which can be created via the Google API
 | 
| +  console). For this to work, the Rietveld instance to talk to must be
 | 
| +  configured to allow the service account client ID as OAuth2 audience (see
 | 
| +  Rietveld source). Both the RSA key and the server URL are provided via static
 | 
| +  application configuration.
 | 
| +  """
 | 
| +
 | 
| +  def __init__(self):
 | 
| +    self.app_config = model.app_config.get()
 | 
| +
 | 
| +  @util.lazy_property
 | 
| +  def http(self):
 | 
| +    http = httplib2.Http()
 | 
| +
 | 
| +    creds = SignedJwtAssertionCredentials(self.app_config.client_id,
 | 
| +                                          self.app_config.service_account_key,
 | 
| +                                          EMAIL_SCOPE)
 | 
| +    creds.authorize(http)
 | 
| +    return http
 | 
| +
 | 
| +  @util.lazy_property
 | 
| +  def xsrf_token(self):
 | 
| +    return self.make_request('xsrf_token',
 | 
| +                             headers={'X-Requesting-XSRF-Token': 1})
 | 
| +
 | 
| +  def make_request(self, req, *args, **kwargs):
 | 
| +    resp, response = self.http.request(
 | 
| +        '%s/%s' % (self.app_config.server_url, req), *args, **kwargs)
 | 
| +    if resp.status != 200:
 | 
| +      raise RietveldRequestError(
 | 
| +          'Rietveld %s request failed: %s\n%s' %
 | 
| +          (req, resp.status, str(resp)), resp, response)
 | 
| +
 | 
| +    return response
 | 
| +
 | 
| +  def post_data(self, req, payload=None):
 | 
| +    actual_payload = dict(payload or {})
 | 
| +    actual_payload['xsrf_token'] = self.xsrf_token
 | 
| +
 | 
| +    return self.make_request(req, method='POST',
 | 
| +                             body=urllib.urlencode(actual_payload))
 | 
| +
 | 
| +  def post_issue_data(self, issue, req, payload):
 | 
| +    return self.post_data('%s/%s' % (issue, req), payload)
 | 
| +
 | 
| +  def post_comment(self, issue, comment, submit_inline_comments=False):
 | 
| +    publish_payload = {
 | 
| +        'message_only': 0 if submit_inline_comments else 1,
 | 
| +        'send_mail': 1,
 | 
| +        'add_as_reviewer': 0,
 | 
| +        'message': comment,
 | 
| +        'no_redirect': 1,
 | 
| +    }
 | 
| +    self.post_issue_data(issue, 'publish', publish_payload)
 | 
| +
 | 
| +  def add_inline_comment(self, issue_id, patchset_id, patch_id, line, a_or_b,
 | 
| +                         comment):
 | 
| +    comment_payload = {
 | 
| +        'snapshot': 'old' if a_or_b is 'a' else 'new',
 | 
| +        'lineno': line,
 | 
| +        'side': a_or_b,
 | 
| +        'issue': issue_id,
 | 
| +        'patchset': patchset_id,
 | 
| +        'patch': patch_id,
 | 
| +        'text': comment,
 | 
| +    }
 | 
| +    self.post_data('inline_draft', comment_payload)
 | 
| 
 | 
| Property changes on: reviewbot/rietveld.py
 | 
| ___________________________________________________________________
 | 
| Added: svn:eol-style
 | 
|    + LF
 | 
| 
 | 
| 
 |