diff --git a/apiclient/ext/appengine.py b/apiclient/ext/appengine.py index a780d0e..ead4d29 100644 --- a/apiclient/ext/appengine.py +++ b/apiclient/ext/appengine.py @@ -88,3 +88,48 @@ class OAuthCredentialsProperty(db.Property): 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: + 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() diff --git a/samples/new_project_template/apiclient b/samples/new_project_template/apiclient new file mode 120000 index 0000000..24fe0bc --- /dev/null +++ b/samples/new_project_template/apiclient @@ -0,0 +1 @@ +../appengine/apiclient \ No newline at end of file diff --git a/samples/new_project_template/app.yaml b/samples/new_project_template/app.yaml new file mode 100644 index 0000000..33f1a19 --- /dev/null +++ b/samples/new_project_template/app.yaml @@ -0,0 +1,9 @@ +application: jcg-testing-01 +version: 1 +runtime: python +api_version: 1 + +handlers: +- url: .* + script: main.py + diff --git a/samples/new_project_template/httplib2 b/samples/new_project_template/httplib2 new file mode 120000 index 0000000..4cd2774 --- /dev/null +++ b/samples/new_project_template/httplib2 @@ -0,0 +1 @@ +../appengine/httplib2 \ No newline at end of file diff --git a/samples/new_project_template/index.yaml b/samples/new_project_template/index.yaml new file mode 100644 index 0000000..a3b9e05 --- /dev/null +++ b/samples/new_project_template/index.yaml @@ -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. diff --git a/samples/new_project_template/main.py b/samples/new_project_template/main.py new file mode 100755 index 0000000..026400e --- /dev/null +++ b/samples/new_project_template/main.py @@ -0,0 +1,99 @@ +#!/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 apiclient.ext.appengine import FlowThreeLeggedProperty +from apiclient.ext.appengine import OAuthCredentialsProperty +from apiclient.ext.appengine import StorageByKeyName +from apiclient.oauth import FlowThreeLegged +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 util +from google.appengine.ext.webapp.util import login_required + +APP_ID = os.environ['APPLICATION_ID'] +STEP2_URI = 'http://%s.appspot.com/auth_return' % APP_ID + + +class Credentials(db.Model): + credentials = OAuthCredentialsProperty() + + +class MainHandler(webapp.RequestHandler): + + @login_required + def get(self): + user = users.get_current_user() + storage = StorageByKeyName(Credentials, user.user_id(), 'credentials') + credentials = storage.get() + http = httplib2.Http() + if credentials: + http = credentials.authorize(http) + service = build("buzz", "v1", http=http) + + if credentials: + followers = service.people().list(userId='@me', groupId='@followers').execute() + self.response.out.write('Hello, you have %s followers!' % + followers['totalResults']) + else: + flow = FlowThreeLegged(service.auth_discovery(), + consumer_key='anonymous', + consumer_secret='anonymous', + user_agent='%s/1.0' % APP_ID, + domain='anonymous', + scope='https://www.googleapis.com/auth/buzz', + xoauth_displayname='App Name') + + authorize_url = flow.step1_get_authorize_url(STEP2_URI) + 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() + storage = StorageByKeyName(Credentials, user.user_id(), 'credentials') + flow = pickle.loads(memcache.get(user.user_id())) + credentials = flow.step2_exchange(self.request.params) + storage.put(credentials) + self.redirect("/") + + +def main(): + application = webapp.WSGIApplication( + [ + ('/', MainHandler), + ('/auth_return', OAuthHandler) + ], + debug=True) + util.run_wsgi_app(application) + + +if __name__ == '__main__': + main() diff --git a/samples/new_project_template/oauth2 b/samples/new_project_template/oauth2 new file mode 120000 index 0000000..ee61c25 --- /dev/null +++ b/samples/new_project_template/oauth2 @@ -0,0 +1 @@ +../appengine/oauth2 \ No newline at end of file diff --git a/samples/new_project_template/uritemplate b/samples/new_project_template/uritemplate new file mode 120000 index 0000000..1c98e41 --- /dev/null +++ b/samples/new_project_template/uritemplate @@ -0,0 +1 @@ +../appengine/uritemplate \ No newline at end of file