class _AE_GCSFileInfo_(db.Model): """Store GCS specific info. GCS allows user to define arbitrary metadata via header x-goog-meta-foo: bar. These headers are returned when user does a GET or HEAD on the object. Key name is blobkey. """ filename = db.StringProperty(required=True) finalized = db.BooleanProperty(required=True) raw_options = db.StringListProperty() size = db.IntegerProperty() creation = db.DateTimeProperty() content_type = db.ByteStringProperty() etag = db.ByteStringProperty() def get_options(self): return dict(o.split(':', 1) for o in self.raw_options) def set_options(self, options_dict): self.raw_options = [ '%s:%s' % (k.lower(), v) for k, v in options_dict.iteritems() ] if 'content-type' in options_dict: self.content_type = options_dict['content-type'] options = property(get_options, set_options) @classmethod def kind(cls): return blobstore_stub._GS_INFO_KIND
class FileStorage(db.Model): # store the file data or a link to that data in the blobstore id = db.ByteStringProperty(required=True) data = db.BlobProperty() msg = db.BlobProperty(required=True) inserted = db.DateTimeProperty(auto_now_add=True, indexed=True) blobkey = db.ByteStringProperty() client_ver = db.IntegerProperty(required=True) sender_token = db.ByteStringProperty(indexed=True) notify_type = db.IntegerProperty() downloaded = db.BooleanProperty(required=True, default=False) push_accepted = db.BooleanProperty(required=True, default=False)
class AllPropertiesModel(db.Model): """Property names are ugly, yes.""" prop_string = db.StringProperty() prop_byte_string = db.ByteStringProperty() prop_boolean = db.BooleanProperty() prop_integer = db.IntegerProperty() prop_float = db.FloatProperty() prop_date_time = db.DateTimeProperty() prop_date = db.DateProperty() prop_time = db.TimeProperty() prop_list = db.ListProperty(int) prop_string_list = db.StringListProperty() prop_reference = db.ReferenceProperty() prop_self_refeference = db.SelfReferenceProperty() prop_user = db.UserProperty() prop_blob = db.BlobProperty() prop_text = db.TextProperty() prop_category = db.CategoryProperty() prop_link = db.LinkProperty() prop_email = db.EmailProperty() prop_geo_pt = db.GeoPtProperty() prop_im = db.IMProperty() prop_phone_number = db.PhoneNumberProperty() prop_postal_address = db.PostalAddressProperty() prop_rating = db.RatingProperty()
class FakeBackup(db.Model): name = db.ByteStringProperty() complete_time = db.DateTimeProperty() @classmethod def kind(cls): return '_AE_Backup_Information'
class NonVerifiedScore(db.Model): value = db.IntegerProperty(required=True) time = db.IntegerProperty(required=True) # seconds ? proof = db.BlobProperty(required=True) seed = db.ByteStringProperty(required=True) version = db.IntegerProperty(required=True) dateTime = db.DateTimeProperty(auto_now_add=True) conflictingReviewers = db.StringListProperty()
class UpFile(db.Model): name = db.StringProperty(required=True) # owner = db.UserProperty() uploaded = db.DateTimeProperty() content = db.ByteStringProperty() size = db.IntegerProperty() blob_key = blobstore.BlobReferenceProperty() blob_key_string = db.StringProperty() ct = db.StringProperty()
class User(db.Model): # key=<auto> v = db.IntegerProperty(default=0) backer = db.BooleanProperty(default=False) backing_started = db.DateTimeProperty() created = db.DateTimeProperty(auto_now_add=True) delinquent = db.BooleanProperty(default=False) delinquent_emailed = db.BooleanProperty(default=False) email = db.StringProperty(default='', indexed=False) image_id = db.ByteStringProperty(default='', indexed=False) link_text = db.StringProperty(default='', indexed=False) link_url = db.StringProperty(default='', indexed=False) name = db.StringProperty(default='', indexed=False) payment_type = db.StringProperty(default='') # 'stripe' | 'manual' plan = db.StringProperty(default='') sponsor = db.BooleanProperty(default=False) stripe_customer_id = db.StringProperty(default='', indexed=False) stripe_is_unpaid = db.BooleanProperty(default=False) stripe_needs_cancelling = db.ListProperty(str, indexed=False) stripe_needs_updating = db.BooleanProperty(default=False) stripe_subscription = db.StringProperty( default='') # stripe subscription id stripe_update_version = db.IntegerProperty(default=0, indexed=False) tax_id = db.StringProperty(default='', indexed=False) tax_id_detailed = db.TextProperty(default=u'') tax_id_is_invalid = db.BooleanProperty(default=False) tax_id_to_validate = db.BooleanProperty(default=False) territory = db.StringProperty(default='') totals_need_syncing = db.BooleanProperty(default=False) totals_version = db.IntegerProperty(default=0, indexed=False) updated = db.DateTimeProperty(auto_now=True) # A tuple with the first indicating the type of image available: # # 'b' - blob stored in gcs # 'g' - md5 hash of the email for use with gravatar # 'u' - direct url of image def get_image_spec(self): if self.image_id: return ('b', self.image_id) return ('g', md5(self.email.lower()).hexdigest()) def get_link_text(self): if self.link_text: return self.link_text return self.name def get_link_url(self): return self.link_url def get_stripe_idempotency_key(self): return 'sub.%s.%s' % (self.key().id(), self.stripe_update_version) def get_stripe_meta(self): return {"version": str(self.stripe_update_version)}
class LocalAuth(UserAuthType): """Supports authenticating to the application using the application datastore only. """ name = 'SimpleEditions' password = db.ByteStringProperty(required=True, indexed=False) @staticmethod def add_to_user(handler, user, password): if not user.email: raise simpleeditions.ConnectError( 'You must enter an e-mail when using password authentication.') password = password.encode('utf-8') salt = os.urandom(4) auth = LocalAuth( parent=user, password=salt + hashlib.sha256(password + salt).digest()) auth.put() return auth @staticmethod def log_in(handler, email, password): """Retrieves a LocalAuth instance, based on an e-mail and a password. The SHA-256 hash of the password must match the hash stored in the datastore, otherwise an exception will be raised. """ email = email.strip().lower() user = User.all(keys_only=True).filter('email', email).get() if user: auth = LocalAuth.all().ancestor(user).get() if auth: password = password.encode('utf-8') salt = auth.password[:4] hash = auth.password[4:] if hashlib.sha256(password + salt).digest() == hash: return auth raise simpleeditions.LogInError( 'Wrong e-mail address or password.') @staticmethod def validate(handler, password): if not isinstance(password, basestring): raise TypeError('The password must be supplied as a string.') if len(password) < 6: raise simpleeditions.ConnectError( 'Password must be at least 6 characters long.')
class ShardState(db.Model): """Single shard execution state. The shard state is stored in the datastore and is later aggregated by controller task. ShardState key_name is equal to shard_id. Shard state contains critical state to ensure the correctness of shard execution. It is the single source of truth about a shard's progress. For example: 1. A slice is allowed to run only if its payload matches shard state's expectation. 2. A slice is considered running only if it has acquired the shard's lock. 3. A slice is considered done only if it has successfully committed shard state to db. Properties about the shard: active: if we have this shard still running as boolean. counters_map: shard's counters map as CountersMap. All counters yielded within mapreduce are stored here. mapreduce_id: unique id of the mapreduce. shard_id: unique id of this shard as string. shard_number: ordered number for this shard. retries: the number of times this shard has been retried. result_status: If not None, the final status of this shard. update_time: The last time this shard state was updated. shard_description: A string description of the work this shard will do. last_work_item: A string description of the last work item processed. writer_state: writer state for this shard. The shard's output writer instance can save in-memory output references to this field in its "finalize" method. Properties about slice management: slice_id: slice id of current executing slice. A slice's task will not run unless its slice_id matches this. Initial value is 0. By the end of slice execution, this number is incremented by 1. slice_start_time: a slice updates this to now at the beginning of execution. If the transaction succeeds, the current task holds a lease of slice duration + some grace period. During this time, no other task with the same slice_id will execute. Upon slice failure, the task should try to unset this value to allow retries to carry on ASAP. slice_request_id: the request id that holds/held the lease. When lease has expired, new request needs to verify that said request has indeed ended according to logs API. Do this only when lease has expired because logs API is expensive. This field should always be set/unset with slice_start_time. It is possible Logs API doesn't log a request at all or doesn't log the end of a request. So a new request can proceed after a long conservative timeout. slice_retries: the number of times a slice has been retried due to processing data when lock is held. Taskqueue/datastore errors related to slice/shard management are not counted. This count is only a lower bound and is used to determined when to fail a slice completely. acquired_once: whether the lock for this slice has been acquired at least once. When this is True, duplicates in outputs are possible. """ RESULT_SUCCESS = "success" RESULT_FAILED = "failed" RESULT_ABORTED = "aborted" _RESULTS = frozenset([RESULT_SUCCESS, RESULT_FAILED, RESULT_ABORTED]) _MAX_STATES_IN_MEMORY = 10 mapreduce_id = db.StringProperty(required=True) active = db.BooleanProperty(default=True, indexed=False) counters_map = json_util.JsonProperty(CountersMap, default=CountersMap(), indexed=False) result_status = db.StringProperty(choices=_RESULTS, indexed=False) retries = db.IntegerProperty(default=0, indexed=False) writer_state = json_util.JsonProperty(dict, indexed=False) slice_id = db.IntegerProperty(default=0, indexed=False) slice_start_time = db.DateTimeProperty(indexed=False) slice_request_id = db.ByteStringProperty(indexed=False) slice_retries = db.IntegerProperty(default=0, indexed=False) acquired_once = db.BooleanProperty(default=False, indexed=False) update_time = db.DateTimeProperty(auto_now=True, indexed=False) shard_description = db.TextProperty(default="") last_work_item = db.TextProperty(default="") def __str__(self): kv = { "active": self.active, "slice_id": self.slice_id, "last_work_item": self.last_work_item, "update_time": self.update_time } if self.result_status: kv["result_status"] = self.result_status if self.retries: kv["retries"] = self.retries if self.slice_start_time: kv["slice_start_time"] = self.slice_start_time if self.slice_retries: kv["slice_retries"] = self.slice_retries if self.slice_request_id: kv["slice_request_id"] = self.slice_request_id if self.acquired_once: kv["acquired_once"] = self.acquired_once keys = kv.keys() keys.sort() result = "ShardState is {" for k in keys: result += k + ":" + str(kv[k]) + "," result += "}" return result def reset_for_retry(self): """Reset self for shard retry.""" self.retries += 1 self.last_work_item = "" self.active = True self.result_status = None self.counters_map = CountersMap() self.slice_id = 0 self.slice_start_time = None self.slice_request_id = None self.slice_retries = 0 self.acquired_once = False def advance_for_next_slice(self, recovery_slice=False): """Advance self for next slice. Args: recovery_slice: True if this slice is running recovery logic. See handlers.MapperWorkerCallbackHandler._attempt_slice_recovery for more info. """ self.slice_start_time = None self.slice_request_id = None self.slice_retries = 0 self.acquired_once = False if recovery_slice: self.slice_id += 2 else: self.slice_id += 1 def set_for_failure(self): self.active = False self.result_status = self.RESULT_FAILED def set_for_abort(self): self.active = False self.result_status = self.RESULT_ABORTED def set_for_success(self): self.active = False self.result_status = self.RESULT_SUCCESS self.slice_start_time = None self.slice_request_id = None self.slice_retries = 0 self.acquired_once = False def copy_from(self, other_state): """Copy data from another shard state entity to self.""" for prop in self.properties().values(): setattr(self, prop.name, getattr(other_state, prop.name)) def __eq__(self, other): if not isinstance(other, self.__class__): return False return self.properties() == other.properties() def get_shard_number(self): """Gets the shard number from the key name.""" return int(self.key().name().split("-")[-1]) shard_number = property(get_shard_number) def get_shard_id(self): """Returns the shard ID.""" return self.key().name() shard_id = property(get_shard_id) @classmethod def kind(cls): """Returns entity kind.""" return "_GAE_MR_ShardState" @classmethod def shard_id_from_number(cls, mapreduce_id, shard_number): """Get shard id by mapreduce id and shard number. Args: mapreduce_id: mapreduce id as string. shard_number: shard number to compute id for as int. Returns: shard id as string. """ return "%s-%d" % (mapreduce_id, shard_number) @classmethod def get_key_by_shard_id(cls, shard_id): """Retrieves the Key for this ShardState. Args: shard_id: The shard ID to fetch. Returns: The Datatore key to use to retrieve this ShardState. """ return db.Key.from_path(cls.kind(), shard_id) @classmethod def get_by_shard_id(cls, shard_id): """Get shard state from datastore by shard_id. Args: shard_id: shard id as string. Returns: ShardState for given shard id or None if it's not found. """ return cls.get_by_key_name(shard_id) @classmethod def find_by_mapreduce_state(cls, mapreduce_state): """Find all shard states for given mapreduce. Deprecated. Use find_all_by_mapreduce_state. This will be removed after 1.8.9 release. Args: mapreduce_state: MapreduceState instance Returns: A list of ShardStates. """ return list(cls.find_all_by_mapreduce_state(mapreduce_state)) @classmethod def find_all_by_mapreduce_state(cls, mapreduce_state): """Find all shard states for given mapreduce. Never runs within a transaction since it may touch >5 entity groups (one for each shard). Args: mapreduce_state: MapreduceState instance Yields: shard states sorted by shard id. """ keys = cls.calculate_keys_by_mapreduce_state(mapreduce_state) i = 0 while i < len(keys): @db.non_transactional def no_tx_get(i): return db.get(keys[i:i + cls._MAX_STATES_IN_MEMORY]) states = no_tx_get(i) for s in states: i += 1 if s is not None: yield s @classmethod def calculate_keys_by_mapreduce_state(cls, mapreduce_state): """Calculate all shard states keys for given mapreduce. Args: mapreduce_state: MapreduceState instance Returns: A list of keys for shard states, sorted by shard id. The corresponding shard states may not exist. """ if mapreduce_state is None: return [] keys = [] for i in range(mapreduce_state.mapreduce_spec.mapper.shard_count): shard_id = cls.shard_id_from_number(mapreduce_state.key().name(), i) keys.append(cls.get_key_by_shard_id(shard_id)) return keys @classmethod def create_new(cls, mapreduce_id, shard_number): """Create new shard state. Args: mapreduce_id: unique mapreduce id as string. shard_number: shard number for which to create shard state. Returns: new instance of ShardState ready to put into datastore. """ shard_id = cls.shard_id_from_number(mapreduce_id, shard_number) state = cls(key_name=shard_id, mapreduce_id=mapreduce_id) return state
class BlockVer(db.Model): date = db.DateTimeProperty(auto_now_add=True) blockData = db.BlobProperty(required=True) # Save Data palData = db.ByteStringProperty() # Pallette Data linkData = db.ListProperty(db.Key) # Links to BLOCK not Block Ver
class ShardState(db.Model): """Single shard execution state. The shard state is stored in the datastore and is later aggregated by controller task. Shard key_name is equal to shard_id. Properties: active: if we have this shard still running as boolean. counters_map: shard's counters map as CountersMap. All counters yielded within mapreduce are stored here. mapreduce_id: unique id of the mapreduce. shard_id: unique id of this shard as string. shard_number: ordered number for this shard. retries: the number of times this shard has been retried. result_status: If not None, the final status of this shard. update_time: The last time this shard state was updated. shard_description: A string description of the work this shard will do. last_work_item: A string description of the last work item processed. writer_state: writer state for this shard. This is filled when a job has one output per shard by OutputWriter's create method. slice_id: slice id of current executing slice. A task will not run unless its slice_id matches this. Initial value is 0. By the end of slice execution, this number is incremented by 1. slice_start_time: a slice updates this to now at the beginning of execution transactionally. If transaction succeeds, the current task holds a lease of slice duration + some grace period. During this time, no other task with the same slice_id will execute. Upon slice failure, the task should try to unset this value to allow retries to carry on ASAP. slice_start_time is only meaningful when slice_id is the same. slice_request_id: the request id that holds/held the lease. When lease has expired, new request needs to verify that said request has indeed ended according to logs API. Do this only when lease has expired because logs API is expensive. This field should always be set/unset with slice_start_time. It is possible Logs API doesn't log a request at all or doesn't log the end of a request. So a new request can proceed after a long conservative timeout. slice_retries: the number of times a slice has been retried due to processing data when lock is held. Taskqueue/datastore errors related to shard management are not counted. This count is only a lower bound and is used to determined when to fail a slice completely. acquired_once: whether the lock for this slice has been acquired at least once. When this is True, duplicates in outputs are possible. This is very different from when slice_retries is 0, e.g. when outputs have been written but a taskqueue problem prevents a slice to continue, acquired_once would be True but slice_retries would be 0. """ RESULT_SUCCESS = "success" RESULT_FAILED = "failed" RESULT_ABORTED = "aborted" _RESULTS = frozenset([RESULT_SUCCESS, RESULT_FAILED, RESULT_ABORTED]) active = db.BooleanProperty(default=True, indexed=False) counters_map = JsonProperty(CountersMap, default=CountersMap(), indexed=False) result_status = db.StringProperty(choices=_RESULTS, indexed=False) retries = db.IntegerProperty(default=0, indexed=False) writer_state = JsonProperty(dict, indexed=False) slice_id = db.IntegerProperty(default=0, indexed=False) slice_start_time = db.DateTimeProperty(indexed=False) slice_request_id = db.ByteStringProperty(indexed=False) slice_retries = db.IntegerProperty(default=0, indexed=False) acquired_once = db.BooleanProperty(default=False, indexed=False) mapreduce_id = db.StringProperty(required=True) update_time = db.DateTimeProperty(auto_now=True, indexed=False) shard_description = db.TextProperty(default="") last_work_item = db.TextProperty(default="") def __str__(self): kv = { "active": self.active, "slice_id": self.slice_id, "last_work_item": self.last_work_item, "update_time": self.update_time } if self.result_status: kv["result_status"] = self.result_status if self.retries: kv["retries"] = self.retries if self.slice_start_time: kv["slice_start_time"] = self.slice_start_time if self.slice_retries: kv["slice_retries"] = self.slice_retries if self.slice_request_id: kv["slice_request_id"] = self.slice_request_id if self.acquired_once: kv["acquired_once"] = self.acquired_once keys = kv.keys() keys.sort() result = "ShardState is {" for k in keys: result += k + ":" + str(kv[k]) + "," result += "}" return result def reset_for_retry(self): """Reset self for shard retry.""" self.retries += 1 self.last_work_item = "" self.active = True self.result_status = None self.counters_map = CountersMap() self.slice_id = 0 self.slice_start_time = None self.slice_request_id = None self.slice_retries = 0 self.acquired_once = False def advance_for_next_slice(self): """Advance self for next slice.""" self.slice_id += 1 self.slice_start_time = None self.slice_request_id = None self.slice_retries = 0 self.acquired_once = False def set_for_abort(self): self.active = False self.result_status = self.RESULT_ABORTED def set_for_success(self): self.active = False self.result_status = self.RESULT_SUCCESS self.slice_start_time = None self.slice_request_id = None self.slice_retries = 0 self.acquired_once = False def copy_from(self, other_state): """Copy data from another shard state entity to self.""" for prop in self.properties().values(): setattr(self, prop.name, getattr(other_state, prop.name)) def get_shard_number(self): """Gets the shard number from the key name.""" return int(self.key().name().split("-")[-1]) shard_number = property(get_shard_number) def get_shard_id(self): """Returns the shard ID.""" return self.key().name() shard_id = property(get_shard_id) @classmethod def kind(cls): """Returns entity kind.""" return "_GAE_MR_ShardState" @classmethod def shard_id_from_number(cls, mapreduce_id, shard_number): """Get shard id by mapreduce id and shard number. Args: mapreduce_id: mapreduce id as string. shard_number: shard number to compute id for as int. Returns: shard id as string. """ return "%s-%d" % (mapreduce_id, shard_number) @classmethod def get_key_by_shard_id(cls, shard_id): """Retrieves the Key for this ShardState. Args: shard_id: The shard ID to fetch. Returns: The Datatore key to use to retrieve this ShardState. """ return db.Key.from_path(cls.kind(), shard_id) @classmethod def get_by_shard_id(cls, shard_id): """Get shard state from datastore by shard_id. Args: shard_id: shard id as string. Returns: ShardState for given shard id or None if it's not found. """ return cls.get_by_key_name(shard_id) @classmethod def find_by_mapreduce_state(cls, mapreduce_state): """Find all shard states for given mapreduce. Args: mapreduce_state: MapreduceState instance Returns: iterable of all ShardState for given mapreduce. """ keys = cls.calculate_keys_by_mapreduce_state(mapreduce_state) return [state for state in db.get(keys) if state] @classmethod def calculate_keys_by_mapreduce_state(cls, mapreduce_state): """Calculate all shard states keys for given mapreduce. Args: mapreduce_state: MapreduceState instance Returns: A list of keys for shard states. The corresponding shard states may not exist. """ keys = [] for i in range(mapreduce_state.mapreduce_spec.mapper.shard_count): shard_id = cls.shard_id_from_number(mapreduce_state.key().name(), i) keys.append(cls.get_key_by_shard_id(shard_id)) return keys @classmethod def find_by_mapreduce_id(cls, mapreduce_id): logging.error( "ShardState.find_by_mapreduce_id method may be inconsistent. " + "ShardState.find_by_mapreduce_state should be used instead.") return cls.all().filter("mapreduce_id =", mapreduce_id).fetch(99999) @classmethod def create_new(cls, mapreduce_id, shard_number): """Create new shard state. Args: mapreduce_id: unique mapreduce id as string. shard_number: shard number for which to create shard state. Returns: new instance of ShardState ready to put into datastore. """ shard_id = cls.shard_id_from_number(mapreduce_id, shard_number) state = cls(key_name=shard_id, mapreduce_id=mapreduce_id) return state
class StoreKey(db.Model): """the database for storing session_id and its correspond session_keys""" s_id = db.ByteStringProperty() s_key_hmackey = db.BlobProperty() date = db.DateTimeProperty(auto_now_add=True)
class TestBytes(db.Model): a = db.ByteStringProperty()
class GameUser(db.Model): """ Models an authenticated user """ name = db.StringProperty() password = db.ByteStringProperty() game = db.StringProperty() salt = db.ByteStringProperty() token = db.StringProperty() expiration = db.IntegerProperty() status = db.IntegerProperty(default=0) verification = db.StringProperty() create_date = db.DateTimeProperty(auto_now_add=True) modify_date = db.DateTimeProperty(auto_now_add=True) last_login_date = db.DateTimeProperty(auto_now_add=True) email = db.ByteStringProperty() phone = db.ByteStringProperty() wins = db.IntegerProperty(default=0) losses = db.IntegerProperty(default=0) credits = db.IntegerProperty(default=0) level = db.IntegerProperty(default=0) experience = db.IntegerProperty(default=0) blob = db.TextProperty() def set_value(self, property, value): if property in USER_INT_PROPERTIES: logging.debug("Setting %s to %s" % (property, value)) setattr(self, property, int(value)) else: logging.debug("Setting %s to %s" % (property, value)) setattr(self, property, str(value)) def to_dict(self): dicty = {} # Handle date properties for property in ("create_date", "modify_date", "last_login_date"): dicty[property] = str(getattr(self, property)) # Handle encrypted properties for property in ('email', 'phone'): dicty[property] = decrypt(getattr(self, property)) logging.debug('Property ' + property + ' is:' + dicty[property]) # Handle rest of visible properties for property in ('name', 'game', 'wins', 'losses', 'credits', 'level', 'experience', 'blob'): dicty[property] = getattr(self, property) dicty['status'] = USER_VERIFY_MAP[self.status] return dicty @classmethod def get_by_verification(cls, verification): return db.GqlQuery("SELECT * from GameUser WHERE verification = :1", verification) @classmethod def get_by_name(cls, name, game): """ Returns the first user for the given game with the given name. """ users = db.GqlQuery( "SELECT * from GameUser WHERE name = :1 and game = :2", name.lower(), game) if users.count() > 1: logging.error("More than one user with name: %s" % name) user = None for user in users: break return user @classmethod def name_is_available(cls, name, game): """ Returns true if the given user name has not been used in the given game. """ users = db.GqlQuery( "SELECT * from GameUser WHERE name = :1 and game = :2", name.lower(), game) return users.count() == 0 @classmethod def email_is_available(cls, email, game): """ Returns true if the given email address has not been used in the given game. """ return True users = db.GqlQuery( "SELECT name from GameUser WHERE email = :1 and game = :2", email, game) return users.count() == 0 @classmethod def list(cls, game): return db.GqlQuery("SELECT * FROM GameUser WHERE game = :1", game)
class StatusUpdate(db.Model): owner = db.UserProperty(required=True) delta = db.ByteStringProperty(required=True) timestamp = db.DateTimeProperty(auto_now_add=True)
class VIPKey(db.Model): """the database for storing session_id and its correspond session_keys""" vessel_name = db.ByteStringProperty() vip_key = db.BlobProperty() date = db.DateTimeProperty(auto_now_add=True)
class PlaySession(db.Model): seed = db.ByteStringProperty(required=True) version = db.IntegerProperty(required=True) seedDateTime = db.DateTimeProperty(required=True)
class GPSData(db.Model): """the database for storing gpsdata for given vessel""" vessel_name = db.ByteStringProperty() gpsdata = db.BlobProperty() vessel_time_stamp = db.IntegerProperty() date = db.DateTimeProperty(auto_now_add=True)