From 7219497a974069104616b8be4b1504dfa3dcf9a0 Mon Sep 17 00:00:00 2001 From: Jerjou Cheng Date: Fri, 17 Jul 2015 11:08:26 -0700 Subject: [PATCH] Move bigquery 3lo sample on GAE to github. Also, update it to use webapp2. --- bigquery/samples/appengine_auth/README.md | 19 ++++ bigquery/samples/appengine_auth/__init__.py | 0 bigquery/samples/appengine_auth/app.yaml | 9 ++ .../appengine_auth/appengine_config.py | 4 + .../appengine_auth/client_secrets.json | 3 + bigquery/samples/appengine_auth/main.py | 60 +++++++++++++ .../samples/appengine_auth/requirements.txt | 1 + bigquery/tests/resources/datasets-list.json | 14 +++ bigquery/tests/test_appengine_auth.py | 88 +++++++++++++++++++ 9 files changed, 198 insertions(+) create mode 100644 bigquery/samples/appengine_auth/README.md create mode 100644 bigquery/samples/appengine_auth/__init__.py create mode 100644 bigquery/samples/appengine_auth/app.yaml create mode 100644 bigquery/samples/appengine_auth/appengine_config.py create mode 100644 bigquery/samples/appengine_auth/client_secrets.json create mode 100644 bigquery/samples/appengine_auth/main.py create mode 100644 bigquery/samples/appengine_auth/requirements.txt create mode 100644 bigquery/tests/resources/datasets-list.json create mode 100644 bigquery/tests/test_appengine_auth.py diff --git a/bigquery/samples/appengine_auth/README.md b/bigquery/samples/appengine_auth/README.md new file mode 100644 index 000000000000..396f1c1be4a8 --- /dev/null +++ b/bigquery/samples/appengine_auth/README.md @@ -0,0 +1,19 @@ +## Google App Engine accessing BigQuery using OAuth2 + +This sample demonstrates [authenticating to BigQuery in App Engine using OAuth2](https://cloud.google.com/bigquery/authorization). + +### Setup + +* To install dependencies for this sample, run: + + $ pip install -t lib -r requirements.txt + +* You must then update `main.py` and replace `` with your project's + id. +* You'll need a client id from your project - instructions + [here](https://cloud-dot-devsite.googleplex.com/bigquery/authorization#clientsecrets). + Once you've downloaded the client's json secret, copy it to the root directory + of this project, and rename it to `client_secrets.json`. +* You can then run the sample on your development server: + + $ dev_appserver.py . diff --git a/bigquery/samples/appengine_auth/__init__.py b/bigquery/samples/appengine_auth/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/bigquery/samples/appengine_auth/app.yaml b/bigquery/samples/appengine_auth/app.yaml new file mode 100644 index 000000000000..6fde9bebf2fb --- /dev/null +++ b/bigquery/samples/appengine_auth/app.yaml @@ -0,0 +1,9 @@ +application: cloud-samples-tests +version: 1 +runtime: python27 +api_version: 1 +threadsafe: yes + +handlers: +- url: .* + script: main.app diff --git a/bigquery/samples/appengine_auth/appengine_config.py b/bigquery/samples/appengine_auth/appengine_config.py new file mode 100644 index 000000000000..4fdc5d2b60fc --- /dev/null +++ b/bigquery/samples/appengine_auth/appengine_config.py @@ -0,0 +1,4 @@ +from google.appengine.ext import vendor + +# Add any libraries installed in the "lib" folder. +vendor.add('lib') diff --git a/bigquery/samples/appengine_auth/client_secrets.json b/bigquery/samples/appengine_auth/client_secrets.json new file mode 100644 index 000000000000..767caf645e63 --- /dev/null +++ b/bigquery/samples/appengine_auth/client_secrets.json @@ -0,0 +1,3 @@ +{"web":{ + "client_id":"NOTE: this is just a placeholder for unit tests. See the README for what to replace this file with.", + "auth_uri":"TODO","token_uri":"TODO","auth_provider_x509_cert_url":"TODO","client_email":"","client_x509_cert_url":"","client_secret":"TODO","redirect_uris":["TODO","TODO"],"javascript_origins":["TODO","TODO"]}} diff --git a/bigquery/samples/appengine_auth/main.py b/bigquery/samples/appengine_auth/main.py new file mode 100644 index 000000000000..9f96acaf1b4d --- /dev/null +++ b/bigquery/samples/appengine_auth/main.py @@ -0,0 +1,60 @@ +# Copyright 2015 Google Inc. All rights reserved. +# +# 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. +# [START all] +"""Sample appengine app demonstrating 3-legged oauth.""" +import json +import os + +from googleapiclient.discovery import build + +from oauth2client.appengine import OAuth2DecoratorFromClientSecrets + +import webapp2 + + +# The project id whose datasets you'd like to list +PROJECTID = '' + +# Create the method decorator for oauth. +decorator = OAuth2DecoratorFromClientSecrets( + os.path.join(os.path.dirname(__file__), 'client_secrets.json'), + scope='https://www.googleapis.com/auth/bigquery') + +# Create the bigquery api client +service = build('bigquery', 'v2') + + +class MainPage(webapp2.RequestHandler): + + @decorator.oauth_required + def get(self): + """Lists the datasets in PROJECTID""" + http = decorator.http() + datasets = service.datasets() + + response = datasets.list(projectId=PROJECTID).execute(http) + + self.response.out.write('

