[mq]: oauth2

This commit is contained in:
Joe Gregorio
2011-01-16 16:46:55 -05:00
parent 89487c620d
commit 695fdc154e
20 changed files with 1078 additions and 4 deletions

View File

@@ -1,5 +1,3 @@
#!/usr/bin/python2.4
#
# Copyright 2010 Google Inc. All Rights Reserved.
"""Utilities for OAuth.
@@ -10,10 +8,14 @@ Utilities for making it easier to work with OAuth.
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
import copy
import datetime
import httplib2
import logging
import oauth2 as oauth
import urllib
import logging
import urlparse
from anyjson import simplejson
try:
from urlparse import parse_qs, parse_qsl
@@ -77,6 +79,9 @@ class Credentials(object):
"""
_abstract()
class Flow(object):
"""Base class for all Flow objects."""
pass
class OAuthCredentials(Credentials):
"""Credentials object for OAuth 1.0a
@@ -148,7 +153,7 @@ class OAuthCredentials(Credentials):
return http
class FlowThreeLegged(object):
class FlowThreeLegged(Flow):
"""Does the Three Legged Dance for OAuth 1.0a.
"""
@@ -249,3 +254,4 @@ class FlowThreeLegged(object):
oauth_params['oauth_token_secret'])
return OAuthCredentials(consumer, token, self.user_agent)

0
oauth2client/__init__.py Normal file
View File

135
oauth2client/appengine.py Normal file
View File

@@ -0,0 +1,135 @@
# Copyright (C) 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Utilities for Google App Engine
Utilities for making it easier to use OAuth 2.0
on Google App Engine.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
import pickle
from google.appengine.ext import db
from client import Credentials
from client import Flow
class FlowProperty(db.Property):
"""Utility property that allows easy
storage and retreival of an
oauth2client.Flow"""
# Tell what the user type is.
data_type = Flow
# For writing to datastore.
def get_value_for_datastore(self, model_instance):
flow = super(FlowProperty,
self).get_value_for_datastore(model_instance)
return db.Blob(pickle.dumps(flow))
# For reading from datastore.
def make_value_from_datastore(self, value):
if value is None:
return None
return pickle.loads(value)
def validate(self, value):
if value is not None and not isinstance(value, Flow):
raise BadValueError('Property %s must be convertible '
'to a FlowThreeLegged instance (%s)' %
(self.name, value))
return super(FlowProperty, self).validate(value)
def empty(self, value):
return not value
class CredentialsProperty(db.Property):
"""Utility property that allows easy
storage and retrieval of
oath2client.Credentials
"""
# Tell what the user type is.
data_type = Credentials
# For writing to datastore.
def get_value_for_datastore(self, model_instance):
cred = super(CredentialsProperty,
self).get_value_for_datastore(model_instance)
return db.Blob(pickle.dumps(cred))
# For reading from datastore.
def make_value_from_datastore(self, value):
if value is None:
return None
return pickle.loads(value)
def validate(self, value):
if value is not None and not isinstance(value, Credentials):
raise BadValueError('Property %s must be convertible '
'to an Credentials instance (%s)' %
(self.name, value))
return super(CredentialsProperty, self).validate(value)
def empty(self, value):
return not value
class StorageByKeyName(object):
"""Store and retrieve a single credential to and from
the App Engine datastore.
This Storage helper presumes the Credentials
have been stored as a CredenialsProperty
on a datastore model class, and that entities
are stored by key_name.
"""
def __init__(self, model, key_name, property_name):
"""Constructor for Storage.
Args:
model: db.Model, model class
key_name: string, key name for the entity that has the credentials
property_name: string, name of the property that is an CredentialsProperty
"""
self.model = model
self.key_name = key_name
self.property_name = property_name
def get(self):
"""Retrieve Credential from datastore.
Returns:
oauth2client.Credentials
"""
entity = self.model.get_or_insert(self.key_name)
credential = getattr(entity, self.property_name)
if credential and hasattr(credential, 'set_store'):
credential.set_store(self.put)
return credential
def put(self, credentials):
"""Write a Credentials to the datastore.
Args:
credentials: Credentials, the credentials to store.
"""
entity = self.model.get_or_insert(self.key_name)
setattr(entity, self.property_name, credentials)
entity.put()

326
oauth2client/client.py Normal file
View File

@@ -0,0 +1,326 @@
# Copyright 2010 Google Inc. All Rights Reserved.
"""An OAuth 2.0 client
Tools for interacting with OAuth 2.0 protected
resources.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
import copy
import datetime
import httplib2
import logging
import urllib
import urlparse
try: # pragma: no cover
import simplejson
except ImportError: # pragma: no cover
try:
# Try to import from django, should work on App Engine
from django.utils import simplejson
except ImportError:
# Should work for Python2.6 and higher.
import json as simplejson
try:
from urlparse import parse_qsl
except ImportError:
from cgi import parse_qsl
class Error(Exception):
"""Base error for this module."""
pass
class RequestError(Error):
"""Error occurred during request."""
pass
class MissingParameter(Error):
pass
def _abstract():
raise NotImplementedError('You need to override this function')
class Credentials(object):
"""Base class for all Credentials objects.
Subclasses must define an authorize() method
that applies the credentials to an HTTP transport.
"""
def authorize(self, http):
"""Take an httplib2.Http instance (or equivalent) and
authorizes it for the set of credentials, usually by
replacing http.request() with a method that adds in
the appropriate headers and then delegates to the original
Http.request() method.
"""
_abstract()
class Flow(object):
"""Base class for all Flow objects."""
pass
class OAuth2Credentials(Credentials):
"""Credentials object for OAuth 2.0
Credentials can be applied to an httplib2.Http object
using the authorize() method, which then signs each
request from that object with the OAuth 2.0 access token.
OAuth2Credentials objects may be safely pickled and unpickled.
"""
def __init__(self, access_token, client_id, client_secret, refresh_token,
token_expiry, token_uri, user_agent):
"""Create an instance of OAuth2Credentials
This constructor is not usually called by the user, instead
OAuth2Credentials objects are instantiated by
the OAuth2WebServerFlow.
Args:
token_uri: string, URI of token endpoint
client_id: string, client identifier
client_secret: string, client secret
access_token: string, access token
token_expiry: datetime, when the access_token expires
refresh_token: string, refresh token
user_agent: string, The HTTP User-Agent to provide for this application.
Notes:
store: callable, a callable that when passed a Credential
will store the credential back to where it came from.
This is needed to store the latest access_token if it
has expired and been refreshed.
"""
self.access_token = access_token
self.client_id = client_id
self.client_secret = client_secret
self.refresh_token = refresh_token
self.store = None
self.token_expiry = token_expiry
self.token_uri = token_uri
self.user_agent = user_agent
def set_store(self, store):
"""Set the storage for the credential.
Args:
store: callable, a callable that when passed a Credential
will store the credential back to where it came from.
This is needed to store the latest access_token if it
has expired and been refreshed.
"""
self.store = store
def __getstate__(self):
"""Trim the state down to something that can be pickled.
"""
d = copy.copy(self.__dict__)
del d['store']
return d
def __setstate__(self, state):
"""Reconstitute the state of the object from being pickled.
"""
self.__dict__.update(state)
self.store = None
def _refresh(self, http_request):
"""Refresh the access_token using the refresh_token.
Args:
http: An instance of httplib2.Http.request
or something that acts like it.
"""
body = urllib.urlencode({
'grant_type': 'refresh_token',
'client_id': self.client_id,
'client_secret': self.client_secret,
'refresh_token' : self.refresh_token
})
headers = {
'user-agent': self.user_agent,
'content-type': 'application/x-www-form-urlencoded'
}
resp, content = http_request(self.token_uri, method='POST', body=body, headers=headers)
if resp.status == 200:
# TODO(jcgregorio) Raise an error if loads fails?
d = simplejson.loads(content)
self.access_token = d['access_token']
self.refresh_token = d.get('refresh_token', self.refresh_token)
if 'expires_in' in d:
self.token_expiry = datetime.timedelta(seconds = int(d['expires_in'])) + datetime.datetime.now()
else:
self.token_expiry = None
if self.store is not None:
self.store(self)
else:
logging.error('Failed to retrieve access token: %s' % content)
raise RequestError('Invalid response %s.' % resp['status'])
def authorize(self, http):
"""
Args:
http: An instance of httplib2.Http
or something that acts like it.
Returns:
A modified instance of http that was passed in.
Example:
h = httplib2.Http()
h = credentials.authorize(h)
You can't create a new OAuth
subclass of httplib2.Authenication because
it never gets passed the absolute URI, which is
needed for signing. So instead we have to overload
'request' with a closure that adds in the
Authorization header and then calls the original version
of 'request()'.
"""
request_orig = http.request
# The closure that will replace 'httplib2.Http.request'.
def new_request(uri, method='GET', body=None, headers=None,
redirections=httplib2.DEFAULT_MAX_REDIRECTS,
connection_type=None):
"""Modify the request headers to add the appropriate
Authorization header."""
if headers == None:
headers = {}
if ((self.token_expiry is not None) and (self.token_expiry <= datetime.datetime.now())):
logging.info("Refreshing because %s <= %s" %(self.token_expiry, datetime.datetime.now()))
self._refresh(request_orig)
headers['authorization'] = 'WRAP access_token=' + self.access_token
if 'user-agent' in headers:
headers['user-agent'] = self.user_agent + ' ' + headers['user-agent']
else:
headers['user-agent'] = self.user_agent
resp, content = request_orig(uri, method, body, headers,
redirections, connection_type)
if resp.status == 401 and 'invalid_token' in resp.get('www-authenticate', ''):
logging.info("Refreshing because we got a 401")
self._refresh(request_orig)
return request_orig(uri, method, body, headers,
redirections, connection_type)
else:
return (resp, content)
http.request = new_request
return http
class OAuth2WebServerFlow(Flow):
"""Does the Web Server Flow for OAuth 2.0.
OAuth2Credentials objects may be safely pickled and unpickled.
"""
def __init__(self, client_id, client_secret, scope, user_agent,
authorization_uri='https://www.google.com/accounts/o8/oauth2/authorization',
token_uri='https://www.google.com/accounts/o8/oauth2/token',
**kwargs):
"""Constructor for OAuth2WebServerFlow
Args:
client_id: string, client identifier
client_secret: string client secret
scope: string, scope of the credentials being requested
user_agent: string, HTTP User-Agent to provide for this application.
authorization_uri: string, URI for authorization endpoint
token_uri: string, URI for token endpoint
**kwargs: dict, The keyword arguments are all optional and required
parameters for the OAuth calls.
"""
self.client_id = client_id
self.client_secret = client_secret
self.scope = scope
self.user_agent = user_agent
self.authorization_uri = authorization_uri
self.token_uri = token_uri
self.params = kwargs
self.redirect_uri = None
def step1_get_authorize_url(self, redirect_uri='oob'):
"""Returns a URI to redirect to the provider.
Args:
redirect_uri: string, Either the string 'oob' for a non-web-based
application, or a URI that handles the callback from
the authorization server.
If redirect_uri is 'oob' then pass in the
generated verification code to step2_exchange,
otherwise pass in the query parameters received
at the callback uri to step2_exchange.
"""
self.redirect_uri = redirect_uri
query = {
'response_type': 'code',
'client_id': self.client_id,
'redirect_uri': redirect_uri,
'scope': self.scope,
}
query.update(self.params)
parts = list(urlparse.urlparse(self.authorization_uri))
query.update(dict(parse_qsl(parts[4]))) # 4 is the index of the query part
parts[4] = urllib.urlencode(query)
return urlparse.urlunparse(parts)
def step2_exchange(self, code):
"""Exhanges a code for OAuth2Credentials.
Args:
code: string or dict, either the code as a string, or a dictionary
of the query parameters to the redirect_uri, which contains
the code.
"""
if not (isinstance(code, str) or isinstance(code, unicode)):
code = code['code']
body = urllib.urlencode({
'grant_type': 'authorization_code',
'client_id': self.client_id,
'client_secret': self.client_secret,
'code': code,
'redirect_uri': self.redirect_uri,
'scope': self.scope
})
headers = {
'user-agent': self.user_agent,
'content-type': 'application/x-www-form-urlencoded'
}
h = httplib2.Http()
resp, content = h.request(self.token_uri, method='POST', body=body, headers=headers)
if resp.status == 200:
# TODO(jcgregorio) Raise an error if simplejson.loads fails?
d = simplejson.loads(content)
access_token = d['access_token']
refresh_token = d.get('refresh_token', None)
token_expiry = None
if 'expires_in' in d:
token_expiry = datetime.datetime.now() + datetime.timedelta(seconds = int(d['expires_in']))
logging.info('Successfully retrieved access token: %s' % content)
return OAuth2Credentials(access_token, self.client_id, self.client_secret,
refresh_token, token_expiry, self.token_uri,
self.user_agent)
else:
logging.error('Failed to retrieve access token: %s' % content)
raise RequestError('Invalid response %s.' % resp['status'])

