class Publisher(model.Model): # key_name=urlname """Model for a VertNet data Publisher.""" name = model.StringProperty('n', required=True) urlname = model.ComputedProperty(lambda self: urlname(self.name)) owner = model.UserProperty('o', required=True) admins = model.UserProperty('a', repeated=True) created = model.DateTimeProperty('c', auto_now_add=True) updated = model.DateTimeProperty('u', auto_now=True) json = model.TextProperty('j', required=True) # JSON representation @classmethod def create(cls, name): return Publisher( id=urlname(name), name=name, owner=users.get_current_user(), json=simplejson.dumps(dict( url='http://%s.%s.appspot.com/publishers/%s' % \ (appver, appid, urlname(name)), name=name, admin=users.get_current_user().nickname()))) @classmethod def get_by_urlname(cls, urlname): return model.Key('Publisher', urlname).get()
class Collection(model.Model): # key_name=urlname, parent=Publisher """Model for a collection of records.""" name = model.StringProperty('n', required=True) urlname = model.ComputedProperty(lambda self: urlname(self.name)) owner = model.UserProperty('o', required=True) admins = model.UserProperty('a', repeated=True) created = model.DateTimeProperty('c', auto_now_add=True) updated = model.DateTimeProperty('u', auto_now=True) json = model.TextProperty('j', required=True) # JSON representation @classmethod def create(cls, name, publisher_key): return Collection( parent=publisher_key, id=urlname(name), name=name, owner=users.get_current_user(), json=simplejson.dumps(dict( name=name, admin=users.get_current_user().nickname(), url='http://%s.%s.appspot.com/publishers/%s/%s' % \ (appver, appid, publisher_key.id(), urlname(name))))) @classmethod def get_by_urlname(cls, urlname, publisher_key): return model.Key('Collection', urlname, parent=publisher_key).get() @classmethod def all_by_publisher(cls, publisher_key): return Collection.query(ancestor=publisher_key).fetch()
class UserToken(model.Model): """Stores validation tokens for users.""" created = model.DateTimeProperty(auto_now_add=True) updated = model.DateTimeProperty(auto_now=True) user = model.StringProperty(required=True, indexed=False) subject = model.StringProperty(required=True) token = model.StringProperty(required=True) @classmethod def get_key(cls, user, subject, token): """Returns a token key.""" return model.Key(cls, '%s.%s.%s' % (user, subject, token)) @classmethod def create(cls, user, subject, token=None): """Fetches a user token.""" token = token or security.generate_random_string(entropy=64) key = cls.get_key(user, subject, token) entity = cls(key=key, user=user, subject=subject, token=token) entity.put() return entity @classmethod def get(cls, user=None, subject=None, token=None): """Fetches a user token.""" if user and subject and token: return cls.get_key(user, subject, token).get() assert subject and token, \ 'subject and token must be provided to UserToken.get().' return cls.query(cls.subject == subject, cls.token == token).get()
class Session(model.Model): """A model to store session data.""" #: Save time. updated = model.DateTimeProperty(auto_now=True) #: Session data, pickled. data = PickleProperty() @classmethod def get_by_sid(cls, sid): """Returns a ``Session`` instance by session id. :param sid: A session id. :returns: An existing ``Session`` entity. """ data = memcache.get(sid) if not data: session = model.Key(cls, sid).get() if session: data = session.data memcache.set(sid, data) return data def _put(self): """Saves the session and updates the memcache entry.""" memcache.set(self._key.id(), self.data) super(Session, self).put()
class Record(model.Model): # key_name=record.occurrenceid, parent=Collection """Model for a record.""" owner = model.UserProperty('u', required=True) record = model.TextProperty( 'r', required=True) # darwin core json representation created = model.DateTimeProperty('c', auto_now_add=True) updated = model.DateTimeProperty('u', auto_now=True) @classmethod def create(cls, rec, collection_key): return Record(parent=collection_key, id=rec['occurrenceid'], owner=users.get_current_user(), record=simplejson.dumps(rec)) @classmethod def all_by_collection(cls, collection_key): return Record.query(ancestor=collection_key).fetch()
class CachedTile(model.Model): tile = model.BlobKeyProperty(required=True) rendered = model.DateTimeProperty(required=True) operation_cost = model.IntegerProperty(required=True) render_time = model.FloatProperty(required=True) level = model.IntegerProperty(required=True) #_use_datastore = False _use_memcache = False @property def position(self): """Returns the level/x/y tuple for this tile.""" return tuple(int(x) for x in self.key.id().split('/')[1:]) @classmethod def key_for_tile(cls, type, level, x, y): return model.Key(cls, '%s/%s/%s/%s' % (type, level, x, y))
class TestArticle(model.Model): title = model.StringProperty() description = model.StringProperty() created = model.DateTimeProperty(auto_now=True) @classmethod def add_property(cls, name, property, **kwargs): """ Method for dynamical adding model properties """ setattr(cls, name, property(name, **kwargs)) cls._fix_up_properties() @classmethod def del_property(cls, name): """ Method for dynamical adding model properties """ delattr(cls, name) cls._fix_up_properties()
class Session(model.Model): """A model to store session data.""" #: Save time. updated = model.DateTimeProperty(auto_now=True) #: Session data, pickled. try: # If model.PickleProperty exists, we must use it, since the # above PickledProperty is broken in NDB 0.9.4 and later. # This still leaves NDB 0.9.4 broken, since it doesn't have # model.PickleProperty. Fortunately no SDK contains NDB # 0.9.4, we went straight from 0.9.3 (in SDK 1.6.1) to 0.9.6 # (in SDK 1.6.2). data = model.PickleProperty() except AttributeError: # In NDB 0.9.3 or before, the above PickledProperty works. data = PickledProperty(dict) @classmethod def get_by_sid(cls, sid): """Returns a ``Session`` instance by session id. :param sid: A session id. :returns: An existing ``Session`` entity. """ data = memcache.get(sid) if not data: session = model.Key(cls, sid).get() if session: data = session.data memcache.set(sid, data) return data def _put(self): """Saves the session and updates the memcache entry.""" memcache.set(self._key.id(), self.data) super(Session, self).put()
class MigrationEntry(model.Model): """ Represents Migration in storage. """ id = model.StringProperty() application = model.StringProperty() ctime = model.DateTimeProperty(auto_now_add=True) status = model.StringProperty(required=True, choices=["apply in process", "rollback in process", "apply failed", "rollback failed", "apply success", "rollback success", ]) @classmethod def _pre_delete_hook(cls, key): memcache.delete(key.kind()) def _post_put_hook(self, future): super(MigrationEntry, self)._post_put_hook(future) memcache.delete(self.key.kind())
class User(model.Expando): """Stores user authentication credentials or authorization ids.""" #: The model used to ensure uniqueness. unique_model = Unique #: The model used to store tokens. token_model = UserToken created = model.DateTimeProperty(auto_now_add=True) updated = model.DateTimeProperty(auto_now=True) # ID for third party authentication, e.g. 'google:username'. UNIQUE. auth_ids = model.StringProperty(repeated=True) # Hashed password. Not required because third party authentication # doesn't use password. password = model.StringProperty() def get_id(self): """Returns this user's unique ID, which can be an integer or string.""" return self._key.id() @classmethod def get_by_auth_id(cls, auth_id): """Returns a user object based on a auth_id. :param auth_id: String representing a unique id for the user. Examples: - own:username - google:username :returns: A user object. """ return cls.query(cls.auth_ids == auth_id).get() @classmethod def get_by_auth_token(cls, user_id, token): """Returns a user object based on a user ID and token. :param user_id: The user_id of the requesting user. :param token: The token string to be verified. :returns: A tuple ``(User, timestamp)``, with a user object and the token timestamp, or ``(None, None)`` if both were not found. """ token_key = cls.token_model.get_key(user_id, 'auth', token) user_key = model.Key(cls, user_id) # Use get_multi() to save a RPC call. valid_token, user = model.get_multi([token_key, user_key]) if valid_token and user: timestamp = int(time.mktime(valid_token.created.timetuple())) return user, timestamp return None, None @classmethod def get_by_auth_password(cls, auth_id, password): """Returns a user object, validating password. :param auth_id: Authentication id. :param password: Password to be checked. :returns: A user object, if found and password matches. :raises: ``auth.InvalidAuthIdError`` or ``auth.InvalidPasswordError``. """ user = cls.get_by_auth_id(auth_id) if not user: raise auth.InvalidAuthIdError() if not security.check_password_hash(password, user.password): raise auth.InvalidPasswordError() return user @classmethod def validate_token(cls, user_id, subject, token): """Checks for existence of a token, given user_id, subject and token. :param user_id: User unique ID. :param subject: The subject of the key. Examples: - 'auth' - 'signup' :param token: The token string to be validated. :returns: A :class:`UserToken` or None if the token does not exist. """ return cls.token_model.get(user=user_id, subject=subject, token=token) is not None @classmethod def create_auth_token(cls, user_id): """Creates a new authorization token for a given user ID. :param user_id: User unique ID. :returns: A string with the authorization token. """ return cls.token_model.create(user_id, 'auth').token @classmethod def validate_auth_token(cls, user_id, token): return cls.validate_token(user_id, 'auth', token) @classmethod def delete_auth_token(cls, user_id, token): """Deletes a given authorization token. :param user_id: User unique ID. :param token: A string with the authorization token. """ cls.token_model.get_key(user_id, 'auth', token).delete() @classmethod def create_signup_token(cls, user_id): entity = cls.token_model.create(user_id, 'signup') return entity.token @classmethod def validate_signup_token(cls, user_id, token): return cls.validate_token(user_id, 'signup', token) @classmethod def delete_signup_token(cls, user_id, token): cls.token_model.get_key(user_id, 'signup', token).delete() @classmethod def create_user(cls, auth_id, unique_properties=None, **user_values): """Creates a new user. :param auth_id: A string that is unique to the user. Users may have multiple auth ids. Example auth ids: - own:username - own:[email protected] - google:username - yahoo:username The value of `auth_id` must be unique. :param unique_properties: Sequence of extra property names that must be unique. :param user_values: Keyword arguments to create a new user entity. Since the model is an ``Expando``, any provided custom properties will be saved. To hash a plain password, pass a keyword ``password_raw``. :returns: A tuple (boolean, info). The boolean indicates if the user was created. If creation succeeds, ``info`` is the user entity; otherwise it is a list of duplicated unique properties that caused creation to fail. """ assert user_values.get('password') is None, \ 'Use password_raw instead of password to create new users.' assert not isinstance(auth_id, list), \ 'Creating a user with multiple auth_ids is not allowed, ' \ 'please provide a single auth_id.' if 'password_raw' in user_values: user_values['password'] = security.generate_password_hash( user_values.pop('password_raw'), length=12) user_values['auth_ids'] = [auth_id] user = cls(**user_values) # Set up unique properties. uniques = [('%s.auth_id:%s' % (cls.__name__, auth_id), 'auth_id')] if unique_properties: for name in unique_properties: key = '%s.%s:%s' % (cls.__name__, name, user_values[name]) uniques.append((key, name)) ok, existing = cls.unique_model.create_multi(k for k, v in uniques) if ok: user.put() return True, user else: properties = [v for k, v in uniques if k in existing] return False, properties
class UserToken(model.Model): """Stores validation tokens for users.""" created = model.DateTimeProperty(auto_now_add=True) updated = model.DateTimeProperty(auto_now=True) user = model.StringProperty(required=True, indexed=False) subject = model.StringProperty(required=True) token = model.StringProperty(required=True) @classmethod def get_key(cls, user, subject, token): """Returns a token key. :param user: User unique ID. :param subject: The subject of the key. Examples: - 'auth' - 'signup' :param token: Randomly generated token. :returns: ``model.Key`` containing a string id in the following format: ``{user_id}.{subject}.{token}.`` """ return model.Key(cls, '%s.%s.%s' % (str(user), subject, token)) @classmethod def create(cls, user, subject, token=None): """Creates a new token for the given user. :param user: User unique ID. :param subject: The subject of the key. Examples: - 'auth' - 'signup' :param token: Optionally an existing token may be provided. If None, a random token will be generated. :returns: The newly created :class:`UserToken`. """ user = str(user) token = token or security.generate_random_string(entropy=128) key = cls.get_key(user, subject, token) entity = cls(key=key, user=user, subject=subject, token=token) entity.put() return entity @classmethod def get(cls, user=None, subject=None, token=None): """Fetches a user token. :param user: User unique ID. :param subject: The subject of the key. Examples: - 'auth' - 'signup' :param token: The existing token needing verified. :returns: A :class:`UserToken` or None if the token does not exist. """ if user and subject and token: return cls.get_key(user, subject, token).get() assert subject and token, \ 'subject and token must be provided to UserToken.get().' return cls.query(cls.subject == subject, cls.token == token).get()
class User(model.Model): """""" created = model.DateTimeProperty(auto_now_add=True) updated = model.DateTimeProperty(auto_now=True) # Display name: username as typed by the user. name = model.StringProperty(required=True) # Username in lower case. UNIQUE. username = model.StringProperty(required=True) # ID for third party authentication, e.g. 'google:username'. UNIQUE. auth_id = model.StringProperty(required=True) # Primary email address. Optionally UNIQUE. email = model.StringProperty(required=True) # Hashed password. Not required because third party authentication # doesn't use password. password = model.StringProperty() @classmethod def get_key(cls, auth_id): return model.Key(cls, auth_id.lower()) @classmethod def get_by_auth_id(cls, auth_id): return cls.get_key(auth_id).get() @classmethod def get_by_username(cls, username): return cls.query(cls.username == username.lower()).get() @classmethod def get_by_email(cls, email): return cls.query(cls.email == email).get() @classmethod def get_by_auth_token(cls, auth_id, token): token_key = UserToken.get_key(auth_id, 'auth', token) user_key = cls.get_key(auth_id) # Use get_multi() to save a RPC call. valid_token, user = model.get_multi([token_key, user_key]) if valid_token and user: timestamp = int(time.mktime(valid_token.created.timetuple())) return user, timestamp return None, None @classmethod def get_by_auth_password(cls, auth_id, password): """Returns user, validating password. :raises: ``auth.InvalidAuthIdError`` or ``auth.InvalidPasswordError``. """ user = cls.get_by_auth_id(auth_id) if not user: raise auth.InvalidAuthIdError() if not security.check_password_hash(password, user.password): raise auth.InvalidPasswordError() return user @classmethod def validate_token(cls, auth_id, subject, token): return UserToken.get(user=auth_id, subject=subject, token=token) is not None @classmethod def create_auth_token(cls, auth_id): return UserToken.create(auth_id, 'auth').token @classmethod def validate_auth_token(cls, auth_id, token): return cls.validate_token(auth_id, 'auth', token) @classmethod def delete_auth_token(cls, auth_id, token): UserToken.get_key(auth_id, 'auth', token).delete() @classmethod def create_signup_token(cls, auth_id): entity = UserToken.create(auth_id, 'signup') return entity.token @classmethod def validate_signup_token(cls, auth_id, token): return cls.validate_token(auth_id, 'signup', token) @classmethod def delete_signup_token(cls, auth_id, token): UserToken.get_key(auth_id, 'signup', token).delete() @classmethod def create_user(cls, _unique_email=True, **user_values): """Creates a new user. :param _unique_email: True to require the email to be unique, False otherwise. :param user_values: Keyword arguments to create a new user entity. Required ones are: - name - username - auth_id - email Optional keywords: - password_raw (a plain password to be hashed) The properties values of `username` and `auth_id` must be unique. Optionally, `email` can also be required to be unique. :returns: A tuple (boolean, info). The boolean indicates if the user was created. If creation succeeds, ``info`` is the user entity; otherwise it is a list of duplicated unique properties that caused the creation to fail. """ assert user_values.get('password') is None, \ 'Use password_raw instead of password to create new users' if 'password_raw' in user_values: user_values['password'] = security.generate_password_hash( user_values.pop('password_raw'), length=12) user_values['username'] = user_values['username'].lower() user_values['auth_id'] = user_values['auth_id'].lower() user = User(key=cls.get_key(user_values['auth_id']), **user_values) # Unique auth id and email. unique_username = '******' % user_values['username'] uniques = [unique_username] if _unique_email: unique_email = 'User.email:%s' % user_values['email'] uniques.append(unique_email) else: unique_email = None if uniques: success, existing = unique_model.Unique.create_multi(uniques) if success: txn = lambda: user.put() if not user.key.get() else None if model.transaction(txn): return True, user else: unique_model.Unique.delete_multi(uniques) return False, ['auth_id'] else: properties = [] if unique_username in uniques: properties.append('username') if unique_email in uniques: properties.append('email') return False, properties
class User(model.Model): """Universal user model. Can be used with App Engine's default users API, own auth or third party authentication methods (OpenId, OAuth etc). """ #: Creation date. created = model.DateTimeProperty(auto_now_add=True) #: Modification date. updated = model.DateTimeProperty(auto_now=True) #: User defined unique name, also used as key_name. username = model.StringProperty(required=True) #: Password, only set for own authentication. password = model.StringProperty(required=False) #: User email email = model.StringProperty(required=False) # Admin flag. is_admin = model.BooleanProperty(default=False) #: Authentication identifier according to the auth method in use. Examples: #: * own|username #: * gae|user_id #: * openid|identifier #: * twitter|username #: * facebook|username auth_id = model.StringProperty(repeated=True) # Flag to persist the auth across sessions for third party auth. auth_remember = model.BooleanProperty(default=False) # Auth token, renewed periodically for improved security. session_id = model.StringProperty(required=True) # Auth token last renewal date. session_updated = model.DateTimeProperty(auto_now_add=True) @classmethod def get_by_username(cls, username): return cls.query(cls.username == username).get() @classmethod def get_by_auth_id(cls, auth_id): return cls.query(cls.auth_id == auth_id).get() @classmethod def create(cls, username, auth_id, **kwargs): """Creates a new user and returns it. If the username already exists, returns None. :param username: Unique username. :param auth_id: Authentication id, according the the authentication method used. :param email: Unique email address. :param kwargs: Additional entity attributes. :returns: The newly created user or None if the username already exists. """ # Assemble the unique scope/value combinations. unique_username = '******' % username unique_auth_id = 'User.auth_id:%s' % auth_id # Create the unique username, auth_id and email. uniques = [unique_username, unique_auth_id] # TODO add email to parms in tipfy.auth so that # we don't have to use kwargs here if 'email' in kwargs: unique_email = 'User.email:%s' % kwargs['email'] uniques.append(unique_email) success, existing = Unique.create_multi(uniques) if success or DEBUG: kwargs['username'] = username # make this a list so that we can have multiple auth methods. kwargs['auth_id'] = [auth_id] # Generate an initial session id. kwargs['session_id'] = create_session_id() if 'password_hash' in kwargs: # Password is already hashed. kwargs['password'] = kwargs.pop('password_hash') elif 'password' in kwargs: # Password is not hashed: generate a hash. kwargs['password'] = generate_password_hash(kwargs['password']) user = cls(**kwargs) user.put() return user else: # The ordering her is important. Email must come before # auth id or the error return will make little since to the user. if unique_email in existing: raise UniqueConstraintViolation('Email %s already ' 'exists. Try logging in.' % kwargs['email']) if unique_username in existing: raise UniqueConstraintViolation('Username %s already ' 'exists' % username) if unique_auth_id in existing: raise UniqueConstraintViolation('Auth id %s already ' 'exists' % auth_id) def set_password(self, new_password): """Sets a new, plain password. :param new_password: A plain, not yet hashed password. :returns: None. """ self.password = generate_password_hash(new_password) def check_password(self, password): """Checks if a password is valid. This is done with form login :param password: Password to be checked. :returns: True is the password is valid, False otherwise. """ if check_password_hash(self.password, password): return True return False def check_session(self, session_id): """Checks if an auth token is valid. :param session_id: Token to be checked. :returns: True is the token id is valid, False otherwise. """ if self.session_id == session_id: return True return False def renew_session(self, force=False, max_age=None): """Renews the session id if its expiration time has passed. :param force: True to force the session id to be renewed, False to check if the expiration time has passed. :returns: None. """ if not force: # Only renew the session id if it is too old. expires = datetime.timedelta(seconds=max_age) force = (self.session_updated + expires < datetime.datetime.now()) if force: self.session_id = create_session_id() self.session_updated = datetime.datetime.now() self.put() def __unicode__(self): """Returns this entity's username. :returns: Username, as unicode. """ return unicode(self.username) def __str__(self): """Returns this entity's username. :returns: Username, as unicode. """ return self.__unicode__() def __eq__(self, obj): """Compares this user entity with another one. :returns: True if both entities have same key, False otherwise. """ if not obj: return False return str(self.key) == str(obj.key) def __ne__(self, obj): """Compares this user entity with another one. :returns: True if both entities don't have same key, False otherwise. """ return not self.__eq__(obj)