class Reference(db.Model, IdModel, DatedModel): id = db.Column(db.Integer(), primary_key=True) document_id = db.Column(db.BigInteger, db.ForeignKey('document.id')) entity_id = db.Column(db.String(32), db.ForeignKey('entity.id')) origin = db.Column(db.String(128)) weight = db.Column(db.Integer) entity = db.relationship('Entity', backref=db.backref('references', lazy='dynamic')) document = db.relationship('Document', backref=db.backref('references', lazy='dynamic')) def to_dict(self): return { 'entity': { 'id': self.entity.id, 'name': self.entity.name, '$schema': self.entity.type }, 'weight': self.weight, 'origin': self.origin } def __repr__(self): return '<Reference(%r, %r)>' % (self.document_id, self.entity_id)
class Match(db.Model, IdModel, DatedModel): entity_id = db.Column(db.String(64)) document_id = db.Column(db.BigInteger()) collection_id = db.Column(db.Integer, db.ForeignKey('collection.id'), index=True) match_id = db.Column(db.String(64)) match_collection_id = db.Column(db.Integer, db.ForeignKey('collection.id'), index=True) score = db.Column(db.Float(), nullable=True) @classmethod def find_by_collection(cls, collection_id, other_id): q = Match.all() q = q.filter(Match.collection_id == collection_id) q = q.filter(Match.document_id == None) # noqa q = q.filter(Match.match_collection_id == other_id) q = q.order_by(Match.score.desc()) q = q.order_by(Match.id) return q @classmethod def delete_by_collection(cls, collection_id, deleted_at=None): q = db.session.query(cls) q = q.filter( or_(cls.collection_id == collection_id, cls.match_collection_id == collection_id)) q.delete(synchronize_session=False) @classmethod def group_by_collection(cls, collection_id, authz=None): from aleph.model import Collection, Permission cnt = func.count(Match.id).label('matches') parent = Match.collection_id.label('parent') coll = aliased(Collection, name='collection') q = db.session.query(cnt, parent) q = q.filter(Match.collection_id == collection_id) q = q.filter(Match.document_id == None) # noqa q = q.filter(Match.match_collection_id != collection_id) q = q.join(coll, Match.match_collection_id == coll.id) q = q.filter(coll.deleted_at == None) # noqa if authz is not None and not authz.is_admin: q = q.join(Permission, Match.match_collection_id == Permission.collection_id) q = q.filter(Permission.deleted_at == None) # noqa q = q.filter(Permission.read == True) # noqa q = q.filter(Permission.role_id.in_(authz.roles)) q = q.add_entity(coll) q = q.group_by(coll, parent) q = q.order_by(cnt.desc()) q = q.order_by(parent.asc()) return q def __repr__(self): return 'Match(%r, %r, %r, %r)' % (self.entity_id, self.document_id, self.match_id, self.score)
class EntityIdentity(db.Model, IdModel, DatedModel): CONFIRMED = 1 REJECTED = 2 UNDECIDED = 3 JUDGEMENTS = [1, 2, 3] entity_id = db.Column(db.String(32), db.ForeignKey('entity.id'), index=True) # noqa entity = db.relationship('Entity', backref=db.backref('identities', lazy='dynamic')) # noqa match_id = db.Column(db.String(254), index=True, nullable=False) judgement = db.Column(db.Integer(), nullable=False) judge_id = db.Column(db.Integer, db.ForeignKey('role.id'), nullable=True) @classmethod def judgements_by_entity(cls, entity_id): q = db.session.query(cls.match_id, cls.judgement) q = q.filter(cls.entity_id == entity_id) return {k: v for k, v in q.all()} @classmethod def entity_ids(cls, entity_id): q = db.session.query(cls.match_id) q = q.filter(cls.entity_id == entity_id) q = q.filter(cls.judgement == cls.CONFIRMED) ids = [entity_id] for mapped_id, in q.all(): ids.append(mapped_id) return ids @classmethod def by_entity_match(cls, entity_id, match_id): q = db.session.query(cls) q = q.filter(cls.entity_id == entity_id) q = q.filter(cls.match_id == match_id) return q.first() @classmethod def save(cls, entity_id, match_id, judgement, judge=None): obj = cls.by_entity_match(entity_id, match_id) if obj is None: obj = cls() obj.entity_id = entity_id obj.match_id = match_id obj.judgement = judgement obj.judge = judge db.session.add(obj) return obj def __repr__(self): return 'EntityIdentity(%r, %r, %r)' % (self.entity_id, self.match_id, self.judgement)
class Link(db.Model, UuidModel, SoftDeleteModel): type = db.Column(db.String(255), index=True) source_id = db.Column(db.String(254), index=True) target_id = db.Column(db.String(254), index=True) foreign_ids = db.Column(ARRAY(db.Unicode())) data = db.Column('data', JSONB) collection_id = db.Column(db.Integer, db.ForeignKey('collection.id'), index=True) # noqa collection = db.relationship(Collection, backref=db.backref('links', lazy='dynamic')) # noqa @property def schema(self): return schemata.get(self.type) def to_dict(self): data = super(Link, self).to_dict() data.update({ 'schema': self.type, 'data': self.data, 'foreign_ids': self.foreign_ids or [], 'collection_id': self.collection_id }) return data def __repr__(self): return '<Link(%r, %r, %r)>' % (self.id, self.source_id, self.target_id)
class Permission(db.Model, IdModel, SoftDeleteModel): """A set of rights granted to a role on a resource.""" __tablename__ = 'permission' id = db.Column(db.Integer, primary_key=True) role_id = db.Column(db.Integer, db.ForeignKey('role.id'), index=True) read = db.Column(db.Boolean, default=False) write = db.Column(db.Boolean, default=False) collection_id = db.Column(db.Integer, nullable=False) @classmethod def grant(cls, collection, role, read, write): permission = cls.by_collection_role(collection, role) if permission is None: permission = Permission() permission.role_id = role.id permission.collection_id = collection.id permission.read = read permission.write = write db.session.add(permission) db.session.flush() return permission @classmethod def by_collection_role(cls, collection, role): q = cls.all() q = q.filter(Permission.role_id == role.id) q = q.filter(Permission.collection_id == collection.id) permission = q.first() return permission
class EventLog(db.Model, IdModel, DatedModel): action = db.Column(db.Unicode(255), index=True) source_ip = db.Column(db.Unicode(255), nullable=True) path = db.Column(db.Unicode(), nullable=True) query = db.Column(JSONB) data = db.Column(JSONB) role_id = db.Column(db.Integer, db.ForeignKey('role.id'), nullable=True) @classmethod def emit(cls, action, path, source_ip=None, query=None, data=None, role_id=None): event = EventLog() event.action = action event.source_ip = source_ip event.path = path event.query = query event.data = data if role_id is not None: event.role_id = role_id db.session.add(event) return event def __repr__(self): return '<EventLog(%r, %r)>' % (self.id, self.action)
class EntityOtherName(db.Model, EntityDetails): _schema = '/entity/other_name.json#' entity_id = db.Column(db.String(32), db.ForeignKey('entity.id'), index=True) entity = db.relationship('Entity', primaryjoin="and_(Entity.id == foreign(EntityOtherName.entity_id), " # noqa "EntityOtherName.deleted_at == None)", # noqa backref=db.backref('other_names', lazy='dynamic', cascade='all, delete-orphan')) # noqa name = db.Column(db.Unicode) note = db.Column(db.Unicode) family_name = db.Column(db.Unicode) given_name = db.Column(db.Unicode) additional_name = db.Column(db.Unicode) honorific_prefix = db.Column(db.Unicode) honorific_suffix = db.Column(db.Unicode) patronymic_name = db.Column(db.Unicode) start_date = db.Column(db.DateTime) end_date = db.Column(db.DateTime) @property def display_name(self): if self.name is not None: return self.name return '' @property def terms(self): return [self.display_name] def to_dict(self): data = super(EntityOtherName, self).to_dict() data['display_name'] = self.display_name return data
class DocumentPage(db.Model): id = db.Column(db.BigInteger, primary_key=True) number = db.Column(db.Integer(), nullable=False) text = db.Column(db.Unicode(), nullable=False) document_id = db.Column(db.Integer(), db.ForeignKey('document.id'), index=True) # noqa document = db.relationship( Document, backref=db.backref('pages', cascade='all, delete-orphan')) # noqa @property def tid(self): tid = sha1(str(self.document_id)) tid.update(str(self.id)) return tid.hexdigest() def __repr__(self): return '<DocumentPage(%r,%r)>' % (self.document_id, self.number) def text_parts(self): """Utility method to get all text snippets in a record.""" text = string_value(self.text) if text is not None: yield self.text def to_dict(self): return { 'id': self.id, 'number': self.number, 'text': self.text, 'document_id': self.document_id }
class DocumentRecord(db.Model): id = db.Column(db.BigInteger, primary_key=True) sheet = db.Column(db.Integer, nullable=False) row_id = db.Column(db.Integer, nullable=False) data = db.Column(JSONB) document_id = db.Column(db.Integer(), db.ForeignKey('document.id')) document = db.relationship( Document, backref=db.backref('records', cascade='all, delete-orphan')) # noqa @property def tid(self): tid = sha1(str(self.document_id)) tid.update(str(self.sheet)) tid.update(str(self.row_id)) return tid.hexdigest() @property def text(self): if self.data is None: return [] text = [t for t in self.data.values() if t is not None] return list(set(text)) def __repr__(self): return '<DocumentRecord(%r,%r)>' % (self.document_id, self.row_id)
class DocumentRecord(db.Model): id = db.Column(db.BigInteger, primary_key=True) sheet = db.Column(db.Integer, nullable=False) row_id = db.Column(db.Integer, nullable=False) data = db.Column(JSONB) document_id = db.Column(db.Integer(), db.ForeignKey('document.id'), index=True) # noqa document = db.relationship( Document, backref=db.backref('records', cascade='all, delete-orphan')) # noqa @property def tid(self): tid = sha1(str(self.document_id)) tid.update(str(self.sheet)) tid.update(str(self.row_id)) return tid.hexdigest() def text_parts(self): """Utility method to get all text snippets in a record.""" for value in self.data.values(): text = string_value(value) if text is not None: yield value def __repr__(self): return '<DocumentRecord(%r,%r)>' % (self.document_id, self.row_id)
class DocumentPage(db.Model): id = db.Column(db.BigInteger, primary_key=True) number = db.Column(db.Integer(), nullable=False) text = db.Column(db.Unicode(), nullable=False) document_id = db.Column(db.Integer(), db.ForeignKey('document.id')) document = db.relationship( Document, backref=db.backref('pages', cascade='all, delete-orphan')) # noqa def __repr__(self): return '<DocumentPage(%r,%r)>' % (self.document_id, self.number) def text_parts(self): """Utility method to get all text snippets in a record.""" if self.text is not None and len(self.text): yield self.text def to_dict(self): return { 'id': self.id, 'number': self.number, 'text': self.text, 'document_id': self.document_id }
class Selector(db.Model): id = db.Column(db.Integer, primary_key=True) _text = db.Column('text', db.Unicode, index=True) normalized = db.Column(db.Unicode, index=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) entity_id = db.Column(db.Unicode(50), db.ForeignKey('entity.id')) entity = db.relationship('Entity', backref=db.backref( 'selectors', lazy='dynamic', cascade='all, delete-orphan')) # noqa @hybrid_property def text(self): return self._text @text.setter def text(self, text): self._text = text self.normalized = self.normalize(text) @classmethod def normalize(cls, text): return normalize(text) def __repr__(self): return '<Selector(%r, %r)>' % (self.entity_id, self.text) def __unicode__(self): return self.text
class DocumentTag(db.Model, IdModel): """A record reflects an entity or tag extracted from a document.""" TEXT_LENGTH = 1024 TYPE_PHONE = 'phone' TYPE_EMAIL = 'email' TYPE_PERSON = 'person' TYPE_ORGANIZATION = 'organization' TYPE_LOCATION = 'location' TYPE_IP = 'ip' TYPE_IBAN = 'iban' TYPES = { TYPE_PERSON: exactitude.names, TYPE_ORGANIZATION: exactitude.names, TYPE_EMAIL: exactitude.emails, TYPE_PHONE: exactitude.phones, TYPE_LOCATION: exactitude.addresses, TYPE_IP: exactitude.ips, TYPE_IBAN: exactitude.ibans, } id = db.Column(db.BigInteger, primary_key=True) origin = db.Column(db.Unicode(255), nullable=False, index=True) type = db.Column(db.Unicode(16), nullable=False) weight = db.Column(db.Integer, default=1) text = db.Column(db.Unicode(TEXT_LENGTH), nullable=True) document_id = db.Column(db.Integer(), db.ForeignKey('document.id'), index=True) # noqa document = db.relationship( "Document", backref=db.backref('tags', cascade='all, delete-orphan')) # noqa @property def field(self): type_ = self.TYPES[self.type] for (candidate, invert) in TYPES.values(): if candidate == type_: return invert @classmethod def delete_by(cls, document_id=None, origin=None, type=None): pq = db.session.query(cls) assert document_id or origin or type if document_id is not None: pq = pq.filter(cls.document_id == document_id) if origin is not None: pq = pq.filter(cls.origin == origin) if type is not None: pq = pq.filter(cls.type == type) pq.delete() db.session.flush() def __repr__(self): return '<DocumentTag(%r,%r)>' % (self.document_id, self.text)
class DocumentTag(db.Model, IdModel): """A record reflects an entity or tag extracted from a document.""" TEXT_LENGTH = 1024 TYPE_PHONE = 'phone' TYPE_EMAIL = 'email' TYPE_PERSON = 'person' TYPE_ORGANIZATION = 'organization' TYPE_LOCATION = 'location' TYPE_IP = 'ip' TYPE_IBAN = 'iban' TYPE_COUNTRY = 'country' TYPE_LANGUAGE = 'language' MAPPING = { TYPE_PERSON: 'namesMentioned', TYPE_ORGANIZATION: 'namesMentioned', TYPE_EMAIL: 'emailMentioned', TYPE_PHONE: 'phoneMentioned', TYPE_LOCATION: 'locationMentioned', TYPE_IP: 'ipMentioned', TYPE_IBAN: 'ibanMentioned', TYPE_COUNTRY: 'country', TYPE_LANGUAGE: 'language' } id = db.Column(db.BigInteger, primary_key=True) origin = db.Column(db.Unicode(255), nullable=False, index=True) type = db.Column(db.Unicode(16), nullable=False) weight = db.Column(db.Integer, default=1) text = db.Column(db.Unicode(TEXT_LENGTH), nullable=True) document_id = db.Column(db.Integer(), db.ForeignKey('document.id'), index=True) # noqa document = db.relationship("Document", backref=db.backref('tags', cascade='all, delete-orphan')) # noqa @property def field(self): type_ = registry.get(self.type) if type_ is not None and type_.group is not None: return type_.group @classmethod def delete_by(cls, document_id=None, origin=None, type=None): pq = db.session.query(cls) assert document_id or origin or type if document_id is not None: pq = pq.filter(cls.document_id == document_id) if origin is not None: pq = pq.filter(cls.origin == origin) if type is not None: pq = pq.filter(cls.type == type) pq.delete() db.session.flush() def __repr__(self): return '<DocumentTag(%r,%r)>' % (self.document_id, self.text)
class EntityIdentifier(db.Model, EntityDetails): _schema = '/entity/identifier.json#' __tablename__ = 'entity_identifier' entity_id = db.Column(db.String(32), db.ForeignKey('entity.id'), index=True) entity = db.relationship('Entity', primaryjoin="and_(Entity.id == foreign(EntityIdentifier.entity_id), " # noqa "EntityIdentifier.deleted_at == None)", # noqa backref=db.backref('identifiers', lazy='dynamic', cascade='all, delete-orphan')) # noqa identifier = db.Column(db.Unicode) scheme = db.Column(db.Unicode)
class Reference(db.Model, IdModel, DatedModel): id = db.Column(db.Integer(), primary_key=True) origin = db.Column(db.String(128)) weight = db.Column(db.Integer) document_id = db.Column(db.BigInteger, db.ForeignKey('document.id'), index=True) # noqa document = db.relationship('Document', backref=db.backref('references', lazy='dynamic')) # noqa entity_id = db.Column(db.String(32), db.ForeignKey('entity.id'), index=True) # noqa entity = db.relationship('Entity', backref=db.backref('references', lazy='dynamic')) # noqa @classmethod def index_references(cls, document_id): """Helper function to get reference data for indexing.""" # cf. aleph.index.entities.generate_entities() from aleph.model.entity import Entity q = db.session.query(Reference.entity_id, Entity.collection_id) q = q.filter(Reference.document_id == document_id) q = q.filter(Entity.id == Reference.entity_id) q = q.filter(Entity.state == Entity.STATE_ACTIVE) return q.all() def to_dict(self): return { 'entity': { 'id': self.entity.id, 'name': self.entity.name, '$schema': self.entity.type }, 'weight': self.weight, 'origin': self.origin } def __repr__(self): return '<Reference(%r, %r)>' % (self.document_id, self.entity_id)
class Reference(db.Model, IdModel, DatedModel): id = db.Column(db.Integer(), primary_key=True) document_id = db.Column(db.BigInteger, db.ForeignKey('document.id')) entity_id = db.Column(db.String(32), db.ForeignKey('entity.id')) weight = db.Column(db.Integer) entity = db.relationship(Entity, backref=db.backref('references', lazy='dynamic')) document = db.relationship(Document, backref=db.backref('references', lazy='dynamic')) @classmethod def delete_document(cls, document_id): q = cls.all().filter_by(document_id=document_id) q.delete(synchronize_session='fetch') def __repr__(self): return '<Reference(%r, %r)>' % (self.document_id, self.entity_id)
class Notification(db.Model, IdModel, DatedModel): GLOBAL = 'Global' _event = db.Column('event', db.String(255), nullable=False) channels = db.Column(ARRAY(db.String(255)), index=True) params = db.Column(JSONB) actor_id = db.Column(db.Integer, db.ForeignKey('role.id'), nullable=True) actor = db.relationship(Role) @hybrid_property def event(self): return Events.get(self._event) @event.setter def event(self, event): self._event = event.name def iterparams(self): if self.actor_id is not None: yield 'actor', Role, self.actor_id if self.event is None: return for name, clazz in self.event.params.items(): value = self.params.get(name) if value is not None: yield name, clazz, value @classmethod def publish(cls, event, actor_id=None, channels=[], params={}): notf = cls() notf.event = event notf.actor_id = actor_id notf.params = params notf.channels = list(set([c for c in channels if c is not None])) db.session.add(notf) return notf @classmethod def by_role(cls, role): sq = db.session.query(Subscription.channel) sq = sq.filter(Subscription.deleted_at == None) # noqa sq = sq.filter(Subscription.role_id == role.id) sq = sq.cte('sq') q = cls.all() q = q.filter(or_( cls.actor_id != role.id, cls.actor_id == None # noqa )) q = q.filter(cls.channels.any(sq.c.channel)) q = q.filter(cls._event.in_(Events.names())) q = q.order_by(cls.created_at.desc()) q = q.order_by(cls.id.desc()) return q
class EntityBuilding(EntityAsset): _schema = '/entity/building.json#' __mapper_args__ = {'polymorphic_identity': _schema} building_address_id = db.Column(db.String(32), db.ForeignKey('entity_address.id')) # noqa building_address = db.relationship( 'EntityAddress', primaryjoin= "and_(EntityAddress.id == foreign(EntityBuilding.building_address_id), " # noqa "EntityAddress.deleted_at == None)") # noqa
class Permission(db.Model, IdModel, SoftDeleteModel): """A set of rights granted to a role on a resource.""" __tablename__ = 'permission' COLLECTION = 'collection' SOURCE = 'source' RESOURCE_TYPES = [COLLECTION, SOURCE] id = db.Column(db.Integer, primary_key=True) role_id = db.Column(db.Integer, db.ForeignKey('role.id'), index=True) read = db.Column(db.Boolean, default=False) write = db.Column(db.Boolean, default=False) resource_id = db.Column(db.Integer, nullable=False) resource_type = db.Column(db.Enum(*RESOURCE_TYPES, name='permission_type'), nullable=False) @classmethod def grant_foreign(cls, resource, foreign_id, read, write): from aleph.model import Source, Collection, Role role = Role.by_foreign_id(foreign_id) if role is None: return if isinstance(resource, Source): cls.grant_resource(cls.SOURCE, resource.id, role, read, write) if isinstance(resource, Collection): cls.grant_resource(cls.COLLECTION, resource.id, role, read, write) @classmethod def grant_resource(cls, resource_type, resource_id, role, read, write): q = cls.all() q = q.filter(Permission.role_id == role.id) q = q.filter(Permission.resource_type == resource_type) q = q.filter(Permission.resource_id == resource_id) permission = q.first() if permission is None: permission = Permission() permission.role_id = role.id permission.resource_type = resource_type permission.resource_id = resource_id permission.read = read permission.write = write db.session.add(permission) return permission def to_dict(self): return { # 'id': self.id, 'role': self.role_id, 'read': self.read, 'write': self.write, 'resource_id': self.resource_id, 'resource_type': self.resource_type }
class Alert(db.Model, DatedModel): """A subscription to notifications on a given query.""" __tablename__ = "alert" id = db.Column(db.Integer, primary_key=True) query = db.Column(db.Unicode, nullable=True) notified_at = db.Column(db.DateTime, nullable=True) role_id = db.Column(db.Integer, db.ForeignKey("role.id"), index=True) role = db.relationship(Role, backref=db.backref("alerts", lazy="dynamic")) # noqa def update(self): self.notified_at = datetime.utcnow() db.session.add(self) db.session.flush() def to_dict(self): data = self.to_dict_dates() data.update({ "id": stringify(self.id), "query": self.query, "role_id": stringify(self.role_id), "notified_at": self.notified_at, }) return data @classmethod def by_id(cls, id, role_id=None): q = cls.all().filter_by(id=id) if role_id is not None: q = q.filter(cls.role_id == role_id) return q.first() @classmethod def by_role_id(cls, role_id): q = cls.all() q = q.filter(cls.role_id == role_id) q = q.order_by(cls.created_at.desc()) q = q.order_by(cls.id.desc()) return q @classmethod def create(cls, data, role_id): alert = cls() alert.role_id = role_id alert.query = stringify(data.get("query")) alert.update() return alert def __repr__(self): return "<Alert(%r, %r)>" % (self.id, self.query)
class EntityLegalPerson(Entity): _schema = 'entity/legal_person.json#' __mapper_args__ = {'polymorphic_identity': _schema} image = db.Column(db.Unicode, nullable=True) postal_address_id = db.Column(db.String(32), db.ForeignKey('entity_address.id')) # noqa postal_address = db.relationship( 'EntityAddress', primaryjoin= "and_(EntityAddress.id == foreign(EntityLegalPerson.postal_address_id), " # noqa "EntityAddress.deleted_at == None)") # noqa
class Permission(db.Model, IdModel, DatedModel): """A set of rights granted to a role on a collection.""" __tablename__ = "permission" id = db.Column(db.Integer, primary_key=True) role_id = db.Column(db.Integer, db.ForeignKey("role.id"), index=True) read = db.Column(db.Boolean, default=False) write = db.Column(db.Boolean, default=False) collection_id = db.Column(db.Integer, nullable=False) def to_dict(self): data = self.to_dict_dates() data.update({ "id": stringify(self.id), "role_id": stringify(self.role_id), "collection_id": stringify(self.collection_id), "read": self.read, "write": self.write, }) return data @classmethod def grant(cls, collection, role, read, write): read = read or write permission = cls.by_collection_role(collection, role) if not read: if permission is not None: permission.delete() return if permission is None: permission = Permission() permission.role_id = role.id permission.collection_id = collection.id permission.read = True permission.write = write db.session.add(permission) db.session.flush() return permission @classmethod def by_collection_role(cls, collection, role): q = cls.all() q = q.filter(Permission.role_id == role.id) q = q.filter(Permission.collection_id == collection.id) return q.first() @classmethod def delete_by_collection(cls, collection_id): q = db.session.query(cls) q = q.filter(cls.collection_id == collection_id) q.delete(synchronize_session=False)
class EntityContactDetail(db.Model, EntityDetails): _schema = '/entity/contact_detail.json#' entity_id = db.Column(db.String(32), db.ForeignKey('entity.id'), index=True) entity = db.relationship('EntityLegalPerson', primaryjoin="and_(Entity.id == foreign(EntityContactDetail.entity_id), " # noqa "EntityContactDetail.deleted_at == None)", # noqa backref=db.backref('contact_details', lazy='dynamic', cascade='all, delete-orphan')) # noqa label = db.Column(db.Unicode) type = db.Column(db.Unicode) note = db.Column(db.Unicode) valid_from = db.Column(db.DateTime) valid_until = db.Column(db.DateTime)
class Permission(db.Model, IdModel, SoftDeleteModel): """A set of rights granted to a role on a resource.""" __tablename__ = 'permission' id = db.Column(db.Integer, primary_key=True) role_id = db.Column(db.Integer, db.ForeignKey('role.id'), index=True) read = db.Column(db.Boolean, default=False) write = db.Column(db.Boolean, default=False) collection_id = db.Column(db.Integer, nullable=False) def to_dict(self): data = self.to_dict_dates() data.update({ 'id': stringify(self.id), 'role_id': stringify(self.role_id), 'collection_id': stringify(self.collection_id), 'read': self.read, 'write': self.write }) return data @classmethod def grant(cls, collection, role, read, write): permission = cls.by_collection_role(collection, role) if permission is None: permission = Permission() permission.role_id = role.id permission.collection_id = collection.id db.session.add(permission) permission.read = read or write permission.write = write permission.deleted_at = None if not permission.read: permission.deleted_at = datetime.utcnow() db.session.flush() return permission @classmethod def by_collection_role(cls, collection, role): q = cls.all() q = q.filter(Permission.role_id == role.id) q = q.filter(Permission.collection_id == collection.id) return q.first() @classmethod def delete_by_collection(cls, collection_id, deleted_at=None): if deleted_at is None: deleted_at = datetime.utcnow() q = db.session.query(cls) q = q.filter(cls.collection_id == collection_id) q.update({cls.deleted_at: deleted_at}, synchronize_session=False)
class EntityPerson(EntityLegalPerson): _schema = '/entity/person.json#' __mapper_args__ = {'polymorphic_identity': _schema} gender = db.Column(db.Unicode, nullable=True) birth_date = db.Column(db.Unicode, nullable=True) death_date = db.Column(db.Unicode, nullable=True) residential_address_id = db.Column( db.String(32), db.ForeignKey('entity_address.id')) # noqa residential_address = db.relationship( 'EntityAddress', primaryjoin= "and_(EntityAddress.id == foreign(EntityPerson.residential_address_id), " # noqa "EntityAddress.deleted_at == None)") # noqa
class EntityOrganization(EntityLegalPerson): _schema = '/entity/organization.json#' __mapper_args__ = {'polymorphic_identity': _schema} classification = db.Column(db.Unicode, nullable=True) founding_date = db.Column(db.Unicode, nullable=True) dissolution_date = db.Column(db.Unicode, nullable=True) current_status = db.Column(db.Unicode, nullable=True) registered_address_id = db.Column( db.String(32), db.ForeignKey('entity_address.id')) # noqa registered_address = db.relationship( 'EntityAddress', primaryjoin= "and_(EntityAddress.id == foreign(EntityOrganization.registered_address_id), " # noqa "EntityAddress.deleted_at == None)") # noqa headquarters_address_id = db.Column( db.String(32), db.ForeignKey('entity_address.id')) # noqa headquarters_address = db.relationship( 'EntityAddress', primaryjoin= "and_(EntityAddress.id == foreign(EntityOrganization.headquarters_address_id), " # noqa "EntityAddress.deleted_at == None)") # noqa
class DocumentRecord(db.Model): """A record reflects a row or page of a document.""" id = db.Column(db.BigInteger, primary_key=True) sheet = db.Column(db.Integer, nullable=True) index = db.Column(db.Integer, nullable=True, index=True) text = db.Column(db.Unicode, nullable=True) data = db.Column(JSONB, nullable=True) document_id = db.Column(db.Integer(), db.ForeignKey('document.id'), index=True) # noqa document = db.relationship( "Document", backref=db.backref('records', cascade='all, delete-orphan')) # noqa def text_parts(self): """Utility method to get all text snippets in a record.""" if self.data is not None: for value in self.data.values(): text = string_value(value) if text is not None: yield text text = string_value(self.text) if text is not None: yield text @classmethod def find_records(cls, document_id, ids): if not len(ids): return [] q = db.session.query(cls) q = q.filter(cls.document_id == document_id) q = q.filter(cls.id.in_(ids)) return q def to_dict(self): return { 'id': self.id, 'sheet': self.sheet, 'index': self.index, 'data': self.data, 'text': self.text, 'document_id': self.document_id } def __repr__(self): return '<DocumentRecord(%r,%r)>' % (self.document_id, self.index)
class QueryLog(db.Model, IdModel): """Records a search query conducted by a user.""" __tablename__ = 'query_log' id = db.Column(db.BigInteger, primary_key=True) query = db.Column(db.Unicode, nullable=True) session_id = db.Column(db.Unicode, nullable=True) role_id = db.Column(db.Integer, db.ForeignKey('role.id'), index=True, nullable=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) @classmethod def delete_query(cls, role_id, query): pq = db.session.query(cls) pq = pq.filter(cls.query == query) pq = pq.filter(cls.role_id == role_id) pq.delete(synchronize_session=False) @classmethod def query_log(cls, role_id=None): first = func.min(cls.created_at).label('first') last = func.max(cls.created_at).label('last') count = func.count(cls.id).label('count') q = db.session.query(cls.query, first, last, count) q = q.filter(cls.role_id == role_id) q = q.filter(cls.query != None) # noqa q = q.group_by(cls.query) q = q.order_by(last.desc()) return q @classmethod def save(cls, role_id, session_id, query): obj = cls() obj.role_id = role_id obj.session_id = session_id obj.query = query db.session.add(obj) return obj def __repr__(self): return '<QueryLog(%r, %r, %r)>' % \ (self.query, self.role_id, self.session_id)
class DocumentRecord(db.Model): """A record reflects a row or page of a document.""" id = db.Column(db.BigInteger, primary_key=True) sheet = db.Column(db.Integer, nullable=True) index = db.Column(db.Integer, nullable=True, index=True) text = db.Column(db.Unicode, nullable=True) data = db.Column(JSONB, nullable=True) document_id = db.Column(db.Integer(), db.ForeignKey('document.id'), index=True) # noqa document = db.relationship( "Document", backref=db.backref('records', cascade='all, delete-orphan')) # noqa @property def texts(self): """Utility method to get all text snippets in a record.""" if self.data is not None: for value in self.data.values(): yield value yield self.text @classmethod def find_records(cls, ids): if not len(ids): return [] q = db.session.query(cls) q = q.filter(cls.id.in_(ids)) return q @classmethod def by_index(cls, document_id, index): q = db.session.query(cls) q = db.session.query(DocumentRecord) q = q.filter(cls.document_id == document_id) q = q.filter(cls.index == index) return q.first() def __repr__(self): return '<DocumentRecord(%r,%r)>' % (self.document_id, self.index)