Datasets.list raw response:

') + self.response.out.write('
%s
' % + json.dumps(response, sort_keys=True, indent=4, + separators=(',', ': '))) + + +# Create the webapp2 application +app = webapp2.WSGIApplication([ + ('/', MainPage), + # Create the endpoint to receive oauth flow callbacks + (decorator.callback_path, decorator.callback_handler()) +], debug=True) +# [END all] diff --git a/bigquery/samples/appengine_auth/requirements.txt b/bigquery/samples/appengine_auth/requirements.txt new file mode 100644 index 000000000000..d8055e00cd9a --- /dev/null +++ b/bigquery/samples/appengine_auth/requirements.txt @@ -0,0 +1 @@ +google-api-python-client diff --git a/bigquery/tests/resources/datasets-list.json b/bigquery/tests/resources/datasets-list.json new file mode 100644 index 000000000000..c9a3877c4dba --- /dev/null +++ b/bigquery/tests/resources/datasets-list.json @@ -0,0 +1,14 @@ +{ + "datasets": [ + { + "datasetReference": { + "datasetId": "test_dataset_java", + "projectId": "cloud-samples-tests" + }, + "id": "cloud-samples-tests:test_dataset_java", + "kind": "bigquery#dataset" + } + ], + "etag": "\"ZduQht1tG1odVP6IPm66xfuN2eI/HmGRlylAN_zCB6N4JDeX_XDO0R0\"", + "kind": "bigquery#datasetList" +} diff --git a/bigquery/tests/test_appengine_auth.py b/bigquery/tests/test_appengine_auth.py new file mode 100644 index 000000000000..9539c2ce351b --- /dev/null +++ b/bigquery/tests/test_appengine_auth.py @@ -0,0 +1,88 @@ +# Copyright 2015 Google Inc. All rights reserved. +# +# 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. + +import os +import re + +from apiclient.http import HttpMock + +from bigquery.samples.appengine_auth import main + +import mock + +import tests + +import webapp2 + + +RESOURCE_PATH = os.path.join( + os.path.abspath(os.path.dirname(__file__)), 'resources') + + +class TestAuthSample(tests.DatastoreTestbedCase, tests.CloudBaseTest): + + def setUp(self): + tests.DatastoreTestbedCase.setUp(self) + tests.CloudBaseTest.setUp(self) + + self.testbed.init_user_stub() + + def loginUser(self, email='user@example.com', id='123', is_admin=False): + self.testbed.setup_env( + user_email=email, + user_id=id, + user_is_admin='1' if is_admin else '0', + overwrite=True) + + def test_anonymous_get(self): + request = webapp2.Request.blank('/') + response = request.get_response(main.app) + + # Should redirect to login + self.assertEqual(response.status_int, 302) + self.assertRegexpMatches(response.headers['Location'], + r'.*accounts.*Login.*') + + def test_loggedin_get(self): + self.loginUser() + + request = webapp2.Request.blank('/') + response = request.get_response(main.app) + + # Should redirect to login + self.assertEqual(response.status_int, 302) + self.assertRegexpMatches(response.headers['Location'], r'.*oauth2.*') + + @mock.patch.object(main.decorator, 'has_credentials', return_value=True) + def test_oauthed_get(self, *args): + self.loginUser() + + request = webapp2.Request.blank('/') + + mock_http = HttpMock( + os.path.join(RESOURCE_PATH, 'datasets-list.json'), + {'status': '200'}) + with mock.patch.object(main.decorator, 'http', return_value=mock_http): + original_projectid = main.PROJECTID + try: + main.PROJECTID = self.constants['projectId'] + response = request.get_response(main.app) + finally: + main.PROJECTID = original_projectid + + # Should make the api call + self.assertEqual(response.status_int, 200) + self.assertRegexpMatches( + response.body, + re.compile(r'.*datasets.*datasetReference.*etag.*', re.DOTALL))