|
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