class Publisher(db.Model): """ Publisher database, One-to-Many """ __tablename__ = 'publisher' id = db.Column(db.String(128), primary_key=True, default=lambda: uuid.uuid4().hex) name = db.Column(db.String(128), nullable=False, unique=True) department = db.Column(db.String(128)) web = db.Column(db.String(1024)) email = db.Column(db.String(128)) role = db.Column(db.String(64)) created = db.Column(db.DateTime(), default=func.now()) updated = db.Column(db.DateTime(), onupdate=func.now()) organization_id = db.Column(db.Integer, db.ForeignKey('organization.id')) organization = db.relationship('Organization', backref='publishers') @classmethod def get(cls, publisher_id=None, publisher_name=None, **kwargs): if publisher_id is not None: publisher = cls.query.filter_by(id=publisher_id).first() if publisher is None: raise ObjectDoesNotExist('Publisher "%s" does not exists' % publisher_id) return publisher if publisher_name is not None: publisher = cls.query.filter_by(name=publisher_name).first() if publisher is None: raise ObjectDoesNotExist('Publisher "%s" does not exists' % publisher_name) return publisher if len(kwargs) > 0: return cls.query.filter_by(**kwargs).all() return None @classmethod def create(cls, **params): """Add a new publisher """ new_publisher = Publisher(**params) db.session.add(new_publisher) return new_publisher
class Reference(db.Model): """ Reference database, Many-to-One """ __tablename__ = 'reference' id = db.Column(db.String(128), primary_key=True, default=lambda: uuid.uuid4().hex) dataset_id = db.Column(db.String(128), db.ForeignKey('dataset.id'), nullable=False) title = db.Column(db.String(128), nullable=False, unique=True) url = db.Column(db.String(1024), nullable=False) snapshot = db.Column(db.String(512)) created = db.Column(db.DateTime(), default=func.now()) updated = db.Column(db.DateTime(), onupdate=func.now()) @classmethod def get(cls, ref_id=None, ref_title=None, **kwargs): if ref_id is not None: reference = cls.query.filter_by(id=ref_id).first() if reference is None: raise ObjectDoesNotExist('Reference "%s" does not exists' % ref_id) return reference if ref_title is not None: reference = cls.query.filter_by(name=ref_title).first() if reference is None: raise ObjectDoesNotExist('Reference "%s" does not exists' % ref_title) return reference if len(kwargs) > 0: return cls.query.filter_by(**kwargs).all() return None @classmethod def create(cls, **params): """Add a new reference """ new_ref = Reference(**params) db.session.add(new_ref) return new_ref
class Organization(db.Model): """ Database of dataset-publishing organizations, One-to-Many """ __tablename__ = 'organization' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), nullable=False, unique=True) email = db.Column(db.String(128)) web = db.Column(db.String(1024)) country = db.Column(db.String(28)) created = db.Column(db.DateTime(), default=func.now()) updated = db.Column(db.DateTime(), onupdate=func.now()) @classmethod def get(cls, org_id=None, org_name=None, **kwargs): if org_id is not None: organization = cls.query.filter_by(id=org_id).first() if organization is None: raise ObjectDoesNotExist('Organization "%s" does not exists' % org_id) return organization if org_name is not None: organization = cls.query.filter_by(name=org_name).first() if organization is None: raise ObjectDoesNotExist('Organization "%s" does not exists' % org_name) return organization if len(kwargs) > 0: return cls.query.filter_by(**kwargs).all() return None @classmethod def create(cls, **params): """Add a new Organization """ new_org = Organization(**params) db.session.add(new_org) return new_org
class License(db.Model): """ License database, One-to-Many """ __tablename__ = 'license' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), nullable=False, unique=True) url = db.Column(db.String(1024)) type = db.Column(db.String(64)) created = db.Column(db.DateTime(), default=func.now()) updated = db.Column(db.DateTime(), onupdate=func.now()) @classmethod def get(cls, license_id=None, license_name=None, **kwargs): if license_id is not None: license = cls.query.filter_by(id=license_id).first() if license is None: raise ObjectDoesNotExist('License "%s" does not exists' % license_id) return license if license_name is not None: license = cls.query.filter_by(name=license_name).first() if license is None: raise ObjectDoesNotExist('License "%s" does not exists' % license_name) return license if len(kwargs) > 0: return cls.query.filter_by(**kwargs).all() return None @classmethod def create(cls, **params): """Add a new License """ new_license = License(**params) db.session.add(new_license) return new_license
class UserStarStory(db.Model): """ User staring on stories """ __tablename__ = 'user_star_story' __table_args__ = (db.PrimaryKeyConstraint('user_id', 'story_id'), ) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) story_id = db.Column(db.String(128), db.ForeignKey('story.id'), nullable=True) stared_time = db.Column(db.DateTime(), default=func.now())
class UserFollowers(db.Model): """ User bidirectional following relationships """ __tablename__ = 'user_followers' __table_args__ = (db.PrimaryKeyConstraint('user_id', 'follower_id'), ) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) follower_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) issued_time = db.Column(db.DateTime(), default=func.now())
class Comment(db.Model): """ Database of user comments on datasets and stories """ __tablename__ = 'comment' id = db.Column(db.String(128), primary_key=True, nullable=False) comment = db.Column(db.Text, nullable=False) target_id = db.Column(db.String(128), nullable=False) target_type = db.Column(db.Integer, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) user = db.relationship('User', backref='comments') stars = db.Column(db.Integer, default=0) created = db.Column(db.DateTime(), default=func.now()) updated = db.Column(db.DateTime(), onupdate=func.now()) @classmethod def comment_id(cls): return uuid.uuid4().hex @classmethod def create(cls, user_id, target_id, target_type, comment): """ Create a new comment :param user_id: the user id :param target_id: the target id :param target_type: the target type, as an instance of `CommentType` :param comment: comment content :return: created comment """ cid = cls.comment_id() comment = Comment(id=cid, comment=comment, target_id=target_id, target_type=int(target_type), user_id=user_id) db.session.add(comment) return comment @classmethod def get(cls, comment_id=None, **kwargs): """Get specific comment or a general query""" if comment_id is not None: comment = cls.query.filter_by(id=comment_id).first() if comment is None: raise ObjectDoesNotExist('Comment "%s" does not exists' % comment_id) return comment return cls.query.filter_by(**kwargs).all() @classmethod def delete(cls, comment_id=None, comment=None): if comment_id is not None: comment = cls.get(comment_id=comment_id) db.session.delete(comment) @classmethod def get_target_comments(cls, target_id, target_type=None): """ Get all comments of a target""" params = {'target_id': target_id} if target_type is not None: params.update(target_type=int(target_type)) return cls.get(**params) @classmethod def delete_target_all_comments(cls, target_id, target_type=None): comments = cls.get_target_comments(target_id, target_type) for comment in comments: db.session.delete(comment)
class User(db.Model): """ User database model. """ id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(length=80), unique=True, nullable=False) password = db.Column(column_types.PasswordType(max_length=128, schemes=('bcrypt', )), nullable=False) email = db.Column(column_types.EmailType(length=120), unique=True, nullable=False) first_name = db.Column(db.String(length=30), default='', nullable=False) middle_name = db.Column(db.String(length=30), default='', nullable=False) last_name = db.Column(db.String(length=30), default='', nullable=False) organization = db.Column(db.String(128)) github = db.Column(db.String(128)) country = db.Column(db.String(64)) bio = db.Column(db.Text) followers = db.Column(db.Integer, default=0, nullable=False) following = db.Column(db.Integer, default=0, nullable=False) created = db.Column(db.DateTime(), default=func.now(), nullable=False) updated = db.Column(db.DateTime(), onupdate=func.now(), default=func.now(), nullable=False) class StaticRoles(enum.Enum): INTERNAL = (0x8000, "Internal") ADMIN = (0x4000, "Admin") REGULAR_USER = (0x2000, "Regular User") ACTIVE = (0x1000, "Active Account") @property def mask(self): return self.value[0] @property def title(self): return self.value[1] static_roles = db.Column(db.Integer, default=0, nullable=False) is_internal = _get_is_static_role_property('is_internal', StaticRoles.INTERNAL) is_admin = _get_is_static_role_property('is_admin', StaticRoles.ADMIN) is_regular_user = _get_is_static_role_property('is_regular_user', StaticRoles.REGULAR_USER) is_active = _get_is_static_role_property('is_active', StaticRoles.ACTIVE) def __repr__(self): return ("<{class_name}(" "id={self.id}, " "username=\"{self.username}\", " "email=\"{self.email}\", " "is_internal={self.is_internal}, " "is_admin={self.is_admin}, " "is_regular_user={self.is_regular_user}, " "is_active={self.is_active}, " ")>".format(class_name=self.__class__.__name__, self=self)) def has_static_role(self, role): return (self.static_roles & role.mask) != 0 def set_static_role(self, role): if self.has_static_role(role): return self.static_roles |= role.mask def unset_static_role(self, role): if not self.has_static_role(role): return self.static_roles ^= role.mask def check_owner(self, user): return self == user @property def is_authenticated(self): return True @property def is_anonymous(self): return False @classmethod def find_with_password(cls, username, password): """ Args: username (str) password (str) - plain-text password Returns: user (User) - if there is a user with a specified username and password, None otherwise. """ user = cls.query.filter_by(username=username).first() if not user: return None if user.password == password: return user return None @classmethod def get(cls, user_id=None, username=None, **kwargs): """ DAO: query dataset by ID or arguments. :return: Dataset object or None """ if user_id is not None: user = cls.query.filter_by(id=user_id).first() if user is None: raise ObjectDoesNotExist('User "%s" does not exists' % user_id) return user if username is not None: user = cls.query.filter_by(username=username).first() if user is None: raise ObjectDoesNotExist('User "%s" does not exists' % username) return user if len(kwargs) > 0: return cls.query.filter_by(**kwargs).all() return None def follows(self, another_id): """Follow another user """ follower = UserFollowers(user_id=another_id, follower_id=self.id) db.session.add(follower) # Update stat. another = self.query.get_or_404(another_id) another.followers += 1 self.following += 1 def unfollows(self, another_id): """Unfollow another user """ follower = UserFollowers.query \ .filter_by(user_id=another_id, follower_id=self.id) \ .first_or_404() # Update stat. another = self.query.get_or_404(another_id) if another.followers > 0: another.followers -= 1 if self.following > 0: self.following -= 1 db.session.delete(follower) @classmethod def query_all_followers(cls, uid): """Return query of all followers of current user """ followers_query = cls.query \ .join(UserFollowers, User.id == UserFollowers.follower_id) \ .filter(UserFollowers.user_id == uid) return followers_query @classmethod def query_all_following(cls, uid): """Return query of all following of current user """ following_query = cls.query \ .join(UserFollowers, User.id == UserFollowers.user_id) \ .filter(UserFollowers.follower_id == uid) return following_query
class Dataset(db.Model): """ Database of datasets """ __tablename__ = 'dataset' type = 'table' id = db.Column(db.String(128), primary_key=True) name = db.Column(db.String(128), unique=True, nullable=False) title = db.Column(db.String(256), nullable=False) description = db.Column(db.Text, nullable=False) homepage = db.Column(db.String(1024), nullable=False) version = db.Column(db.String(24)) keywords = db.Column(ScalarListType(separator=' '), nullable=False) image = db.Column(db.String(1024)) temporal = db.Column(db.String(64)) spatial = db.Column(db.String(64)) access_level = db.Column(db.String(32), nullable=False) copyrights = db.Column(db.String(256)) accrual_periodicity = db.Column(db.String(32)) specification = db.Column(db.Text) data_quality = db.Column(db.Boolean, nullable=False) data_dictionary = db.Column(db.String(1024)) category = db.Column(db.String(128), nullable=False) issued_time = db.Column(db.String(64)) language = db.Column(db.String(64)) stars = db.Column(db.Integer, default=0) license_id = db.Column(db.Integer, db.ForeignKey('license.id')) license = db.relationship('License', backref='datasets') organization_id = db.Column(db.Integer, db.ForeignKey('organization.id')) organization = db.relationship('Organization', backref='datasets') # Original publisher of dataset publisher_id = db.Column(db.String(128), db.ForeignKey('publisher.id')) publisher = db.relationship('Publisher', backref='datasets') # Owner contributor_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) contributor = db.relationship('User', backref='datasets') created = db.Column(db.DateTime(), default=func.now()) updated = db.Column(db.DateTime(), onupdate=func.now()) deleted = db.Column(db.Boolean, default=False) # relationships sources = db.relationship('Source', backref='dataset', lazy='dynamic') references = db.relationship('Reference', backref='dataset', lazy='dynamic') @classmethod def dataset_id(cls): return uuid.uuid4().hex @classmethod def get(cls, id=None, deleted=False, **kwargs): """ DAO: query dataset by ID or arguments. :return: Dataset object or None """ if id is not None: dataset = cls.query.filter_by(id=id, deleted=deleted, **kwargs).first() if dataset is None: raise ObjectDoesNotExist('Dataset "%s" does not exists' % id) return dataset if len(kwargs) > 0: return Dataset.query.filter_by(**kwargs).all() return None @classmethod def create(cls, **params): new_dataset = Dataset( id=cls.dataset_id(), name=params.get('name'), title=params.get('title'), license_id=params.get('license_id'), organization_id=params.get('organization_id'), publisher_id=params.get('publisher_id'), contributor_id=params.get('contributor_id'), description=params.get('description'), homepage=params.get('homepage'), version=params.get('version'), keywords=params.get('keywords'), image=params.get('image'), temporal=params.get('temporal'), spatial=params.get('spatial'), access_level=params.get('access_level'), copyrights=params.get('copyrights'), accrual_periodicity=params.get('accrual_periodicity'), specification=params.get('specification'), data_quality=params.get('data_quality'), data_dictionary=params.get('data_dictionary'), category=params.get('category'), issued_time=params.get('issued_time'), language=params.get('language'), stars=params.get('stars', 0)) db.session.add(new_dataset) return new_dataset @classmethod def update(cls, id, **kwargs): cls.query.filter_by(id=id, deleted=False).update(dict(kwargs)) return cls.get(id=id) @classmethod def delete(cls, id=None, dataset=None, hard=True): if id is not None: dataset = cls.get(id=id) if hard: db.session.delete(dataset) else: dataset.deleted = True @classmethod def delete_all(cls, hard=True): try: if not hard: db.session.get(Dataset).update(deleted=True) else: db.session.get(Dataset).delete() except Exception as e: logger.error( 'Problems occur for deleting datastes, rollback: {}'.format(e)) db.session.rollback() @classmethod def update_contributor(cls, dataset_id, contributor): dataset = cls.get(id=dataset_id) dataset.contributor = contributor @classmethod def update_license(cls, dataset_id, license): dataset = cls.get(id=dataset_id) dataset.license = license @classmethod def update_organization(cls, dataset_id, organization): dataset = cls.get(id=dataset_id) dataset.organization = organization @classmethod def update_publisher(cls, dataset_id, publisher): dataset = cls.get(id=dataset_id) dataset.publisher = publisher @classmethod def add_reference(cls, dataset_id, **params): """Add a new Reference """ name = params.get('name') reference = params.get('reference') new_ref = Reference(dataset_id=dataset_id, name=name, reference=reference) db.session.add(new_ref) return new_ref @classmethod def add_source(cls, dataset_id, **params): """Add a new Source """ title = params.get('title') format = params.get('format') access_url = params.get('access_url') download_url = params.get('download_url') if download_url is None: download_url = access_url email = params.get('email') description = params.get('description') media_type = params.get('media_type') schema = params.get('schema') new_source = Source(dataset_id=dataset_id, title=title, format=format, access_url=access_url, download_url=download_url, email=email, description=description, media_type=media_type, schema=schema) db.session.add(new_source) return new_source def associated_stories_num(self): """ Get the number of associated stories with the dataset :return: integer """ return len(list(self.stories_association))