Skip to content

Commit 5f1dac2

Browse files
author
Jonathan Wayne Parrott
committed
Merge pull request #108 from GoogleCloudPlatform/storage-bucket-lister
Migrating sample.
2 parents 8037a93 + 87653ca commit 5f1dac2

File tree

6 files changed

+181
-0
lines changed

6 files changed

+181
-0
lines changed

appengine/storage/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Google App Engine using Cloud Storage
2+
3+
This sample demonstrates how to use cloud storage from Google App Engine

appengine/storage/__init__.py

Whitespace-only changes.

appengine/storage/app.yaml

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
runtime: python27
2+
threadsafe: yes
3+
api_version: 1
4+
5+
handlers:
6+
- url: /
7+
static_files: index.html
8+
upload: index.html
9+
10+
- url: /favicon.ico
11+
static_files: favicon.ico
12+
upload: favicon.ico
13+
14+
- url: .*
15+
script: main.app
16+
17+
libraries:
18+
- name: jinja2
19+
version: latest

appengine/storage/index.html

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<html>
2+
<head>
3+
<script type="text/javascript">
4+
function getList() {
5+
var bucket_name = self.document.getElementById("bucket_name").value;
6+
location.pathname = bucket_name;
7+
}
8+
</script>
9+
</head>
10+
<body>
11+
<h1>Google Cloud Storage Bucket Lister</h1>
12+
bucket name:
13+
<input id="bucket_name" type="text"/>
14+
<button onclick="getList()">list</button>
15+
</body>
16+
<html>

appengine/storage/listing.html

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<html>
2+
<body>
3+
<h2><a href="http://developer.google.com/storage">Google Cloud Storage</a> Content Listing for Bucket <i>{{ bucket_name }}</i></h2>
4+
<table border="1" cellpadding="5">
5+
<tr bgcolor="#9acd32">
6+
<th>Object Name</th>
7+
<th>Modification Time</th>
8+
<th>Hash</th>
9+
<th>Size</th>
10+
</tr>
11+
{% for obj in items %}
12+
<tr>
13+
<td>{{ obj['name'] }}</td>
14+
<td>{{ obj['media']['timeCreated'] }}</td>
15+
<td>{{ obj['media']['hash'] }}</td>
16+
<td>{{ obj['media']['length'] }}</td>
17+
</tr>
18+
{% endfor %}
19+
</table>
20+
</body>
21+
</html>

appengine/storage/main.py

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2015 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
"""Present formatted listings for Google Cloud Storage buckets.
18+
This Google App Engine application takes a bucket name in the URL path and uses
19+
the Google Cloud Storage JSON API and Google's Python client library to list
20+
the bucket's contents.
21+
For example, if this app is invoked with the URI
22+
http://bucket-list.appspot.com/foo, it would extract the bucket name 'foo' and
23+
issue a request to GCS for its contents. The app formats the listing into an
24+
XML document, which is prepended with a reference to an XSLT style sheet for
25+
human readable presentation.
26+
For more information:
27+
Google APIs Client Library for Python:
28+
<https://code.google.com/p/google-api-python-client/>
29+
Google Cloud Storage JSON API:
30+
<https://developers.google.com/storage/docs/json_api/>
31+
Using OAuth 2.0 for Server to Server Applications:
32+
<https://developers.google.com/accounts/docs/OAuth2ServiceAccount>
33+
App Identity Python API Overview:
34+
<https://code.google.com/appengine/docs/python/appidentity/overview.html>
35+
"""
36+
37+
import os
38+
39+
from apiclient.discovery import build as build_service
40+
from google.appengine.ext import webapp
41+
from google.appengine.ext.webapp.util import login_required
42+
import httplib2
43+
import jinja2
44+
from oauth2client.client import OAuth2WebServerFlow
45+
46+
# NOTE: You must provide a client ID and secret with access to the GCS JSON
47+
# API.
48+
# You can acquire a client ID and secret from the Google Developers Console.
49+
# <https://developers.google.com/console#:access>
50+
CLIENT_ID = ''
51+
CLIENT_SECRET = ''
52+
SCOPE = 'https://www.googleapis.com/auth/devstorage.read_only'
53+
USER_AGENT = 'app-engine-bucket-lister'
54+
55+
# Since we don't plan to use all object attributes, we pass a fields argument
56+
# to specify what the server should return.
57+
FIELDS = 'items(name,media(timeCreated,hash,length))'
58+
59+
60+
def GetBucketName(path):
61+
bucket = path[1:] # Trim the preceding slash
62+
if bucket[-1] == '/':
63+
# Trim final slash, if necessary.
64+
bucket = bucket[:-1]
65+
return bucket
66+
67+
68+
class MainHandler(webapp.RequestHandler):
69+
@login_required
70+
def get(self):
71+
callback = self.request.host_url + '/oauth2callback'
72+
flow = OAuth2WebServerFlow(
73+
client_id=CLIENT_ID,
74+
client_secret=CLIENT_SECRET,
75+
redirect_uri=callback,
76+
access_type='online',
77+
scope=SCOPE,
78+
user_agent=USER_AGENT)
79+
80+
bucket = GetBucketName(self.request.path)
81+
step2_url = flow.step1_get_authorize_url()
82+
# Add state to remember which bucket to list.
83+
self.redirect(step2_url + '&state=%s' % bucket)
84+
85+
86+
class AuthHandler(webapp.RequestHandler):
87+
@login_required
88+
def get(self):
89+
callback = self.request.host_url + '/oauth2callback'
90+
flow = OAuth2WebServerFlow(
91+
client_id=CLIENT_ID,
92+
client_secret=CLIENT_SECRET,
93+
redirect_uri=callback,
94+
scope=SCOPE,
95+
user_agent=USER_AGENT)
96+
97+
# Exchange the code (in self.request.params) for an access token.
98+
credentials = flow.step2_exchange(self.request.params)
99+
http = credentials.authorize(httplib2.Http())
100+
101+
bucket = self.request.get('state')
102+
storage = build_service('storage', 'v1beta1', http=http)
103+
list_response = storage.objects().list(bucket=bucket,
104+
fields=FIELDS).execute()
105+
template_values = {
106+
'items': list_response['items'], 'bucket_name': bucket}
107+
108+
# We use a templating engine to format our output. For more
109+
# information:
110+
# <http://jinja.pocoo.org/docs/>
111+
jinja_env = jinja2.Environment(
112+
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))
113+
template = jinja_env.get_template('listing.html')
114+
self.response.out.write(template.render(template_values))
115+
116+
117+
app = webapp.WSGIApplication(
118+
[
119+
('/oauth2callback', AuthHandler),
120+
('/..*', MainHandler)
121+
],
122+
debug=True)

0 commit comments

Comments
 (0)