class Users(model.Model): user_id = model.StringProperty() email = model.StringProperty() token = model.StringProperty() def generate_token(cls, token_length): u = uuid.uuid4() return u.bytes.encode("base64")[:token_length] generate_token = classmethod(generate_token) def test_pilot_id(cls, id): user = Users.query(Users.email == id).get() if user is None: return -1 else: return user.user_id test_pilot_id = classmethod(test_pilot_id) def test_user_login(cls, id, pw): user = Users.query(Users.email == id, Users.token == pw).get() if user is None: return None else: return user.user_id test_user_login = classmethod(test_user_login)
class EnkiModelApp(model.Model): user_id = model.IntegerProperty() name = model.StringProperty() secret = model.StringProperty() time_created = model.DateTimeProperty(auto_now_add=True) @classmethod def exist_by_name(cls, name): count = cls.query(cls.name == name).count(1) return count > 0 @classmethod def count_by_user_id(cls, user_id): return cls.query(cls.user_id == user_id).count() @classmethod def fetch_by_user_id(cls, user_id): list = cls.query(cls.user_id == user_id).order( cls.time_created).fetch() return list @classmethod def exist_by_app_id_app_secret(cls, app_id, app_secret): item = ndb.Key(cls, int(app_id)).get() if item and item.secret == app_secret: return True return False
class EnkiModelTokenEmailRollback(model.Model): #=== MODEL ==================================================================== token = model.StringProperty() email = model.StringProperty() user_id = model.IntegerProperty() # ndb user ID time_created = model.DateTimeProperty(auto_now_add=True) #=== QUERIES ================================================================== @classmethod def get_by_user_id_email(cls, user_id, email): return cls.query(ndb.AND(cls.user_id == user_id, cls.email == email)).get() @classmethod def get_by_token(cls, token): return cls.query(cls.token == token).get() @classmethod def fetch_keys_by_user_id(cls, user_id): return cls.query(cls.user_id == user_id).fetch(keys_only=True) @classmethod def fetch_keys_by_user_id_time(cls, user_id, time_created): return cls.query( ndb.AND(cls.time_created >= time_created, cls.user_id == user_id)).fetch(keys_only=True)
class KindPropertyNamePropertyTypeStat(BaseKindStatistic): """Statistic on (kind, property_name, property_type) tuples in Cloud Datastore. There is an instance of the KindPropertyNamePropertyTypeStat for every (kind, property_name, property_type) tuple in the application's datastore. Attributes: property_type: the property type associated with the statistic instance. property_name: the name of the property associated with the statistic instance. builtin_index_bytes: the number of bytes taken up to store builtin-in index entries builtin_index_count: the number of built-in index entries. """ STORED_KIND_NAME = '__Stat_PropertyType_PropertyName_Kind__' property_type = model.StringProperty() property_name = model.StringProperty() builtin_index_bytes = model.IntegerProperty(default=0) builtin_index_count = model.IntegerProperty(default=0)
class EnkiModelDisplayName( model.Model ): user_id = model.IntegerProperty() prefix = model.StringProperty() # prefix e.g. 'Jane' prefix_lower = model.ComputedProperty(lambda self: self.prefix.lower()) # lowercase prefix e.g. "jane" suffix = model.StringProperty() # suffix e.g. '#1234' => full display name = 'Jane#1234' current = model.BooleanProperty( default = True ) time_created = model.DateTimeProperty( auto_now_add = True )
class NotificationToken(ndb.Model): android = 0 ios = 1 winPhone = 2 userId = model.IntegerProperty() token = model.StringProperty() email = model.StringProperty() kind = model.IntegerProperty()
class EnkiModelRestAPIDataStore(model.Model): user_id = model.IntegerProperty() app_id = model.StringProperty() data_type = model.StringProperty() data_id = model.StringProperty() data_payload = model.JsonProperty() time_expires = model.DateTimeProperty(auto_now_add=False) read_access = model.StringProperty( choices=['private', 'friends', 'public'], default='private')
class EnkiModelUser(model.Model): #=== MODEL ==================================================================== # if logged in through enki auth, otherwise null email = model.StringProperty() # unique password = model.StringProperty() # if logged in through external provider at least once, otherwise null. Format "provider:userId" auth_ids_provider = model.StringProperty(repeated=True) # unique roles = model.StringProperty(repeated=True) time_created = model.DateTimeProperty(auto_now_add=True) time_updated = model.DateTimeProperty(auto_now=True) #=== QUERIES ================================================================== @classmethod def count(cls): count = EnkiModelUser.query().count() return count @classmethod def get_key_by_email(cls, email): return cls.query(cls.email == email).get(keys_only=True) @classmethod def get_by_email(cls, email): return cls.query(cls.email == email).get() @classmethod def exist_by_auth_id(cls, auth_id): count = cls.query(cls.auth_ids_provider == auth_id).count(1) return count > 0 @classmethod def get_by_auth_id(cls, auth_id): return cls.query(cls.auth_ids_provider == auth_id).get() #=== UTILITIES ================================================================ @classmethod def exist_by_email(cls, email): if email and email != 'removed': count = cls.query(cls.email == email).count(1) return count > 0 return False @classmethod def has_password_by_email(cls, email): user = cls.get_by_email(email) if user.password: return True return False
class EnkiModelUser(model.Model): # if logged in through enki auth, otherwise null email = model.StringProperty() # unique password = model.StringProperty() # if logged in through external provider at least once, otherwise null. Format "provider:userId" auth_ids_provider = model.StringProperty(repeated=True) # unique # other time_created = model.DateTimeProperty(auto_now_add=True) time_updated = model.DateTimeProperty(auto_now=True)
class EnkiModelForum(model.Model): title = model.StringProperty() description = model.StringProperty() group = model.StringProperty() # group of forums order = model.IntegerProperty( default=0) # sort the forums (within a group) num_threads = model.IntegerProperty( default=0) # number of threads in the forum num_posts = model.IntegerProperty( default=0) # number of posts in the forum's threads time_created = model.DateTimeProperty(auto_now_add=True)
class AcarsFlight(model.Model): flight_id = model.StringProperty() user_id = model.StringProperty() acars_id = model.IntegerProperty() aircraft_type = model.StringProperty() flight_number = model.StringProperty() flight_type = model.StringProperty() flight_plan = model.StringProperty(repeated=True) departure = model.StringProperty() destination = model.StringProperty() flight_path = model.LocalStructuredProperty(FlightPosition, repeated=True) def add_flight(self): self.put() def active_flights_for_user(self, user_id, limit=20, offset=0): flights = AcarsFlight.query(AcarsFlight.user_id == user_id).fetch( limit, offset=offset) active_flights = [] for flight in flights: position = AcarsPosition.query( AcarsPosition.flight_id == flight.flight_id, AcarsPosition.message_type == 'ZZ').get() if position is None: active_flights.append(flight) return active_flights active_flights_for_user = classmethod(active_flights_for_user)
class AcarsFlightData(model.Model): flight_number = model.StringProperty() aircraft = model.StringProperty() departure = model.StringProperty() destination = model.StringProperty() alternate = model.StringProperty() route = model.StringProperty() altitude = model.StringProperty() pax = model.StringProperty() cargo = model.StringProperty() rules = model.StringProperty() def add_flight_data(self): self.put_async()
class EnkiModelRestAPITokenVerify( EnkiModelTokenVerify ): app_id = model.StringProperty() app_secret = model.StringProperty() @classmethod def get_by_user_id_token( cls, user_id, token ): entity = cls.query( ndb.AND( cls.user_id == user_id, cls.token == token )).get() return entity @classmethod def exist_by_user_id_token_app_secret( cls, user_id, token, app_secret ): count = cls.query( ndb.AND( cls.user_id == user_id, cls.token == token, cls.app_secret == app_secret )).count( 1 ) return count > 0
class PropertyTypeStat(BaseStatistic): """An aggregate of all properties across the entire application by type. There is an instance of the PropertyTypeStat for every property type (google.appengine.api.datastore_types._PROPERTY_TYPES) in use by the application in its datastore. Attributes: property_type: the property type associated with the statistic instance. entity_bytes: the number of bytes taken up to store the statistic in Cloud Datastore minus the cost of storing indices. builtin_index_bytes: the number of bytes taken up to store builtin-in index entries builtin_index_count: the number of built-in index entries. """ STORED_KIND_NAME = '__Stat_PropertyType__' property_type = model.StringProperty() entity_bytes = model.IntegerProperty(default=0) builtin_index_bytes = model.IntegerProperty(default=0) builtin_index_count = model.IntegerProperty(default=0)
class Config(ndb.Model): Name = model.StringProperty() Value = model.StringProperty() @classmethod def min_server_version_allowed(cls): kvp = cls.query(cls.Name == 'min_server_version').get() if not kvp: kvp = cls() kvp.Name = 'min_server_version' kvp.Value = settings.config['min_version'] kvp.put() if float(kvp.Value) < float(settings.config['min_version']): kvp.Value = settings.config['min_version'] kvp.put() return kvp.Value
class NDBTestModel(ndb_model.Model): @classmethod def _get_kind(cls): """ Use the existing TestModel entities. """ return 'TestModel' prop1 = ndb_model.StringProperty()
class EnkiModelSummary(model.Model): #=== MODEL ==================================================================== name = model.StringProperty() count = model.IntegerProperty() time_created = model.DateTimeProperty(auto_now_add=True) #=== UTILITIES ================================================================ @classmethod def create(cls, name, count): cls(name=name, count=count).put_async() @classmethod def csv(cls): list = cls.query().order(-cls.time_created, cls.name).fetch() result = '"time_created","count","name"\n' for item in list: time_created = '"' + str(item.time_created).replace('"', "''") + '"' count = '"' + str(item.count) + '"' name = '"' + str(item.name).replace('"', "''") + '"' result += ','.join([time_created, count, name]) + '\n' return result
class UserToken(BaseUserToken): SUBJECT_BEARER = 'bearer' unique_model = Unique bearer_token_timedelta = timedelta(days=365) refresh_token = model.StringProperty() @classmethod def create(cls, user, subject, token=None): if subject == cls.SUBJECT_BEARER: user = str(user) token = token or security.generate_random_string(entropy=128) # Bearer tokens must be unique on their own, without a user scope. key = cls.get_key('', subject, token) entity = cls( key=key, user=user, subject=subject, token=token, refresh_token=security.generate_random_string(entropy=128)) # Refresh tokens must be unique ok = cls.unique_model.create('%s.refresh_token:%s' % (cls.__name__, entity.refresh_token)) if ok: entity.put() else: logging.warning( 'Unable to create a unique user token for user %s', user) entity = None else: entity = super(UserToken, cls).create(user, subject, token) return entity def expires_at(self): """Returns the datetime after which this token is no longer valid :returns: A datetime object after which this token is no longer valid. """ if self.subject == self.SUBJECT_BEARER: return self.created + self.bearer_token_timedelta return None def is_expired(self): """Whether the token is past its expiry time :returns: True if the token has expired """ return self.expires_at() <= datetime.now()
class EnkiModelThread(model.Model): author = model.IntegerProperty() title = model.StringProperty() forum = model.IntegerProperty() # forum the thread belongs to num_posts = model.IntegerProperty( default=0) # number of posts in the thread time_created = model.DateTimeProperty(auto_now_add=True)
class EnkiModelUserPageData(model.Model): user_id = model.IntegerProperty() route = model.StringProperty() data = model.PickleProperty() @classmethod def get_by_user_id_route(cls, user_id, route): entity = cls.query(ndb.AND(cls.user_id == user_id, cls.route == route)).get() return entity
class AcarsPosition(model.Model): flight_id = model.StringProperty() message_id = model.StringProperty() system_time = model.DateTimeProperty(auto_now_add=True) remote_time = model.DateTimeProperty() message_type = model.StringProperty() flight_status = model.IntegerProperty() waypoint = model.StringProperty() lat_lon = model.GeoPtProperty() hdg = model.IntegerProperty() alt = model.IntegerProperty() vs = model.IntegerProperty() gs = model.IntegerProperty() ias = model.IntegerProperty() tas = model.IntegerProperty() fob = model.IntegerProperty() wnd = model.StringProperty() oat = model.IntegerProperty() tat = model.IntegerProperty() distance_from_dept = model.IntegerProperty() distance_total = model.IntegerProperty() pause_mode = model.IntegerProperty() airport = model.StringProperty() message = model.TextProperty() def add_position(self): self.put_async() if self.lat_lon: acars_flight = AcarsFlight.query( AcarsFlight.flight_id == self.flight_id).get() flight_position = FlightPosition(lat_lon=self.lat_lon, altitude=self.alt) acars_flight.flight_path.append(flight_position) acars_flight.put_async()
class EnkiModelUserPageData(model.Model): #=== MODEL ==================================================================== user_id = model.IntegerProperty() route = model.StringProperty() data = model.PickleProperty() #=== QUERIES ================================================================== @classmethod def get_by_user_id_route(cls, user_id, route): return cls.query(ndb.AND(cls.user_id == user_id, cls.route == route)).get()
class Change(ndb.Model): recordId = model.StringProperty() when = model.DateTimeProperty() subscriberId = model.StringProperty() kind = model.IntegerProperty() CHANGE_VOTE = 1 CHANGE_PLACE = 2 CHANGE_COMMENT = 3 @classmethod def migrate_old_votes_to_changes(cls): count = 0 vote_changes = VoteChange.query() for v in vote_changes: new_change = Change() new_change.kind = cls.CHANGE_VOTE new_change.subscriberId = v.subscriberId new_change.recordId = v.voteId new_change.when = v.when new_change.put() count += 1 return count @classmethod def migrate_old_places_to_changes(cls): count = 0 place_changes = PlaceChange.query() for p in place_changes: new_change = Change() new_change.kind = cls.CHANGE_PLACE new_change.subscriberId = p.subscriberId new_change.recordId = p.placeId new_change.when = p.when new_change.put() count += 1 return count
class EnkiModelRestAPIConnectToken(model.Model): #=== MODEL ==================================================================== token = model.StringProperty() user_id = model.IntegerProperty() time_created = model.DateTimeProperty(auto_now_add=True) #=== CONSTANTS ================================================================ MAX_AGE = 5 # in minutes, duration of a connection token validity #=== QUERIES ================================================================== @classmethod def get_by_user_id_token_valid_age(cls, user_id, token): return cls.query( ndb.AND( cls.user_id == user_id, cls.token == token, cls.time_created > (datetime.datetime.now() - datetime.timedelta(minutes=cls.MAX_AGE)))).get() @classmethod def fetch_by_user(cls, user_id): return cls.query(cls.user_id == user_id).fetch(keys_only=True) @classmethod def fetch_expired(cls): return cls.query( cls.time_created < (datetime.datetime.now() - datetime.timedelta( minutes=cls.MAX_AGE))).fetch(keys_only=True) #=== UTILITIES ================================================================ @classmethod def cleanup_and_get_new_connection_token(cls, user_id): # note: ensure user is logged in and has display name before calling this function if user_id: # delete any existing connect token for the user ndb.delete_multi_async(cls.fetch_by_user(user_id)) # create a new token and return it token = enki.libutil.generate_connect_code() entity = cls(token=token, user_id=int(user_id)) entity.put() return token return None
class KindCompositeIndexStat(BaseStatistic): """Statistic on (kind, composite_index_id) tuples in Cloud Datastore. There is an instance of the KindCompositeIndexStat for every unique (kind, composite_index_id) tuple in the application's datastore indexes. Attributes: index_id: the id of the composite index associated with the statistic instance. kind_name: the name of the kind associated with the statistic instance. """ STORED_KIND_NAME = '__Stat_Kind_CompositeIndex__' index_id = model.IntegerProperty() kind_name = model.StringProperty()
class BaseKindStatistic(BaseStatistic): """Base Statistic Model class for stats associated with kinds. Attributes: kind_name: the name of the kind associated with the statistic instance. entity_bytes: the number of bytes taken up to store the statistic in Cloud Datastore minus the cost of storing indices. """ STORED_KIND_NAME = '__BaseKindStatistic__' kind_name = model.StringProperty() entity_bytes = model.IntegerProperty(default=0)
class EnkiModelProductKey( model.Model ): licence_key = model.StringProperty() # mandatory product_name = model.StringProperty() # mandatory purchaser_email = model.StringProperty() # mandatory purchaser_user_id = model.IntegerProperty() # if the purchaser is registered shop_name = model.StringProperty() #choices = [ 'FastSpring' ]) purchase_price = model.StringProperty() quantity = model.IntegerProperty() order_id = model.StringProperty() order_type = model.StringProperty( choices = [ 'emulated', 'test', 'normal' ]) activated_by_user = model.IntegerProperty( ) time_created = model.DateTimeProperty( auto_now_add = True ) time_updated = model.DateTimeProperty( auto_now = True )
class Message(model.Model): username = model.StringProperty() picture_url = model.StringProperty() message = model.StringProperty() commit_hash = model.StringProperty(required=False) url = model.StringProperty(required=False) project = model.StringProperty(required=False) timestamp = model.DateTimeProperty(auto_now_add=True) def __str__(self): return '%s - %s' % (self.username, self.message) def __unicode__(self): return self.__str__() def to_json(self): data = self.to_dict(exclude=['timestamp']) return json.dumps(data) @classmethod def create_message(cls, username, picture_url, message, **kwargs): message = cls(username=username, picture_url=picture_url, message=message) message.populate(**kwargs) message.put() deferred.defer(send_live_message, message.key.urlsafe(), _queue="live") return message @classmethod def add_commit(cls, key): commit_key = model.Key(urlsafe=key) commit = commit_key.get() parent_key = commit_key.parent() if parent_key is None: return parent = parent_key.get() picture_url = getattr(parent, 'picture_url', '/static/images/spread_the_word_button.png') message = cls(username=parent.username, picture_url=picture_url, message=commit.message[:200], url=commit.url, project=commit.project, commit_hash=commit.hash) message.put() deferred.defer(send_live_message, message.key.urlsafe(), _queue="live") return message
class AcarsPirep(model.Model): time_report = model.DateTimeProperty(auto_now_add=True) acars_id = model.IntegerProperty() user_id = model.StringProperty() flight_number = model.StringProperty() ac_icao = model.StringProperty() cruise_alt = model.IntegerProperty() flight_type = model.StringProperty() departure = model.StringProperty() destination = model.StringProperty() alternate = model.StringProperty() dep_time = model.DateTimeProperty() block_time = model.IntegerProperty() block_fuel = model.IntegerProperty() flight_time = model.IntegerProperty() flight_fuel = model.IntegerProperty() pax = model.IntegerProperty() cargo = model.IntegerProperty() online = model.IntegerProperty() engine_start_ts = model.IntegerProperty() takeoff_ts = model.IntegerProperty() landing_ts = model.IntegerProperty() engine_stop_ts = model.IntegerProperty() zero_fuel_weight = model.IntegerProperty() take_off_weight = model.IntegerProperty() landing_weight = model.IntegerProperty() out_geo = model.GeoPtProperty() out_altitude = model.IntegerProperty() in_geo = model.GeoPtProperty() in_altitude = model.IntegerProperty() max_climb_rate = model.IntegerProperty() max_descend_rate = model.IntegerProperty() max_ias = model.IntegerProperty() max_gs = model.IntegerProperty() def add_pirep(self): self.put_async() def flights_for_user(self, user_id, limit=20, offset=0): return AcarsPirep.query(AcarsPirep.user_id == user_id).fetch( limit, offset=offset) flights_for_user = classmethod(flights_for_user)
class NamespaceStat(BaseStatistic): """An aggregate of all entities across an entire namespace. This statistic has one instance per namespace. The key_name is the represented namespace. NamespaceStat entities will only be found in the namespace "" (empty string). It contains the total number of entities stored and the total number of bytes they take up. Attributes: subject_namespace: the namespace associated with the statistic instance. entity_bytes: the number of bytes taken up to store the statistic in Cloud Datastore minus the cost of storing indices. builtin_index_bytes: the number of bytes taken up to store builtin-in index entries builtin_index_count: the number of built-in index entries. composite_index_bytes: the number of bytes taken up to store composite index entries composite_index_count: the number of composite index entries. """ STORED_KIND_NAME = '__Stat_Namespace__' subject_namespace = model.StringProperty() entity_bytes = model.IntegerProperty(default=0) builtin_index_bytes = model.IntegerProperty(default=0) builtin_index_count = model.IntegerProperty(default=0) composite_index_bytes = model.IntegerProperty(default=0) composite_index_count = model.IntegerProperty(default=0)