|
14 | 14 | # See the License for the specific language governing permissions and |
15 | 15 | # limitations under the License. |
16 | 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 | 17 | """ |
| 18 | +Sample Google App Engine application that lists the objects in a Google Cloud |
| 19 | +Storage bucket. |
36 | 20 |
|
37 | | -import os |
| 21 | +For more information about Cloud Storage, see README.md in /storage. |
| 22 | +For more information about Google App Engine, see README.md in /appengine. |
| 23 | +""" |
38 | 24 |
|
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 |
| 25 | +import json |
45 | 26 |
|
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' |
| 27 | +from googleapiclient import discovery |
| 28 | +from oauth2client.client import GoogleCredentials |
| 29 | +import webapp2 |
54 | 30 |
|
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 | 31 |
|
| 32 | +# The bucket that will be used to list objects. |
| 33 | +BUCKET_NAME = '<your-bucket-name>' |
59 | 34 |
|
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 |
| 35 | +credentials = GoogleCredentials.get_application_default() |
| 36 | +storage = discovery.build('storage', 'v1', credentials=credentials) |
66 | 37 |
|
67 | 38 |
|
68 | | -class MainHandler(webapp.RequestHandler): |
69 | | - @login_required |
| 39 | +class MainPage(webapp2.RequestHandler): |
70 | 40 | 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} |
| 41 | + response = storage.objects().list(bucket=BUCKET_NAME).execute() |
107 | 42 |
|
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)) |
| 43 | + self.response.write( |
| 44 | + '<h3>Objects.list raw response:</h3>' |
| 45 | + '<pre>{}</pre>'.format( |
| 46 | + json.dumps(response, sort_keys=True, indent=2))) |
115 | 47 |
|
116 | 48 |
|
117 | | -app = webapp.WSGIApplication( |
118 | | - [ |
119 | | - ('/oauth2callback', AuthHandler), |
120 | | - ('/..*', MainHandler) |
121 | | - ], |
122 | | - debug=True) |
| 49 | +app = webapp2.WSGIApplication([ |
| 50 | + ('/', MainPage) |
| 51 | +], debug=True) |
0 commit comments