def get_all_nodes(): """Get and return all type and place nodes""" sql = """ SELECT e.id, e.name, e.class_code, e.description, e.system_type, e.created, e.modified, es.id AS super_id, COUNT(e2.id) AS count, COUNT(lp.id) AS count_property FROM model.entity e -- get super LEFT JOIN model.link l ON e.id = l.domain_id AND l.property_code = %(property_code)s LEFT JOIN model.entity es ON l.range_id = es.id -- get count LEFT JOIN model.link l2 ON e.id = l2.range_id LEFT JOIN model.entity e2 ON l2.domain_id = e2.id AND (l2.property_code = 'P2' OR (l2.property_code = 'P89' AND e2.system_type = 'place location')) LEFT JOIN model.link_property lp ON e.id = lp.range_id AND lp.property_code = 'P2' WHERE e.class_code = %(class_code)s AND (e.system_type IS NULL OR e.system_type != 'place location') GROUP BY e.id, es.id ORDER BY e.name;""" g.cursor.execute(sql, {'class_code': 'E55', 'property_code': 'P127'}) debug_model['div sql'] += 1 types = g.cursor.fetchall() g.cursor.execute(sql, {'class_code': 'E53', 'property_code': 'P89'}) debug_model['div sql'] += 1 places = g.cursor.fetchall() nodes = OrderedDict() for row in types + places: node = Entity(row) nodes[node.id] = node node.count = row.count + row.count_property node.count_subs = 0 node.subs = [] node.root = [row.super_id] if row.super_id else [] NodeMapper.populate_subs(nodes) return nodes
def file_add(id_: int, view: str) -> Union[str, Response]: entity = Entity.get_by_id(id_) if request.method == 'POST': if request.form['checkbox_values']: entity.link_string('P67', request.form['checkbox_values']) return redirect(f"{url_for('entity_view', id_=entity.id)}#tab-{view}") return render_template( 'form.html', form=build_table_form(view, entity.get_linked_entities('P67')), title=entity.name, crumbs=[ [_(entity.class_.view), url_for('index', view=entity.class_.view)], entity, f"{_('link')} {_(view)}"])
def insert_system(form: FlaskForm) -> Entity: entity = Entity.insert('reference_system', form.name.data, form.description.data) Db.insert_system({ 'entity_id': entity.id, 'name': entity.name, 'website_url': form.website_url.data if form.website_url.data else None, 'resolver_url': form.resolver_url.data if form.resolver_url.data else None }) return ReferenceSystem.get_all()[entity.id]
def insert_system(data: dict[str, str]) -> Entity: entity = Entity.insert('reference_system', data['name'], data['description']) Db.insert_system({ 'entity_id': entity.id, 'name': entity.name, 'website_url': data['website_url'] if data['website_url'] else None, 'resolver_url': data['resolver_url'] if data['resolver_url'] else None }) return ReferenceSystem.get_all()[entity.id]
def display_file_api(filename: str) -> Any: # pragma: no cover parser = image_parser.parse_args() from pathlib import Path as Pathlib_path entity = Entity.get_by_id(int(Pathlib_path(filename).stem), nodes=True) license_ = None for node in entity.nodes: if node.root and node.root[-1] == Node.get_hierarchy('License').id: license_ = node.name if not license_: raise AccessDeniedError if parser['download']: return send_file(str(app.config['UPLOAD_DIR']) + '/' + filename, as_attachment=True) return send_from_directory(app.config['UPLOAD_DIR'], filename)
def translation_update(id_: int) -> Union[str, Response]: translation = Entity.get_by_id(id_, nodes=True) form = build_form('source_translation', translation) if form.validate_on_submit(): save(form, translation) flash(_('info update'), 'info') return redirect(url_for('entity_view', id_=translation.id)) return render_template( 'display_form.html', form=form, title=translation.name, crumbs=[[_('source'), url_for('index', view='source')], translation.get_linked_entity('P73', True), translation, _('edit')])
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 translation_insert(source_id: int) -> Union[str, Response]: source = Entity.get_by_id(source_id) form = build_form('source_translation') if form.validate_on_submit(): translation = save(form, source=source) flash(_('entity created'), 'info') if hasattr(form, 'continue_') and form.continue_.data == 'yes': return redirect(url_for('translation_insert', source_id=source.id)) return redirect(url_for('entity_view', id_=translation.id)) return render_template( 'display_form.html', form=form, crumbs=[[_('source'), url_for('index', view='source')], source, f"+ {uc_first(_('text'))}"])
def note_insert(entity_id: int) -> Union[str, Response]: entity = Entity.get_by_id(entity_id) form = build_form('note') if form.validate_on_submit(): User.insert_note(entity_id, form.description.data, form.public.data) flash(_('note added'), 'info') return redirect(f"{url_for('view', id_=entity.id)}#tab-note") return render_template('display_form.html', form=form, entity=entity, crumbs=[[ _(entity.class_.view), url_for('index', view=entity.class_.view) ], entity, f"+ {uc_first(_('note'))}"])
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 member_insert(origin_id: int, code: str = 'member') -> Union[str, Response]: origin = Entity.get_by_id(origin_id) form = build_form('actor_function', code=code) form.member_origin_id.data = origin.id if form.validate_on_submit(): Transaction.begin() try: member_field = getattr(form, 'actor') \ if code == 'member' else getattr(form, 'group') for actor in Entity.get_by_ids(ast.literal_eval( member_field.data)): if code == 'membership': link_ = Link.get_by_id( actor.link('P107', origin, form.description.data)[0]) else: link_ = Link.get_by_id( origin.link('P107', actor, form.description.data)[0]) link_.set_dates(process_form_dates(form)) link_.type = get_link_type(form) link_.update() Transaction.commit() flash(_('entity created'), 'info') except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') if hasattr(form, 'continue_') and form.continue_.data == 'yes': return redirect( url_for('member_insert', origin_id=origin_id, code=code)) return redirect(f"{url_for('view', id_=origin.id)}" f"#tab-member{'' if code == 'member' else '-of'}") return render_template( 'display_form.html', form=form, crumbs=[[_('actor'), url_for('index', view='actor')], origin, _('member')])
def admin_check_link_duplicates( delete: Optional[str] = None) -> Union[str, Response]: if delete: delete_count = str(Link.delete_link_duplicates()) logger.log('info', 'admin', 'Deleted duplicate links: ' + delete_count) flash(_('deleted links') + ': ' + delete_count, 'info') return redirect(url_for('admin_check_link_duplicates')) table = Table([ 'domain', 'range', 'property_code', 'description', 'type_id', 'begin_from', 'begin_to', 'begin_comment', 'end_from', 'end_to', 'end_comment', 'count' ]) for row in Link.check_link_duplicates(): table.rows.append([ link(Entity.get_by_id(row['domain_id'])), link(Entity.get_by_id(row['range_id'])), link(g.properties[row['property_code']]), row['description'], link(g.nodes[row['type_id']]) if row['type_id'] else '', format_date(row['begin_from']), format_date(row['begin_to']), row['begin_comment'], format_date(row['end_from']), format_date(row['end_to']), row['end_comment'], row['count'] ]) duplicates = False if table.rows: duplicates = True else: # If no exact duplicates where found check if single types are used multiple times table = Table( ['entity', 'class', 'base type', 'incorrect multiple types'], rows=Link.check_single_type_duplicates()) return render_template( 'admin/check_link_duplicates.html', table=table, duplicates=duplicates, title=_('admin'), crumbs=[[_('admin'), url_for('admin_index') + '#tab-data'], _('check link duplicates')])
def relation_update(id_: int, origin_id: int) -> Union[str, Response]: link_ = Link.get_by_id(id_) domain = Entity.get_by_id(link_.domain.id) range_ = Entity.get_by_id(link_.range.id) origin = range_ if origin_id == range_.id else domain related = range_ if origin_id == domain.id else domain form = build_form('actor_actor_relation', link_) if form.validate_on_submit(): Transaction.begin() try: link_.delete() if form.inverse.data: link_ = Link.get_by_id( related.link('OA7', origin, form.description.data)[0]) else: link_ = Link.get_by_id( origin.link('OA7', related, form.description.data)[0]) link_.set_dates(form) link_.type = get_link_type(form) link_.update() Transaction.commit() flash(_('info update'), 'info') except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') return redirect( url_for('entity_view', id_=origin.id) + '#tab-relation') if origin.id == range_.id: form.inverse.data = True return render_template( 'display_form.html', form=form, title=_('relation'), crumbs=[[_('actor'), url_for('index', view='actor')], origin, related, _('edit')])
def test_duplicates(self) -> None: with app.app_context(): with app.test_request_context(): app.preprocess_request() # type: ignore event = Entity.insert('acquisition', 'Event Horizon') source = Entity.insert('source', 'Tha source') source.link('P67', event) source.link('P67', event) source_type = Type.get_hierarchy('Source') source.link('P2', g.types[source_type.subs[0]]) source.link('P2', g.types[source_type.subs[1]]) rv = self.app.get(url_for('admin_check_link_duplicates')) assert b'Event Horizon' in rv.data rv = self.app.get( url_for('admin_check_link_duplicates', delete='delete'), follow_redirects=True) assert b'Remove' in rv.data rv = self.app.get( url_for( 'admin_delete_single_type_duplicate', entity_id=source.id, type_id=source_type.subs[0]), follow_redirects=True) assert b'Congratulations, everything looks fine!' in rv.data
def get_by_object(object_: Entity) -> Dict[int, Overlay]: ids = [object_.id] # Get overlays of parents if object_.system_type == 'find': stratigraphic_unit = object_.get_linked_entity_safe('P46', True) ids.append(stratigraphic_unit.id) feature = stratigraphic_unit.get_linked_entity_safe('P46', True) ids.append(feature.id) ids.append(feature.get_linked_entity_safe('P46', True).id) elif object_.system_type == 'stratigraphic unit': feature = object_.get_linked_entity_safe('P46', True) ids.append(feature.id) ids.append(feature.get_linked_entity_safe('P46', True).id) elif object_.system_type == 'feature': ids.append(object_.get_linked_entity_safe('P46', True).id) sql = """ SELECT o.id, o.place_id, o.image_id, o.bounding_box, i.name FROM web.map_overlay o JOIN model.entity i ON o.image_id = i.id WHERE o.place_id IN %(place_ids)s;""" g.execute(sql, {'place_ids': tuple(ids)}) return {row.image_id: Overlay(row) for row in g.cursor.fetchall()}
def delete_entity(id_: int) -> Optional[str]: url = None entity = Entity.get_by_id(id_) if not is_authorized(entity.class_.write_access): abort(403) # pragma: no cover if isinstance(entity, ReferenceSystem): if entity.system: abort(403) if entity.forms: flash(_('Deletion not possible if forms are attached'), 'error') return url_for('entity_view', id_=id_) if entity.class_.view in ['artifact', 'place']: if entity.get_linked_entities('P46'): flash(_('Deletion not possible if subunits exists'), 'error') return url_for('entity_view', id_=id_) parent = None if entity.class_.name == 'place' else entity.get_linked_entity( 'P46', True) entity.delete() logger.log_user(id_, 'delete') flash(_('entity deleted'), 'info') if parent: tab = '#tab-' + entity.class_.name.replace('_', '-') url = url_for('entity_view', id_=parent.id) + tab else: Entity.delete_(id_) logger.log_user(id_, 'delete') flash(_('entity deleted'), 'info') if entity.class_.name == 'file': try: path = get_file_path(id_) if path: # Only delete file on disk if it exists to prevent a missing file error path.unlink() except Exception as e: # pragma: no cover logger.log('error', 'file', 'file deletion failed', e) flash(_('error file delete'), 'error') return url
def populate_reference_systems(form: FlaskForm, item: Entity) -> None: system_links = { # Can't use isinstance for class_ check here link_.domain.id: link_ for link_ in item.get_links('P67', True) if link_.domain.class_.name == 'reference_system' } for field in form: if field.id.startswith('reference_system_id_'): system_id = int(field.id.replace('reference_system_id_', '')) if system_id in system_links: field.data = system_links[system_id].description precision_field = getattr( form, f'reference_system_precision_{system_id}') precision_field.data = str(system_links[system_id].type.id)
def add_tabs_for_file(entity: Entity) -> dict[str, Tab]: tabs = {} for name in [ 'source', 'event', 'actor', 'place', 'feature', 'stratigraphic_unit', 'artifact', 'human_remains', 'reference', 'type' ]: tabs[name] = Tab(name, entity=entity) entity.image_id = entity.id if get_file_path(entity.id) else None for link_ in entity.get_links('P67'): range_ = link_.range data = get_base_table_data(range_) data.append(remove_link(range_.name, link_, entity, range_.class_.name)) tabs[range_.class_.view].table.rows.append(data) for link_ in entity.get_links('P67', True): data = get_base_table_data(link_.domain) data.append(link_.description) data.append( edit_link(url_for('link_update', id_=link_.id, origin_id=entity.id))) data.append(remove_link(link_.domain.name, link_, entity, 'reference')) tabs['reference'].table.rows.append(data) return tabs
def overlay_update(id_: int) -> Union[str, Response]: overlay = Overlay.get_by_id(id_) form = OverlayForm() if form.validate_on_submit(): Overlay.update(form=form, image_id=overlay.image_id, place_id=overlay.place_id) flash(_('info update'), 'info') return redirect( url_for('entity_view', id_=overlay.place_id) + '#tab-file') bounding = ast.literal_eval(overlay.bounding_box) form.top_left_easting.data = bounding[0][1] form.top_left_northing.data = bounding[0][0] form.bottom_right_easting.data = bounding[1][1] form.bottom_right_northing.data = bounding[1][0] entity = Entity.get_by_id(overlay.place_id) return render_template( 'overlay/update.html', form=form, overlay=overlay, entity=entity, crumbs=[[_('place'), url_for('index', view='place')], entity, Entity.get_by_id(overlay.image_id), _('update overlay')])
def get_invalid_cidoc_links() -> List[Dict[str, str]]: from openatlas.models.entity import Entity from openatlas.util.util import link invalid_linking = [] for row in Db.get_cidoc_links(): property_ = g.properties[row['property_code']] domain_is_valid = property_.find_object( 'domain_class_code', row['domain_code']) range_is_valid = property_.find_object( 'range_class_code', row['range_code']) if not domain_is_valid or not range_is_valid: invalid_linking.append(row) invalid_links = [] for item in invalid_linking: for row in Db.get_invalid_links(item): domain = Entity.get_by_id(row['domain_id']) range_ = Entity.get_by_id(row['range_id']) invalid_links.append({ 'domain': f"{link(domain)} ({domain.cidoc_class.code})", 'property': link(g.properties[row['property_code']]), 'range': f"{link(range_)} ({range_.cidoc_class.code})"}) return invalid_links
def update_links(form: FlaskForm, entity: Entity) -> None: for field in form: if field.id.startswith('reference_system_id_'): # Recreate link system = Entity.get_by_id( int(field.id.replace('reference_system_id_', ''))) precision_field = getattr( form, field.id.replace('id_', 'precision_')) Db.remove_link(system.id, entity.id) if field.data: system.link( 'P67', entity, field.data, type_id=precision_field.data)
def get_place_info_for_update(entity: Entity) -> dict[str, Any]: if entity.class_.view not in ['artifact', 'place']: return { 'structure': None, 'gis_data': None, 'overlays': None, 'location': None } structure = get_structure(entity) return { 'structure': structure, 'gis_data': Gis.get_all([entity], structure), 'overlays': Overlay.get_by_object(entity), 'location': entity.get_linked_entity_safe('P53', types=True) }
def get(filename: str) -> Response: # pragma: no cover entity = Entity.get_by_id(int(Pathlib_path(filename).stem), types=True) license_ = get_license(entity) if not license_: raise AccessDeniedError parser = image.parse_args() if parser['download']: return send_file( f"{app.config['UPLOAD_DIR']}/{filename}", as_attachment=True) if parser['image_size'] and check_processed_image(filename): size = app.config['IMAGE_SIZE'][parser['image_size']] return send_from_directory( f"{app.config['RESIZED_IMAGES']}/{size}", filename) return send_from_directory(app.config['UPLOAD_DIR'], filename)
def entity_add_reference(id_: int) -> Union[str, Response]: entity = Entity.get_by_id(id_) form = AddReferenceForm() if form.validate_on_submit(): entity.link_string('P67', form.reference.data, description=form.page.data, inverse=True) return redirect(f"{url_for('entity_view', id_=id_)}#tab-reference") form.page.label.text = uc_first(_('page / link text')) return render_template('display_form.html', entity=entity, form=form, crumbs=[[ _(entity.class_.view), url_for('index', view=entity.class_.view) ], entity, f"{_('link')} {_('reference')}"])
def entity_add_source(id_: int) -> Union[str, Response]: entity = Entity.get_by_id(id_) if request.method == 'POST': if request.form['checkbox_values']: entity.link_string('P67', request.form['checkbox_values'], inverse=True) return redirect(f"{url_for('entity_view', id_=id_)}#tab-source") form = build_table_form('source', entity.get_linked_entities('P67', inverse=True)) return render_template('form.html', form=form, title=entity.name, crumbs=[[ _(entity.class_.view), url_for('index', view=entity.class_.view) ], entity, f"{_('link')} {_('source')}"])
def get_subunits(id_: int) -> List[Dict[str, Any]]: # Get first level of subunits try: entity = Entity.get_by_id(id_, nodes=True, aliases=True) except Exception: # pragma: no cover raise EntityDoesNotExistError structure = get_structure(entity) data = [] if not structure or not structure['subunits']: raise InvalidSubunitError # pragma: no cover for n in structure['subunits']: data.append({ 'id': n.id, 'label': n.name, 'url': url_for('entity', id_=n.id, _external=True) }) return data
def save(form: FlaskForm, node: Optional[Node] = None, param: Optional[str] = None) -> Optional[Node]: Transaction.begin() try: if node: Node.update_hierarchy(node, form) else: node = Entity.insert('type', sanitize(form.name.data)) Node.insert_hierarchy(node, form, value_type=(param == 'value')) node.update(form) Transaction.commit() except Exception as e: # pragma: no cover Transaction.rollback() logger.log('error', 'database', 'transaction failed', e) flash(_('error transaction'), 'error') abort(418) return node
def get(filename: str) -> Response: from pathlib import Path as Pathlib_path entity = Entity.get_by_id(int(Pathlib_path(filename).stem), nodes=True) license_ = None for node in entity.nodes: if node.root and node.root[-1] == Node.get_hierarchy('License').id: license_ = node.name if not license_: raise AccessDeniedError parser = image.parse_args() if parser['download']: return send_file(f"{app.config['UPLOAD_DIR']}/{filename}", as_attachment=True) if parser['image_size']: size = app.config['IMAGE_SIZE'][parser['image_size']] return send_from_directory( f"{app.config['RESIZED_IMAGES']}/{size}", filename) return send_from_directory(app.config['UPLOAD_DIR'], filename)
def get_untyped(hierarchy_id: int) -> list[Entity]: hierarchy = g.types[hierarchy_id] classes = hierarchy.classes if hierarchy.name in ('Administrative unit', 'Historical place'): classes = 'object_location' # pragma: no cover untyped = [] for entity in Entity.get_by_class(classes, types=True): linked = False for type_ in entity.types: if type_.root[0] == hierarchy_id: linked = True break if not linked: if classes == 'object_location': # pragma: no cover if entity.get_linked_entity('P53', True): untyped.append(entity) else: untyped.append(entity) return untyped
def admin_check_similar() -> str: form = SimilarForm() form.classes.choices = [(x.name, x.label) for name, x in g.classes.items() if x.label] table = None if form.validate_on_submit(): table = Table(['name', _('count')]) for sample in Entity.get_similar_named(form).values(): html = link(sample['entity']) for entity in sample['entities']: # Table linebreaks workaround html += f'<br><br><br><br><br>{link(entity)}' table.rows.append([html, len(sample['entities']) + 1]) return render_template( 'admin/check_similar.html', table=table, form=form, title=_('admin'), crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-data"], _('check similar names')])
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