View File

@@ -0,0 +1,38 @@
from django.db import models
class CredentialsField(models.Field):
__metaclass__ = models.SubfieldBase
def db_type(self):
return 'VARCHAR'
def to_python(self, value):
if value is None:
return None
if isinstance(value, oauth2client.Credentials):
return value
return pickle.loads(base64.b64decode(value))
def get_db_prep_value(self, value):
return base64.b64encode(pickle.dumps(value))
class FlowField(models.Field):
__metaclass__ = models.SubfieldBase
def db_type(self):
return 'VARCHAR'
def to_python(self, value):
print "In to_python", value
if value is None:
return None
if isinstance(value, oauth2client.Flow):
return value
return pickle.loads(base64.b64decode(value))
def get_db_prep_value(self, value):
return base64.b64encode(pickle.dumps(value))

42
oauth2client/file.py Normal file
View File

@@ -0,0 +1,42 @@
# Copyright 2010 Google Inc. All Rights Reserved.
"""Utilities for OAuth.
Utilities for making it easier to work with OAuth 2.0
credentials.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
import pickle
class Storage(object):
"""Store and retrieve a single credential to and from a file."""
def __init__(self, filename):
self.filename = filename
def get(self):
"""Retrieve Credential from file.
Returns:
apiclient.oauth.Credentials
"""
f = open(self.filename, 'r')
credentials = pickle.loads(f.read())
f.close()
credentials.set_store(self.put)
return credentials
def put(self, credentials):
"""Write a pickled Credentials to file.
Args:
credentials: Credentials, the credentials to store.
"""
f = open(self.filename, 'w')
f.write(pickle.dumps(credentials))
f.close()

136
oauth2client/tools.py Normal file
View File

@@ -0,0 +1,136 @@
# Copyright (C) 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Command-line tools for authenticating via OAuth 2.0
Do the OAuth 2.0 Web Server dance for
a command line application. Stores the generated
credentials in a common file that is used by
other example apps in the same directory.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
__all__ = ["run"]
import socket
import sys
import BaseHTTPServer
import logging
from optparse import OptionParser
from oauth2client.file import Storage
try:
from urlparse import parse_qsl
except ImportError:
from cgi import parse_qsl
# TODO(jcgregorio)
# - docs
# - error handling
# - oob when implemented
class ClientRedirectServer(BaseHTTPServer.HTTPServer):
"""A server to handle OAuth 2.0 redirects back to localhost.
Waits for a single request and parses the query parameters
into query_params and then stops serving.
"""
query_params = {}
class ClientRedirectHandler(BaseHTTPServer.BaseHTTPRequestHandler):
"""A handler for OAuth 2.0 redirects back to localhost.
Waits for a single request and parses the query parameters
into the servers query_params and then stops serving.
"""
def do_GET(s):
"""Handle a GET request
Checks the query parameters and if an error
occurred print a message of failure, otherwise
indicate success.
"""
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
query = s.path.split('?', 1)[-1]
query = dict(parse_qsl(query))
s.server.query_params = query
s.wfile.write("<html><head><title>Authentication Status</title></head>")
if 'error' in query:
s.wfile.write("<body><p>The authentication request failed.</p>")
else:
s.wfile.write("<body><p>You have successfully authenticated</p>")
s.wfile.write("</body></html>")
def log_message(self, format, *args):
"""Do not log messages to stdout while running as a command line program."""
pass
def run(flow, filename):
"""Core code for a command-line application.
"""
parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
default=filename, help="write credentials to FILE", metavar="FILE")
parser.add_option("-p", "--no_local_web_server", dest="localhost",
action="store_false",
default=True,
help="Do not run a web server on localhost to handle redirect URIs")
parser.add_option("-w", "--local_web_server", dest="localhost",
action="store_true",
default=True,
help="Run a web server on localhost to handle redirect URIs")
(options, args) = parser.parse_args()
host_name = 'localhost'
port_numbers = [8080, 8090]
if options.localhost:
server_class = BaseHTTPServer.HTTPServer
try:
port_number = port_numbers[0]
httpd = server_class((host_name, port_number), ClientRedirectHandler)
except socket.error:
port_number = port_numbers[1]
try:
httpd = server_class((host_name, port_number), ClientRedirectHandler)
except socket.error:
options.localhost = False
authorize_url = flow.step1_get_authorize_url('http://%s:%s/' % (host_name, port_number))
print 'Go to the following link in your browser:'
print authorize_url
print
if options.localhost:
httpd.handle_request()
if 'error' in httpd.query_params:
sys.exit('Authentication request was rejected.')
if 'code' in httpd.query_params:
code = httpd.query_params['code']
else:
accepted = 'n'
while accepted.lower() == 'n':
accepted = raw_input('Have you authorized me? (y/n) ')
code = raw_input('What is the verification code? ').strip()
credentials = flow.step2_exchange(code)
Storage(options.filename).put(credentials)
print "You have successfully authenticated."

View File

@@ -0,0 +1 @@
../../../apiclient/

View File

@@ -0,0 +1,16 @@
application: m-buzz
version: 1
runtime: python
api_version: 1
handlers:
- url: /static
static_dir: static
- url: /google8f1adb368b7bd14c.html
upload: google8f1adb368b7bd14c.html
static_files: static/google8f1adb368b7bd14c.html
- url: .*
script: main.py

View File

@@ -0,0 +1 @@
../../../httplib2/

View File

@@ -0,0 +1,11 @@
indexes:
# AUTOGENERATED
# This index.yaml is automatically updated whenever the dev_appserver
# detects that a new type of query is run. If you want to manage the
# index.yaml file manually, remove the above marker line (the line
# saying "# AUTOGENERATED"). If you want to manage some indexes
# manually, move them above the marker line. The index.yaml file is
# automatically uploaded to the admin console when you next deploy
# your application using appcfg.py.

View File

@@ -0,0 +1,104 @@
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
import httplib2
import logging
import os
import pickle
from apiclient.discovery import build
from oauth2client.appengine import CredentialsProperty
from oauth2client.appengine import StorageByKeyName
from oauth2client.client import OAuth2WebServerFlow
from google.appengine.api import memcache
from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp.util import login_required
class Credentials(db.Model):
credentials = CredentialsProperty()
class MainHandler(webapp.RequestHandler):
@login_required
def get(self):
user = users.get_current_user()
credentials = StorageByKeyName(Credentials, user.user_id(), 'credentials').get()
if credentials:
http = httplib2.Http()
http = credentials.authorize(http)
p = build("buzz", "v1", http=http)
activities = p.activities()
activitylist = activities.list(scope='@consumption',
userId='@me').execute()
path = os.path.join(os.path.dirname(__file__), 'welcome.html')
logout = users.create_logout_url('/')
self.response.out.write(
template.render(
path, {'activitylist': activitylist,
'logout': logout
}))
else:
flow = OAuth2WebServerFlow(
client_id='anonymous',
client_secret='anonymous',
scope='https://www.googleapis.com/auth/buzz',
user_agent='buzz-cmdline-sample/1.0',
domain='anonymous',
xoauth_displayname='Google App Engine Example App')
callback = self.request.relative_url('/auth_return')
authorize_url = flow.step1_get_authorize_url(callback)
memcache.set(user.user_id(), pickle.dumps(flow))
self.redirect(authorize_url)
class OAuthHandler(webapp.RequestHandler):
@login_required
def get(self):
user = users.get_current_user()
flow = pickle.loads(memcache.get(user.user_id()))
if flow:
credentials = flow.step2_exchange(self.request.params)
StorageByKeyName(Credentials, user.user_id(), 'credentials').put(credentials)
self.redirect("/")
else:
pass
def main():
application = webapp.WSGIApplication(
[
('/', MainHandler),
('/auth_return', OAuthHandler)
],
debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1 @@
../../../oauth2client/

View File

@@ -0,0 +1 @@
../../../simplejson/

View File

@@ -0,0 +1 @@
../../../uritemplate/

View File

@@ -0,0 +1,29 @@
<html>
<head>
<title>Buzz Stuff</title>
<style type=text/css>
td { vertical-align: top; padding: 0.5em }
img { border:0 }
</style>
</head>
<body>
<p><a href="{{ logout }}">Logout</a></p>
<table border=0>
{% for item in activitylist.items %}
<tr valign=top>
<td>
<a href="{{ item.actor.profileUrl }}"><img
src="{{ item.actor.thumbnailUrl }}"></a><br>
<a href="{{ item.actor.profileUrl }}">{{ item.actor.name }}</a></td>
<td>
{{ item.object.content }}
</td>
<td>
<a href="{{ item.object.links.alternate.0.href }}"><img
src="/static/go.png"></a>
</td>
</tr>
{% endfor %}
</table>
</body>
</html>

View File

@@ -0,0 +1,71 @@
#!/usr/bin/python2.4
# -*- coding: utf-8 -*-
#
# Copyright 2010 Google Inc. All Rights Reserved.
"""Simple command-line example for Buzz.
Command-line application that retrieves the users
latest content and then adds a new entry.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
from apiclient.discovery import build
from oauth2client.file import Storage
import httplib2
import pickle
import pprint
# Uncomment the next line to get very detailed logging
#httplib2.debuglevel = 4
def main():
credentials = Storage('buzz.dat').get()
http = httplib2.Http()
http = credentials.authorize(http)
p = build("buzz", "v1", http=http, developerKey="AIzaSyDRRpR3GS1F1_jKNNM9HCNd2wJQyPG3oN0")
activities = p.activities()
# Retrieve the first two activities
activitylist = activities.list(max_results='2', scope='@self', userId='@me').execute()
print "Retrieved the first two activities"
# Retrieve the next two activities
if activitylist:
activitylist = activities.list_next(activitylist).execute()
print "Retrieved the next two activities"
# Add a new activity
new_activity_body = {
"data": {
'title': 'Testing insert',
'object': {
'content': u'Just a short note to show that insert is working. ☄',
'type': 'note'}
}
}
activity = activities.insert(userId='@me', body=new_activity_body).execute()
print "Added a new activity"
activitylist = activities.list(max_results='2', scope='@self', userId='@me').execute()
# Add a comment to that activity
comment_body = {
"data": {
"content": "This is a comment"
}
}
item = activitylist['items'][0]
comment = p.comments().insert(
userId=item['actor']['id'], postId=item['id'], body=comment_body
).execute()
print 'Added a comment to the new activity'
pprint.pprint(comment)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,37 @@
# Copyright (C) 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Do the OAuth 2.0 Web Server dance.
Do the OAuth 2.0 Web Server dance for
a command line application. Store the generated
credentials in a common file that is used by
other example apps in the same directory.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run
flow = OAuth2WebServerFlow(
client_id='anonymous',
client_secret='anonymous',
scope='https://www.googleapis.com/auth/buzz',
user_agent='buzz-cmdline-sample/1.0',
domain='anonymous',
xoauth_displayname='Buzz Client Example App'
)
run(flow, 'buzz.dat')

