diff --git a/appengine/standard/firebase/firetactoe/creds.json b/appengine/standard/firebase/firetactoe/creds.json deleted file mode 120000 index 86538f43fcb..00000000000 --- a/appengine/standard/firebase/firetactoe/creds.json +++ /dev/null @@ -1 +0,0 @@ -../../../../../channels-api-deprecation-1e958c196e99.json \ No newline at end of file diff --git a/appengine/standard/firebase/firetactoe/firetactoe.py b/appengine/standard/firebase/firetactoe/firetactoe.py index 9d9e8c99a49..ec84abf90c8 100644 --- a/appengine/standard/firebase/firetactoe/firetactoe.py +++ b/appengine/standard/firebase/firetactoe/firetactoe.py @@ -75,7 +75,6 @@ def _get_firebase_db_url(): # Memoize the authorized http, to avoid fetching new access tokens @lru_cache() -# [START authed_http] def _get_http(): """Provides an authed http object.""" http = httplib2.Http() @@ -85,10 +84,8 @@ def _get_http(): _FIREBASE_SCOPES) creds.authorize(http) return http -# [END authed_http] -# [START send_msg] def _send_firebase_message(u_id, message=None): """Updates data in firebase. If a message is provided, then it updates the data at /channels/ with the message using the PATCH @@ -101,10 +98,8 @@ def _send_firebase_message(u_id, message=None): return _get_http().request(url, 'PATCH', body=message) else: return _get_http().request(url, 'DELETE') -# [END send_msg] -# [START create_token] def create_custom_token(uid, valid_minutes=60): """Create a secure token for the given id. @@ -135,7 +130,6 @@ def create_custom_token(uid, valid_minutes=60): # Sign the jwt using the built in app_identity service return '{}.{}'.format(to_sign, base64.b64encode( app_identity.sign_blob(to_sign)[1])) -# [END create_token] class Game(ndb.Model): @@ -152,20 +146,16 @@ def to_json(self): d['winningBoard'] = d.pop('winning_board') return json.dumps(d, default=lambda user: user.user_id()) - # [START send_update] def send_update(self): """Updates Firebase's copy of the board.""" message = self.to_json() # send updated game state to user X _send_firebase_message( - self.userX.user_id() + self.key.id(), - message=message) + self.userX.user_id() + self.key.id(), message=message) # send updated game state to user O if self.userO: _send_firebase_message( - self.userO.user_id() + self.key.id(), - message=message) - # [END send_update] + self.userO.user_id() + self.key.id(), message=message) def _check_win(self): if self.moveX: @@ -187,7 +177,6 @@ def _check_win(self): if ' ' not in self.board: self.winner = 'Noone' - # [START make_move] def make_move(self, position, user): # If the user is a player, and it's their move if (user in (self.userX, self.userO)) and ( @@ -202,7 +191,6 @@ def make_move(self, position, user): self.put() self.send_update() return - # [END make_move] # [START move_route] @@ -224,8 +212,7 @@ def delete(): if not game: return 'Game not found', 400 user = users.get_current_user() - _send_firebase_message( - user.user_id() + game.key.id(), message=None) + _send_firebase_message(user.user_id() + game.key.id(), message=None) return '' # [END route_delete] @@ -266,8 +253,7 @@ def main_page(): # Firebase's data security rules will be able to decrypt the # token and prevent unauthorized access client_auth_token = create_custom_token(channel_id) - _send_firebase_message( - channel_id, message=game.to_json()) + _send_firebase_message(channel_id, message=game.to_json()) # game_link is a url that you can open in another browser to play # against this player diff --git a/appengine/standard/firebase/firetactoe/rest_api.py b/appengine/standard/firebase/firetactoe/rest_api.py new file mode 100644 index 00000000000..a067953a8f1 --- /dev/null +++ b/appengine/standard/firebase/firetactoe/rest_api.py @@ -0,0 +1,114 @@ +# Copyright 2016 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. + +"""Demonstration of the Firebase REST API in Python""" + +try: + from functools import lru_cache +except ImportError: + from functools32 import lru_cache +# [START rest_writing_data] +import json + +import httplib2 +from oauth2client.client import GoogleCredentials + +_FIREBASE_SCOPES = [ + 'https://www.googleapis.com/auth/firebase.database', + 'https://www.googleapis.com/auth/userinfo.email'] + + +# Memoize the authorized http, to avoid fetching new access tokens +@lru_cache() +def _get_http(): + """Provides an authed http object.""" + http = httplib2.Http() + # Use application default credentials to make the Firebase calls + # https://firebase.google.com/docs/reference/rest/database/user-auth + creds = GoogleCredentials.get_application_default().create_scoped( + _FIREBASE_SCOPES) + creds.authorize(http) + return http + + +def firebase_put(path, value=None): + """Writes data to Firebase. + + An HTTP PUT writes an entire object at the given database path. Updates to + fields cannot be performed without overwriting the entire object + + Args: + path - the url to the Firebase object to write. + value - a json string. + """ + response, content = _get_http().request(path, method='PUT', body=value) + return json.loads(content) + + +def firebase_patch(path, value=None): + """Update specific children or fields + + An HTTP PATCH allows specific children or fields to be updated without + overwriting the entire object. + + Args: + path - the url to the Firebase object to write. + value - a json string. + """ + response, content = _get_http().request(path, method='PATCH', body=value) + return json.loads(content) + + +def firebase_post(path, value=None): + """Add an object to an existing list of data. + + An HTTP POST allows an object to be added to an existing list of data. + A successful request will be indicated by a 200 OK HTTP status code. The + response content will contain a new attribute "name" which is the key for + the child added. + + Args: + path - the url to the Firebase list to append to. + value - a json string. + """ + response, content = _get_http().request(path, method='POST', body=value) + return json.loads(content) +# [END rest_writing_data] + + +def firebase_get(path): + """Read the data at the given path. + + An HTTP GET request allows reading of data at a particular path. + A successful request will be indicated by a 200 OK HTTP status code. + The response will contain the data being retrieved. + + Args: + path - the url to the Firebase object to read. + """ + response, content = _get_http().request(path, method='GET') + return json.loads(content) + + +def firebase_delete(path): + """Removes the data at a particular path. + + An HTTP DELETE removes the data at a particular path. A successful request + will be indicated by a 200 OK HTTP status code with a response containing + JSON null. + + Args: + path - the url to the Firebase object to delete. + """ + response, content = _get_http().request(path, method='DELETE')