def update(self, form: Optional[FlaskForm] = None) -> None: from openatlas.util.display import sanitize if form: # e.g. imports have no forms self.save_nodes(form) if self.class_.name != 'object_location': self.set_dates(form) self.update_aliases(form) for field in ['name', 'description']: if hasattr(form, field): setattr(self, field, getattr(form, field).data) if hasattr(form, 'name_inverse'): # A directional node, e.g. actor actor relation self.name = form.name.data.replace('(', '').replace(')', '').strip() if form.name_inverse.data.strip(): inverse = form.name_inverse.data.replace('(', '').replace(')', '').strip() self.name += ' (' + inverse + ')' if self.class_.name == 'type': self.name = sanitize(self.name, 'node') elif self.class_.name == 'object_location': self.name = 'Location of ' + self.name self.description = None Db.update({ 'id': self.id, 'name': str(self.name).strip(), 'begin_from': Date.datetime64_to_timestamp(self.begin_from), 'begin_to': Date.datetime64_to_timestamp(self.begin_to), 'end_from': Date.datetime64_to_timestamp(self.end_from), 'end_to': Date.datetime64_to_timestamp(self.end_to), 'begin_comment': str(self.begin_comment).strip() if self.begin_comment else None, 'end_comment': str(self.end_comment).strip() if self.end_comment else None, 'description': sanitize(self.description, 'text')})
def get_by_project_id(project_id: int) -> List[Entity]: entities = [] for row in Db.get_by_project_id(project_id): entity = Entity(row) entity.origin_id = ['origin_id'] entities.append(entity) return entities
def get_display_files() -> list[Entity]: entities = [] for row in Db.get_by_class('file', types=True): ext = g.file_stats[row['id']]['ext'] \ if row['id'] in g.file_stats else 'N/A' if ext in app.config['DISPLAY_FILE_EXTENSIONS']: entities.append(Entity(row)) return entities
def update_gis(self, gis_data: dict[str, Any], new: bool) -> None: from openatlas.models.gis import Gis if not self.location: self.location = self.get_linked_entity_safe('P53') if not new: Db.update({ 'id': self.location.id, 'name': f'Location of {str(self.name).strip()}', 'begin_from': None, 'begin_to': None, 'end_from': None, 'end_to': None, 'begin_comment': None, 'end_comment': None, 'description': None}) Gis.delete_by_entity(self.location) Gis.insert(self.location, gis_data)
def update_attributes(self, attributes: dict[str, Any]) -> None: for key, value in attributes.items(): setattr(self, key, value) Db.update({ 'id': self.id, 'name': str(self.name).strip(), 'begin_from': datetime64_to_timestamp(self.begin_from), 'begin_to': datetime64_to_timestamp(self.begin_to), 'end_from': datetime64_to_timestamp(self.end_from), 'end_to': datetime64_to_timestamp(self.end_to), 'begin_comment': str(self.begin_comment).strip() if self.begin_comment else None, 'end_comment': str(self.end_comment).strip() if self.end_comment else None, 'description': sanitize(self.description, 'text') if self.description else None })
def get_by_class( classes: Union[str, list[str]], types: bool = False, aliases: bool = False) -> list[Entity]: if aliases: # For performance: check classes if they can have an alias aliases = False for class_ in classes if isinstance(classes, list) \ else [classes]: if g.classes[class_].alias_allowed: aliases = True break return [Entity(row) for row in Db.get_by_class(classes, types, aliases)]
def get_by_ids(ids: Iterable[int], types: bool = False, aliases: bool = False) -> list[Entity]: entities = [] for row in Db.get_by_ids(ids, types, aliases): if row['id'] in g.types: entities.append(g.types[row['id']]) elif row['id'] in g.reference_systems: entities.append(g.reference_systems[row['id']]) else: entities.append(Entity(row)) return entities
def insert(class_name: str, name: str, description: Optional[str] = None) -> Entity: from openatlas.util.display import sanitize if not name: # pragma: no cover from openatlas import logger logger.log('error', 'model', 'Insert entity without name') abort(422) id_ = Db.insert({ 'name': str(name).strip(), 'code': g.classes[class_name].cidoc_class.code, 'system_class': class_name, 'description': sanitize(description, 'text') if description else None}) return Entity.get_by_id(id_)
def get_by_id(id_: int, nodes: bool = False, aliases: bool = False) -> Union[Entity, Node, 'ReferenceSystem']: if id_ in g.nodes: return g.nodes[id_] if id_ in g.reference_systems: return g.reference_systems[id_] data = Db.get_by_id(id_, nodes, aliases) if not data: if 'activity' in request.path: raise AttributeError # pragma: no cover, re-raise if user activity view abort(418) return Entity(data)
def get_by_class_code( code: Union[str, list[str]], parser: dict[str, Any]) -> list[dict[str, Any]]: sql_parts = Filter.get_filter( parameters={ 'codes': tuple(code if isinstance(code, list) else [code])}, parser=parser) sql = Entity.select_sql(types=True) + f""" WHERE cidoc_class_code IN %(codes)s {sql_parts['clause']} GROUP BY e.id ORDER BY {', '.join(parser['column'])} {parser['sort']};""" g.cursor.execute(sql, sql_parts['parameters']) return [dict(row) for row in g.cursor.fetchall()]
def get_by_system_class(classes: str, parser: Dict[str, Any]) -> List[Dict[str, Any]]: sql_parts = Filter.get_filter(parameters={ 'class': tuple(classes if isinstance(classes, list) else [classes]) }, parser=parser) sql = Entity.build_sql(nodes=True, aliases=True) + f""" WHERE e.system_class IN %(class)s {sql_parts['clause']} GROUP BY e.id ORDER BY {', '.join(parser['column'])} {parser['sort']};""" g.cursor.execute(sql, sql_parts['parameters']) return [dict(row) for row in g.cursor.fetchall()]
def get_by_class( classes: Union[str, List[str]], nodes: bool = False, aliases: bool = False) -> List[Entity]: if aliases: # For performance: check classes if they can have an alias aliases_needed = False for system_class in classes if isinstance(classes, list) \ else [classes]: if g.classes[system_class].alias_possible: aliases_needed = True break aliases = aliases_needed return [Entity(row) for row in Db.get_by_class(classes, nodes, aliases)]
def get_by_system_class(classes: str, parser: Dict[str, Any]) -> List[Entity]: parameters = { 'class': tuple(classes if isinstance(classes, list) else [classes]) } sql = Db.build_sql(nodes=True, aliases=True) + """ WHERE e.system_class IN %(class)s {clause} GROUP BY e.id ORDER BY {order} {sort};""".format( clause=Filter.get_filter(parameters=parameters, parser=parser), order=', '.join(parser['column']), sort=parser['sort']) g.cursor.execute(sql, parameters) return [Entity(row) for row in g.cursor.fetchall()]
def get_by_class_code_api(code: Union[str, List[str]], parser: Dict[str, Any]) -> List[Entity]: parameters = { 'codes': tuple(code if isinstance(code, list) else [code]) } sql = Db.build_sql(nodes=True) + """ WHERE class_code IN %(codes)s {clause} GROUP BY e.id ORDER BY {order} {sort};""".format( clause=Filter.get_filter(parameters=parameters, parser=parser), order=', '.join(parser['column']), sort=parser['sort']) g.cursor.execute(sql, parameters) return [Entity(row) for row in g.cursor.fetchall()]
def get_by_id( id_: int, types: bool = False, aliases: bool = False) -> Union[Entity, Type, ReferenceSystem]: if id_ in g.types: return g.types[id_] if id_ in g.reference_systems: return g.reference_systems[id_] data = Db.get_by_id(id_, types, aliases) if not data: if 'activity' in request.path: # Re-raise if in user activity view raise AttributeError # pragma: no cover abort(418) return Entity(data)
def test_links(self) -> None: from openatlas.database.entity import Entity as DbEntity from openatlas.database.link import Link as DbLink with app.app_context(): with app.test_request_context(): app.preprocess_request() # type: ignore id_ = DbEntity.insert({ 'name': 'Invalid linked entity', 'openatlas_class_name': 'artifact', 'code': 'E13', 'description': ''}) DbLink.insert({ 'property_code': 'P86', 'domain_id': id_, 'range_id': id_, 'description': '', 'type_id': None}) rv = self.app.get(url_for('admin_check_links')) assert b'Invalid linked entity' in rv.data
def search(data: dict[str, Any]) -> list[Entity]: if not data['term']: return [] if 'person' in data['classes'] \ or 'place' in data['classes'] \ or 'group' in data['classes']: data['classes'].append('appellation') entities = [] for row in Db.search(data['term'], data['classes'], data['desc'], data['own'], current_user.id): if row['openatlas_class_name'] == 'appellation': entity = Link.get_linked_entity_safe(row['id'], 'P1', True) if entity.class_.name not in data['classes']: continue else: entity = Entity(row) if entity and check_dates(entity, data): entities.append(entity) return list({d.id: d for d in entities}.values()) # Remove duplicates
def get_orphans() -> List[Entity]: return [Entity.get_by_id(row['id']) for row in Db.get_orphans()]
def get_overview_counts() -> Dict[str, int]: return Db.get_overview_counts(g.class_view_mapping.keys())
def get_by_cidoc_class(code: Union[str, List[str]]) -> List[Entity]: return [Entity(row) for row in Db.get_by_cidoc_class(code)]
def get_latest(limit: int) -> List[Entity]: return [Entity(row) for row in Db.get_latest(g.class_view_mapping.keys(), limit)]
def get_by_ids(ids: Iterable[int], nodes: bool = False) -> List[Entity]: return [Entity(row) for row in Db.get_by_ids(ids, nodes)]
def get_circular() -> List[Entity]: # Get entities that are linked to itself. return [Entity.get_by_id(row['domain_id']) for row in Db.get_circular()]
def get_display_files() -> List[Entity]: entities = [] for row in Db.get_by_class('file', nodes=True): if get_file_extension(row['id']) in app.config['DISPLAY_FILE_EXTENSIONS']: entities.append(Entity(row)) return entities
def get_by_class(classes: Union[str, List[str]], nodes: bool = False, aliases: bool = False) -> List[Entity]: return [Entity(row) for row in Db.get_by_class(classes, nodes, aliases)]
def delete_(id_: Union[int, List[int]]) -> None: if not id_: return Db.delete(id_ if isinstance(id_, list) else [id_])
def set_profile_image(id_: int, origin_id: int) -> None: Db.set_profile_image(id_, origin_id)
def get_profile_image_id(self) -> Optional[int]: return Db.get_profile_image_id(self.id)
def search(form: FlaskForm) -> ValuesView[Entity]: if not form.term.data: return {}.values() classes = form.classes.data if 'person' in classes: classes.append('actor_appellation') if 'place' in classes: classes.append('appellation') # Repopulate date fields with autocompleted values from_date = Date.form_to_datetime64(form.begin_year.data, form.begin_month.data, form.begin_day.data) to_date = Date.form_to_datetime64(form.end_year.data, form.end_month.data, form.end_day.data, to_date=True) if from_date: string = str(from_date) if string.startswith('-') or string.startswith('0000'): string = string[1:] parts = string.split('-') form.begin_month.raw_data = None form.begin_day.raw_data = None form.begin_month.data = int(parts[1]) form.begin_day.data = int(parts[2]) if to_date: string = str(to_date) if string.startswith('-') or string.startswith('0000'): string = string[1:] # pragma: no cover parts = string.split('-') form.end_month.raw_data = None form.end_day.raw_data = None form.end_month.data = int(parts[1]) form.end_day.data = int(parts[2]) # Get search results entities = [] for row in Db.search(form.term.data, tuple(form.classes.data), form.desc.data, form.own.data, current_user.id): if row['system_class'] == 'actor_appellation': # If found in actor alias entity = Link.get_linked_entity(row['id'], 'P131', True) elif row['system_class'] == 'appellation': # If found in place alias entity = Link.get_linked_entity(row['id'], 'P1', True) else: entity = Entity(row) if not entity: # pragma: no cover continue if not from_date and not to_date: entities.append(entity) continue # Date criteria present but entity has no dates if not entity.begin_from and not entity.begin_to and not entity.end_from \ and not entity.end_to: if form.include_dateless.data: # Include dateless entities entities.append(entity) continue # Check date criteria dates = [ entity.begin_from, entity.begin_to, entity.end_from, entity.end_to ] begin_check_ok = False if not from_date: begin_check_ok = True # pragma: no cover else: for date in dates: if date and date >= from_date: begin_check_ok = True end_check_ok = False if not to_date: end_check_ok = True # pragma: no cover else: for date in dates: if date and date <= to_date: end_check_ok = True if begin_check_ok and end_check_ok: entities.append(entity) return {d.id: d for d in entities}.values() # Remove duplicates before returning
def remove_profile_image(self) -> None: Db.remove_profile_image(self.id)