View File

@@ -0,0 +1,83 @@
#!/usr/bin/python2.4
# -*- coding: utf-8 -*-
#
# Copyright 2010 Google Inc. All Rights Reserved.
"""Simple command-line example for Buzz.
Command-line application that retrieves the users
latest content and then adds a new entry.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
from apiclient.discovery import build
from oauth2client.file import Storage
import httplib2
# Uncomment to get low level HTTP logging
#httplib2.debuglevel = 4
# Uncomment to get logging
#import logging
#logging.basicConfig(level=logging.DEBUG)
def main():
credentials = Storage('moderator.dat').get()
http = httplib2.Http()
http = credentials.authorize(http)
p = build("moderator", "v1", http=http)
series_body = {
"data": {
"description": "Share and rank tips for eating healthy and cheap!",
"name": "Eating Healthy & Cheap",
"videoSubmissionAllowed": False
}
}
series = p.series().insert(body=series_body).execute()
print "Created a new series"
topic_body = {
"data": {
"description": "Share your ideas on eating healthy!",
"name": "Ideas",
"presenter": "liz"
}
}
topic = p.topics().insert(seriesId=series['id']['seriesId'],
body=topic_body).execute()
print "Created a new topic"
submission_body = {
"data": {
"attachmentUrl": "http://www.youtube.com/watch?v=1a1wyc5Xxpg",
"attribution": {
"displayName": "Bashan",
"location": "Bainbridge Island, WA"
},
"text": "Charlie Ayers @ Google"
}
}
submission = p.submissions().insert(seriesId=topic['id']['seriesId'],
topicId=topic['id']['topicId'], body=submission_body).execute()
print "Inserted a new submisson on the topic"
vote_body = {
"data": {
"vote": "PLUS"
}
}
p.votes().insert(seriesId=topic['id']['seriesId'],
submissionId=submission['id']['submissionId'],
body=vote_body)
print "Voted on the submission"
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,35 @@
# Copyright (C) 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Do the OAuth 2.0 Web Server dance.
Do the OAuth 2.0 Web Server dance for
a command line application. Store the generated
credentials in a common file that is used by
other example apps in the same directory.
"""
__author__ = 'jcgregorio@google.com (Joe Gregorio)'
from oauth2client.client import OAuth2WebServerFlow
from oauth2client.tools import run
flow = OAuth2WebServerFlow(
client_id='anonymous',
client_secret='anonymous',
scope='https://www.googleapis.com/auth/moderator',
user_agent='moderator-cmdline-sample/1.0',
xoauth_displayname='Moderator Client Example App')
run(flow, 'moderator.dat')