class OAuth2Client(db.Model, MyOAuth2ClientMixin): __tablename__ = 'oauth2_client' id = db.Column(db.Integer, primary_key=True) user_id = db.Column( db.Integer, db.ForeignKey('user.id', ondelete='CASCADE')) class ClientTypes(str, enum.Enum): public = 'public' confidential = 'confidential' client_type = db.Column(db.Enum(ClientTypes), default=ClientTypes.public, nullable=False) default_scopes = db.Column(ScalarListType(separator=' '), nullable=False) scope = db.Column(ScalarListType(separator=' '), nullable=False) user = db.relationship('User') @property def default_redirect_uri(self): return self.get_default_redirect_uri() @classmethod def find(cls, client_id): if not client_id: return return cls.query.get(client_id)
class OAuth2Client(db.Model): """ Model that binds OAuth2 Client ID and Secret to a specific User. """ __tablename__ = 'oauth2_client' client_id = db.Column(db.String(length=40), primary_key=True) client_secret = db.Column(db.String(length=55), nullable=False) user_id = db.Column(db.ForeignKey('user.id', ondelete='CASCADE'), index=True, nullable=False) user = db.relationship(User) class ClientTypes(str, enum.Enum): public = 'public' confidential = 'confidential' client_type = db.Column(db.Enum(ClientTypes), default=ClientTypes.public, nullable=False) redirect_uris = db.Column(ScalarListType(separator=' '), default=[], nullable=False) default_scopes = db.Column(ScalarListType(separator=' '), nullable=False) @property def default_redirect_uri(self): redirect_uris = self.redirect_uris if redirect_uris: return redirect_uris[0] return None @classmethod def find(cls, client_id): if not client_id: return return cls.query.get(client_id)
class OAuth2Client(db.Model): """ Model that binds OAuth2 Client ID and Secret to a specific User. """ __tablename__ = 'oauth2_client' guid = db.Column(db.GUID, default=uuid.uuid4, primary_key=True) secret = db.Column(db.String(length=64), default=_generate_salt_64, nullable=False) user_guid = db.Column(db.ForeignKey('user.guid', ondelete='CASCADE'), index=True, nullable=False) user = db.relationship(User) class ClientLevels(str, enum.Enum): public = 'public' session = 'session' confidential = 'confidential' level = db.Column(db.Enum(ClientLevels), default=ClientLevels.public, nullable=False) redirect_uris = db.Column(ScalarListType(separator=' '), default=[], nullable=False) default_scopes = db.Column(ScalarListType(separator=' '), nullable=False) @property def default_redirect_uri(self): redirect_uris = self.redirect_uris if redirect_uris: return redirect_uris[0] return None @property def client_id(self): return self.guid @property def client_secret(self): return self.secret @classmethod def find(cls, guid): if not guid: return None return cls.query.get(guid) def validate_scopes(self, scopes): # The only reason for this override is that Swagger UI has a bug which leads to that # `scope` parameter contains extra spaces between scopes: # https://github.com/frol/flask-restplus-server-example/issues/131 return set(self.default_scopes).issuperset(set(scopes) - {''}) def delete(self): with db.session.begin(): db.session.delete(self)
class OAuth2Grant(db.Model): """ Intermediate temporary helper for OAuth2 Grants. """ __tablename__ = 'oauth2_grant' id = db.Column(db.Integer, primary_key=True) # pylint: disable=invalid-name user_id = db.Column(db.ForeignKey('user.id', ondelete='CASCADE'), index=True, nullable=False) user = db.relationship('User') client_id = db.Column( db.String(length=40), db.ForeignKey('oauth2_client.client_id'), index=True, nullable=False, ) client = db.relationship('OAuth2Client') code = db.Column(db.String(length=255), index=True, nullable=False) redirect_uri = db.Column(db.String(length=255), nullable=False) expires = db.Column(db.DateTime, nullable=False) scopes = db.Column(ScalarListType(separator=' '), nullable=False) def delete(self): db.session.delete(self) db.session.commit() return self @classmethod def find(cls, client_id, code): return cls.query.filter_by(client_id=client_id, code=code).first()
class Voting(db.Model): __tablename__ = 'voting' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), nullable=False) description = db.Column(db.String(512), nullable=False) start_at = db.Column(db.DateTime, default=timezone.now) finish_at = db.Column(db.DateTime, nullable=False) items = db.Column(ScalarListType(), nullable=False) users = db.Column(ScalarListType(), default=[]) enabled = db.Column(db.Boolean, default=True) anonymous = db.Column(db.Boolean, default=True) can_discard = db.Column(db.Boolean, default=True) select_count = db.Column(db.Integer, default=1) members = db.relationship('VotingMember', backref='voting', lazy='dynamic') @validates('finish_at') def validate_finish_at(self, key, value): if value <= self.start_at: raise ValueError('`finish_at` must be more then `start_at`') return value @hybrid_property def active(self) -> bool: return self.finish_at > timezone.now() >= self.start_at and self.enabled @active.expression def active(cls) -> bool: return db.and_( cls.finish_at > timezone.now(), cls.start_at <= timezone.now(), cls.enabled ) def result(self) -> list: if timezone.now() < self.start_at: raise VotingError('Voting not started') if self.anonymous: return [m.result for m in self.memderships] else: return [(m.result, m.user_id) for m in self.memderships]
class OAuth2Grant(db.Model): """ Intermediate temporary helper for OAuth2 Grants. """ __tablename__ = 'oauth2_grant' guid = db.Column( db.GUID, default=uuid.uuid4, primary_key=True ) # pylint: disable=invalid-name user_guid = db.Column( db.ForeignKey('user.guid', ondelete='CASCADE'), index=True, nullable=False ) user = db.relationship('User') client_guid = db.Column( db.GUID, db.ForeignKey('oauth2_client.guid'), index=True, nullable=False, ) client = db.relationship('OAuth2Client') code = db.Column(db.String(length=255), index=True, nullable=False) redirect_uri = db.Column(db.String(length=255), nullable=False) expires = db.Column(db.DateTime, nullable=False) scopes = db.Column(ScalarListType(separator=' '), nullable=False) def delete(self): with db.session.begin(): db.session.delete(self) @property def client_id(self): return self.client_guid @classmethod def find(cls, client_guid, code): return cls.query.filter_by(client_guid=client_guid, code=code).first() @property def is_expired(self): now_utc = datetime.datetime.now(tz=pytz.utc) expired = now_utc > self.expires.replace(tzinfo=pytz.utc) return expired
class OAuth2Token(db.Model): """ OAuth2 Access Tokens storage model. """ __tablename__ = 'oauth2_token' id = db.Column(db.Integer, primary_key=True) # pylint: disable=invalid-name client_id = db.Column( db.String(length=40), db.ForeignKey('oauth2_client.client_id'), index=True, nullable=False, ) client = db.relationship('OAuth2Client') user_id = db.Column(db.ForeignKey('user.id', ondelete='CASCADE'), index=True, nullable=False) user = db.relationship('User') class TokenTypes(str, enum.Enum): # currently only bearer is supported Bearer = 'Bearer' token_type = db.Column(db.Enum(TokenTypes), nullable=False) access_token = db.Column(db.String(length=255), unique=True, nullable=False) refresh_token = db.Column(db.String(length=255), unique=True, nullable=True) expires = db.Column(db.DateTime, nullable=False) scopes = db.Column(ScalarListType(separator=' '), nullable=False) @classmethod def find(cls, access_token=None, refresh_token=None): if access_token: return cls.query.filter_by(access_token=access_token).first() if refresh_token: return cls.query.filter_by(refresh_token=refresh_token).first() return None def delete(self): with db.session.begin(): db.session.delete(self)
class VotingMember(InternalAPIMixin, db.Model): __tablename__ = 'voting_members' __table_args__ = ( db.UniqueConstraint('user_id', 'voting_id'), ) id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, nullable=False) voting_id = db.Column(db.Integer, db.ForeignKey('voting.id'), nullable=False) result = db.Column(ScalarListType(), nullable=False) created = db.Column(db.DateTime, default=timezone.now) updated = db.Column(db.DateTime, onupdate=timezone.now) voted = db.Column(db.Boolean, default=False) enabled = db.Column(db.Boolean, default=True) async def get_user(self) -> RemoteUser: data = await self.internal_request('login', 'get_user', user_id=self.user_id) return RemoteUser(**data) @as_future def vote(self, items: Optional[list] = None) -> None: items = self.result or items if not items: raise VotingError('No items to vote') if not self.voting.active: raise VotingError('Voting not active') if not self.enabled: raise VotingError('Voting member disabled') if self.voted: raise VotingError('Already voted') if len(items) != self.voting.select_count: raise VotingError('Voting items count: %s/%s' % (len(items), self.voting.select_count)) if not set(items).issubset(self.voting.items): raise VotingError('Voting items is %s. Must be a subset ' 'of %s' % (','.join(items), ','.join(self.voting.items))) self.result = items self.voted = True self.save() @as_future def discard(self) -> None: if self.voting.can_discard: self.delete() else: raise VotingError('Cannot discard')
class OAuth2Token(db.Model): """ OAuth2 Access Tokens storage model. """ __tablename__ = 'oauth2_token' guid = db.Column( db.GUID, default=uuid.uuid4, primary_key=True ) # pylint: disable=invalid-name client_guid = db.Column( db.GUID, db.ForeignKey('oauth2_client.guid'), index=True, nullable=False, ) client = db.relationship('OAuth2Client') user_guid = db.Column( db.ForeignKey('user.guid', ondelete='CASCADE'), index=True, nullable=False ) user = db.relationship('User') class TokenTypes(str, enum.Enum): # currently only bearer is supported Bearer = 'Bearer' token_type = db.Column(db.Enum(TokenTypes), nullable=False) access_token = db.Column( db.String(length=128), default=security.generate_random_128, unique=True, nullable=False, ) refresh_token = db.Column( db.String(length=128), default=security.generate_random_128, unique=True, nullable=True, ) expires = db.Column(db.DateTime, nullable=False) scopes = db.Column(ScalarListType(separator=' '), nullable=False) @property def client_id(self): return self.client_guid @classmethod def find(cls, access_token=None, refresh_token=None): response = None if access_token: response = cls.query.filter_by(access_token=access_token).first() if refresh_token: response = cls.query.filter_by(refresh_token=refresh_token).first() return response def delete(self): with db.session.begin(): db.session.delete(self) @property def is_expired(self): now_utc = datetime.datetime.now(tz=pytz.utc) expired = now_utc > self.expires.replace(tzinfo=pytz.utc) return expired
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))
def upgrade(): # ### commands auto generated by Alembic - please adjust! ### op.add_column( 'project_classes', sa.Column('presentation_list', ScalarListType(), nullable=True))