# 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. """Google App Engine utilities helper. Classes that directly require App Engine's ndb library. Provided as a separate module in case of failure to import ndb while other App Engine libraries are present. """ import logging from google.appengine.ext import ndb from oauth2client import client NDB_KEY = ndb.Key """Key constant used by :mod:`oauth2client.contrib.appengine`.""" NDB_MODEL = ndb.Model """Model constant used by :mod:`oauth2client.contrib.appengine`.""" _LOGGER = logging.getLogger(__name__) class SiteXsrfSecretKeyNDB(ndb.Model): """NDB Model for storage for the sites XSRF secret key. Since this model uses the same kind as SiteXsrfSecretKey, it can be used interchangeably. This simply provides an NDB model for interacting with the same data the DB model interacts with. There should only be one instance stored of this model, the one used for the site. """ secret = ndb.StringProperty() @classmethod def _get_kind(cls): """Return the kind name for this class.""" return 'SiteXsrfSecretKey' class FlowNDBProperty(ndb.PickleProperty): """App Engine NDB datastore Property for Flow. Serves the same purpose as the DB FlowProperty, but for NDB models. Since PickleProperty inherits from BlobProperty, the underlying representation of the data in the datastore will be the same as in the DB case. Utility property that allows easy storage and retrieval of an oauth2client.Flow """ def _validate(self, value): """Validates a value as a proper Flow object. Args: value: A value to be set on the property. Raises: TypeError if the value is not an instance of Flow. """ _LOGGER.info('validate: Got type %s', type(value)) if value is not None and not isinstance(value, client.Flow): raise TypeError( 'Property {0} must be convertible to a flow ' 'instance; received: {1}.'.format(self._name, value)) class CredentialsNDBProperty(ndb.BlobProperty): """App Engine NDB datastore Property for Credentials. Serves the same purpose as the DB CredentialsProperty, but for NDB models. Since CredentialsProperty stores data as a blob and this inherits from BlobProperty, the data in the datastore will be the same as in the DB case. Utility property that allows easy storage and retrieval of Credentials and subclasses. """ def _validate(self, value): """Validates a value as a proper credentials object. Args: value: A value to be set on the property. Raises: TypeError if the value is not an instance of Credentials. """ _LOGGER.info('validate: Got type %s', type(value)) if value is not None and not isinstance(value, client.Credentials): raise TypeError( 'Property {0} must be convertible to a credentials ' 'instance; received: {1}.'.format(self._name, value)) def _to_base_type(self, value): """Converts our validated value to a JSON serialized string. Args: value: A value to be set in the datastore. Returns: A JSON serialized version of the credential, else '' if value is None. """ if value is None: return '' else: return value.to_json() def _from_base_type(self, value): """Converts our stored JSON string back to the desired type. Args: value: A value from the datastore to be converted to the desired type. Returns: A deserialized Credentials (or subclass) object, else None if the value can't be parsed. """ if not value: return None try: # Uses the from_json method of the implied class of value credentials = client.Credentials.new_from_json(value) except ValueError: credentials = None return credentials class CredentialsNDBModel(ndb.Model): """NDB Model for storage of OAuth 2.0 Credentials Since this model uses the same kind as CredentialsModel and has a property which can serialize and deserialize Credentials correctly, it can be used interchangeably with a CredentialsModel to access, insert and delete the same entities. This simply provides an NDB model for interacting with the same data the DB model interacts with. Storage of the model is keyed by the user.user_id(). """ credentials = CredentialsNDBProperty() @classmethod def _get_kind(cls): """Return the kind name for this class.""" return 'CredentialsModel'