Skip to content

Commit 2494669

Browse files
committed
Merge pull request #53 from GoogleCloudPlatform/bq-3lo-gae
Move bigquery 3lo sample on GAE to github.
2 parents e7c99cf + 7219497 commit 2494669

File tree

9 files changed

+198
-0
lines changed

9 files changed

+198
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## Google App Engine accessing BigQuery using OAuth2
2+
3+
This sample demonstrates [authenticating to BigQuery in App Engine using OAuth2](https://cloud.google.com/bigquery/authorization).
4+
5+
### Setup
6+
7+
* To install dependencies for this sample, run:
8+
9+
$ pip install -t lib -r requirements.txt
10+
11+
* You must then update `main.py` and replace `<myproject_id>` with your project's
12+
id.
13+
* You'll need a client id from your project - instructions
14+
[here](https://cloud-dot-devsite.googleplex.com/bigquery/authorization#clientsecrets).
15+
Once you've downloaded the client's json secret, copy it to the root directory
16+
of this project, and rename it to `client_secrets.json`.
17+
* You can then run the sample on your development server:
18+
19+
$ dev_appserver.py .

bigquery/samples/appengine_auth/__init__.py

Whitespace-only changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
application: cloud-samples-tests
2+
version: 1
3+
runtime: python27
4+
api_version: 1
5+
threadsafe: yes
6+
7+
handlers:
8+
- url: .*
9+
script: main.app
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from google.appengine.ext import vendor
2+
3+
# Add any libraries installed in the "lib" folder.
4+
vendor.add('lib')
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{"web":{
2+
"client_id":"NOTE: this is just a placeholder for unit tests. See the README for what to replace this file with.",
3+
"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"]}}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
# [START all]
15+
"""Sample appengine app demonstrating 3-legged oauth."""
16+
import json
17+
import os
18+
19+
from googleapiclient.discovery import build
20+
21+
from oauth2client.appengine import OAuth2DecoratorFromClientSecrets
22+
23+
import webapp2
24+
25+
26+
# The project id whose datasets you'd like to list
27+
PROJECTID = '<myproject_id>'
28+
29+
# Create the method decorator for oauth.
30+
decorator = OAuth2DecoratorFromClientSecrets(
31+
os.path.join(os.path.dirname(__file__), 'client_secrets.json'),
32+
scope='https://www.googleapis.com/auth/bigquery')
33+
34+
# Create the bigquery api client
35+
service = build('bigquery', 'v2')
36+
37+
38+
class MainPage(webapp2.RequestHandler):
39+
40+
@decorator.oauth_required
41+
def get(self):
42+
"""Lists the datasets in PROJECTID"""
43+
http = decorator.http()
44+
datasets = service.datasets()
45+
46+
response = datasets.list(projectId=PROJECTID).execute(http)
47+
48+
self.response.out.write('<h3>Datasets.list raw response:</h3>')
49+
self.response.out.write('<pre>%s</pre>' %
50+
json.dumps(response, sort_keys=True, indent=4,
51+
separators=(',', ': ')))
52+
53+
54+
# Create the webapp2 application
55+
app = webapp2.WSGIApplication([
56+
('/', MainPage),
57+
# Create the endpoint to receive oauth flow callbacks
58+
(decorator.callback_path, decorator.callback_handler())
59+
], debug=True)
60+
# [END all]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
google-api-python-client
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"datasets": [
3+
{
4+
"datasetReference": {
5+
"datasetId": "test_dataset_java",
6+
"projectId": "cloud-samples-tests"
7+
},
8+
"id": "cloud-samples-tests:test_dataset_java",
9+
"kind": "bigquery#dataset"
10+
}
11+
],
12+
"etag": "\"ZduQht1tG1odVP6IPm66xfuN2eI/HmGRlylAN_zCB6N4JDeX_XDO0R0\"",
13+
"kind": "bigquery#datasetList"
14+
}

bigquery/tests/test_appengine_auth.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Copyright 2015 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
import re
17+
18+
from apiclient.http import HttpMock
19+
20+
from bigquery.samples.appengine_auth import main
21+
22+
import mock
23+
24+
import tests
25+
26+
import webapp2
27+
28+
29+
RESOURCE_PATH = os.path.join(
30+
os.path.abspath(os.path.dirname(__file__)), 'resources')
31+
32+
33+
class TestAuthSample(tests.DatastoreTestbedCase, tests.CloudBaseTest):
34+
35+
def setUp(self):
36+
tests.DatastoreTestbedCase.setUp(self)
37+
tests.CloudBaseTest.setUp(self)
38+
39+
self.testbed.init_user_stub()
40+
41+
def loginUser(self, email='[email protected]', id='123', is_admin=False):
42+
self.testbed.setup_env(
43+
user_email=email,
44+
user_id=id,
45+
user_is_admin='1' if is_admin else '0',
46+
overwrite=True)
47+
48+
def test_anonymous_get(self):
49+
request = webapp2.Request.blank('/')
50+
response = request.get_response(main.app)
51+
52+
# Should redirect to login
53+
self.assertEqual(response.status_int, 302)
54+
self.assertRegexpMatches(response.headers['Location'],
55+
r'.*accounts.*Login.*')
56+
57+
def test_loggedin_get(self):
58+
self.loginUser()
59+
60+
request = webapp2.Request.blank('/')
61+
response = request.get_response(main.app)
62+
63+
# Should redirect to login
64+
self.assertEqual(response.status_int, 302)
65+
self.assertRegexpMatches(response.headers['Location'], r'.*oauth2.*')
66+
67+
@mock.patch.object(main.decorator, 'has_credentials', return_value=True)
68+
def test_oauthed_get(self, *args):
69+
self.loginUser()
70+
71+
request = webapp2.Request.blank('/')
72+
73+
mock_http = HttpMock(
74+
os.path.join(RESOURCE_PATH, 'datasets-list.json'),
75+
{'status': '200'})
76+
with mock.patch.object(main.decorator, 'http', return_value=mock_http):
77+
original_projectid = main.PROJECTID
78+
try:
79+
main.PROJECTID = self.constants['projectId']
80+
response = request.get_response(main.app)
81+
finally:
82+
main.PROJECTID = original_projectid
83+
84+
# Should make the api call
85+
self.assertEqual(response.status_int, 200)
86+
self.assertRegexpMatches(
87+
response.body,
88+
re.compile(r'.*datasets.*datasetReference.*etag.*', re.DOTALL))

0 commit comments

Comments
 (0)