def check_single_type_duplicates() -> list: # Find entities with multiple types attached which should be single from openatlas.models.node import NodeMapper from openatlas.models.entity import EntityMapper data = [] for id_, node in g.nodes.items(): if not node.root and not node.multiple and not node.value_type: node_ids = NodeMapper.get_all_sub_ids(node) if node_ids: sql = """ SELECT domain_id FROM model.link WHERE property_code = 'P2' AND range_id IN %(node_ids)s GROUP BY domain_id HAVING COUNT(*) > 1;""" g.execute(sql, {'node_ids': tuple(node_ids)}) for row in g.cursor.fetchall(): offending_nodes = [] entity = EntityMapper.get_by_id(row.domain_id, nodes=True) for entity_node in entity.nodes: if g.nodes[entity_node.root[-1]].id == node.id: url = url_for( 'admin_delete_single_type_duplicate', entity_id=entity.id, node_id=entity_node.id) offending_nodes.append('<a href="' + url + '">' + uc_first(_('remove')) + '</a> ' + entity_node.name) data.append([ link(entity), entity.class_.name, link(g.nodes[id_]), '<br />'.join(offending_nodes) ]) return data
def add_tabs_for_type(entity: Type) -> dict[str, Tab]: tabs = { 'subs': Tab('subs', entity=entity), 'entities': Tab('entities', entity=entity)} for sub_id in entity.subs: sub = g.types[sub_id] tabs['subs'].table.rows.append([ link(sub), sub.count, sub.description]) if entity.category == 'value': tabs['entities'].table.header = \ [_('name'), _('value'), _('class'), _('info')] for item in entity.get_linked_entities( ['P2', 'P89'], inverse=True, types=True): if item.class_.name in ['location', 'reference_system']: continue # pragma: no cover if item.class_.name == 'object_location': item = item.get_linked_entity_safe('P53', inverse=True) data = [link(item)] if entity.category == 'value': data.append(format_number(item.types[entity])) data.append(item.class_.label) data.append(item.description) tabs['entities'].table.rows.append(data) if not tabs['entities'].table.rows: # If no entities available get links with this type_id tabs['entities'].table.header = [_('domain'), _('range')] for row in Link.get_links_by_type(entity): tabs['entities'].table.rows.append([ link(Entity.get_by_id(row['domain_id'])), link(Entity.get_by_id(row['range_id']))]) return tabs
def index(): tables = { 'counts': {'id': 'overview', 'header': [], 'data': [], 'show_pager': False}, 'bookmarks': {'id': 'bookmarks', 'data': [], 'show_pager': False, 'header': ['name', 'class', 'first', 'last']}, 'latest': {'id': 'latest', 'data': [], 'show_pager': False, 'header': ['name', 'class', 'first', 'last', 'date', 'user']}} if current_user.is_authenticated and hasattr(current_user, 'bookmarks'): for entity_id in current_user.bookmarks: entity = EntityMapper.get_by_id(entity_id) tables['bookmarks']['data'].append([ link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, bookmark_toggle(entity.id, True)]) for name, count in EntityMapper.get_overview_counts().items(): count = format_number(count) if count else '' tables['counts']['data'].append([ '<a href="' + url_for(name + '_index') + '">' + uc_first(_(name)) + '</a>', count]) for entity in EntityMapper.get_latest(8): tables['latest']['data'].append([ link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, format_date(entity.created), link(logger.get_log_for_advanced_view(entity.id)['creator'])]) intro = ContentMapper.get_translation('intro') return render_template('index/index.html', intro=intro, tables=tables)
def user_activity(user_id: int = 0) -> str: form = ActivityForm() form.user.choices = [(0, _('all'))] + User.get_users_for_form() if form.validate_on_submit(): activity = User.get_activities(int(form.limit.data), int(form.user.data), form.action.data) elif user_id: form.user.data = user_id activity = User.get_activities(100, user_id, 'all') else: activity = User.get_activities(100, 0, 'all') table = Table(['date', 'user', 'action', 'entity'], order=[[0, 'desc']]) for row in activity: try: entity = link(Entity.get_by_id(row['entity_id'])) except AttributeError: # pragma: no cover - entity already deleted entity = f"id {row['entity_id']}" user = User.get_by_id(row['user_id']) table.rows.append([ format_date(row['created']), link(user) if user else f"id {row['user_id']}", _(row['action']), entity ]) return render_template('user/activity.html', table=table, form=form, title=_('user'), crumbs=[[_('admin'), url_for('admin_index')], _('activity')])
def index() -> str: tables = {'overview': Table(paging=False, defs='[{className: "dt-body-right", targets: 1}]'), 'bookmarks': Table(['name', 'class', 'first', 'last'], defs='[{className: "dt-body-right", targets: [2,3]}]'), 'notes': Table(['name', 'class', 'first', 'last', _('note')], defs='[{className: "dt-body-right", targets: [2,3]}]'), 'latest': Table(['name', 'class', 'first', 'last', 'date', 'user'], order='[[4, "desc"]]', defs='[{className: "dt-body-right", targets: [2,3]}]')} if current_user.is_authenticated and hasattr(current_user, 'bookmarks'): for entity_id in current_user.bookmarks: entity = EntityMapper.get_by_id(entity_id) tables['bookmarks'].rows.append([link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, bookmark_toggle(entity.id, True)]) for entity_id, text in UserMapper.get_notes().items(): entity = EntityMapper.get_by_id(entity_id) tables['notes'].rows.append([link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, truncate_string(text)]) for name, count in EntityMapper.get_overview_counts().items(): if count: count = format_number(count) if count else '' url = url_for(name + '_index') if name != 'find' else url_for('place_index') tables['overview'].rows.append([ '<a href="' + url + '">' + uc_first(_(name)) + '</a>', count]) for entity in EntityMapper.get_latest(8): tables['latest'].rows.append([ link(entity), g.classes[entity.class_.code].name, entity.first, entity.last, format_date(entity.created), link(logger.get_log_for_advanced_view(entity.id)['creator'])]) intro = ContentMapper.get_translation('intro') return render_template('index/index.html', intro=intro, tables=tables)
def admin_check_link_duplicates(delete: Optional[str] = None) -> str: if delete: delete_count = str(LinkMapper.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 result in LinkMapper.check_link_duplicates(): table.rows.append([link(EntityMapper.get_by_id(result.domain_id)), link(EntityMapper.get_by_id(result.range_id)), link(g.properties[result.property_code]), truncate_string(result.description), link(g.nodes[result.type_id]) if result.type_id else '', format_date(result.begin_from), format_date(result.begin_to), truncate_string(result.begin_comment), format_date(result.end_from), format_date(result.end_to), truncate_string(result.end_comment), result.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=LinkMapper.check_single_type_duplicates()) return render_template('admin/check_link_duplicates.html', table=table, duplicates=duplicates)
def cidoc_class_index() -> str: table = Table(['code', 'name', 'count'], defs=[{ 'className': 'dt-body-right', 'targets': 2 }, { 'orderDataType': 'cidoc-model', 'targets': [0] }, { 'sType': 'numeric', 'targets': [0] }]) for class_ in g.cidoc_classes.values(): count = '' if class_.count: count = format_number(class_.count) if class_.code not in ['E53', 'E41', 'E82']: count = link(format_number(class_.count), url_for('class_entities', code=class_.code)) table.rows.append([link(class_), class_.name, count]) return render_template('table.html', table=table, title=_('model'), crumbs=[[_('model'), url_for('model_index')], _('classes')])
def admin_logo(id_: Optional[int] = None) -> Union[str, Response]: if g.settings['logo_file_id']: abort(418) # pragma: no cover - Logo already set if id_: Settings.set_logo(id_) return redirect(f"{url_for('admin_index')}#tab-file") table = Table([''] + g.table_headers['file'] + ['date']) for entity in Entity.get_display_files(): date = 'N/A' if entity.id in g.file_stats: date = format_date( datetime.datetime.utcfromtimestamp( g.file_stats[entity.id]['date'])) table.rows.append([ link(_('set'), url_for('admin_logo', id_=entity.id)), entity.name, link(entity.standard_type), g.file_stats[entity.id]['size'] if entity.id in g.file_stats else 'N/A', g.file_stats[entity.id]['ext'] if entity.id in g.file_stats else 'N/A', entity.description, date ]) return render_template( 'admin/logo.html', table=table, title=_('logo'), crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-files"], _('logo')])
def property_view(code): property_ = g.properties[code] domain = g.classes[property_.domain_class_code] range_ = g.classes[property_.range_class_code] tables = { 'info': [('code', property_.code), ('name', property_.name), ('inverse', property_.name_inverse), ('domain', link(domain) + ' ' + domain.name), ('range', link(range_) + ' ' + range_.name)] } for table in ['super', 'sub']: tables[table] = { 'id': table, 'header': ['code', 'name'], 'data': [], 'show_pager': False, 'sort': 'sortList: [[0, 0]],headers: {0: { sorter: "property_code" }}' } for code in getattr(property_, table): tables[table]['data'].append( [link(g.properties[code]), g.properties[code].name]) return render_template('model/property_view.html', property=property_, tables=tables)
def node_view(id_): from openatlas.models.linkProperty import LinkPropertyMapper node = g.nodes[id_] root = g.nodes[node.root[-1]] if node.root else None super_ = g.nodes[node.root[0]] if node.root else None header = [_('name'), _('class'), _('info')] if root and root.value_type: # pragma: no cover header = [_('name'), _('value'), _('class'), _('info')] tables = {'entities': {'id': 'entities', 'header': header, 'data': []}, 'info': get_entity_data(node)} for entity in node.get_linked_entities(['P2', 'P89'], True): # If it is a place location get the corresponding object entity = entity if node.class_.code == 'E55' else entity.get_linked_entity('P53', True) if entity: # If not entity it is a place node, so do not add data = [link(entity)] if root and root.value_type: # pragma: no cover data.append(format_number(entity.nodes[node])) data.append(g.classes[entity.class_.code].name) data.append(truncate_string(entity.description)) tables['entities']['data'].append(data) tables['link_entities'] = {'id': 'link_items', 'header': [_('domain'), _('range')], 'data': []} for row in LinkPropertyMapper.get_entities_by_node(node): tables['link_entities']['data'].append([link(EntityMapper.get_by_id(row.domain_id)), link(EntityMapper.get_by_id(row.range_id))]) tables['subs'] = {'id': 'subs', 'header': [_('name'), _('count'), _('info')], 'data': []} for sub_id in node.subs: sub = g.nodes[sub_id] tables['subs']['data'].append([link(sub), sub.count, truncate_string(sub.description)]) return render_template('types/view.html', node=node, super_=super_, tables=tables, root=root)
def property_index() -> str: classes = g.cidoc_classes properties = g.properties table = Table([ 'code', 'name', 'inverse', 'domain', 'domain name', 'range', 'range name', 'count' ], defs=[{ 'className': 'dt-body-right', 'targets': 7 }, { 'orderDataType': 'cidoc-model', 'targets': [0, 3, 5] }, { 'sType': 'numeric', 'targets': [0] }]) for property_ in properties.values(): table.rows.append([ link(property_), property_.name, property_.name_inverse, link(classes[property_.domain_class_code]), classes[property_.domain_class_code].name, link(classes[property_.range_class_code]), classes[property_.range_class_code].name, format_number(property_.count) if property_.count else '' ]) return render_template('table.html', table=table, title=_('model'), crumbs=[[_('model'), url_for('model_index')], _('properties')])
def openatlas_class_index() -> str: table = Table([ 'name', f"CIDOC {_('class')}", _('standard type'), _('write access'), 'alias', _('reference system'), 'add type', _('color'), _('icon'), 'count' ]) class_count = OpenatlasClass.get_class_count() for class_ in g.classes.values(): table.rows.append([ class_.label, link(class_.cidoc_class), link(g.types[class_.standard_type_id]) if class_.standard_type_id else '', class_.write_access, _('allowed') if class_.alias_allowed else '', _('allowed') if class_.reference_system_allowed else '', _('allowed') if class_.new_types_allowed else '', class_.network_color, class_.icon, format_number(class_count[class_.name]) if class_count[class_.name] else '' ]) return render_template('table.html', table=table, title=_('model'), crumbs=[[_('model'), url_for('model_index')], f"OpenAtlas {_('classes')}"])
def check_single_type_duplicates() -> list: # Find entities with multiple types attached which should be single from openatlas.models.node import NodeMapper from openatlas.models.entity import EntityMapper data = [] for id_, node in g.nodes.items(): if not node.root and not node.multiple and not node.value_type: node_ids = NodeMapper.get_all_sub_ids(node) if node_ids: sql = """ SELECT domain_id FROM model.link WHERE property_code = 'P2' AND range_id IN %(node_ids)s GROUP BY domain_id HAVING COUNT(*) > 1;""" g.cursor.execute(sql, {'node_ids': tuple(node_ids)}) debug_model['link sql'] += 1 for row in g.cursor.fetchall(): offending_nodes = [] entity = EntityMapper.get_by_id(row.domain_id, nodes=True) for entity_node in entity.nodes: if g.nodes[entity_node.root[-1]].id == node.id: url = url_for('admin_delete_single_type_duplicate', entity_id=entity.id, node_id=entity_node.id) offending_nodes.append( '<a href="' + url + '">' + uc_first(_('remove')) + '</a> ' + entity_node.name) data.append([link(entity), entity.class_.name, link(g.nodes[id_]), '<br />'.join(offending_nodes)]) return data
def check_single_type_duplicates() -> List[List[str]]: from openatlas.models.node import Node from openatlas.models.entity import Entity from openatlas.util.util import uc_first from openatlas.util.util import link data = [] for node in g.nodes.values(): if node.root or node.multiple or node.value_type: continue # pragma: no cover node_ids = Node.get_all_sub_ids(node) if not node_ids: continue # pragma: no cover for id_ in Db.check_single_type_duplicates(node_ids): offending_nodes = [] entity = Entity.get_by_id(id_, nodes=True) for entity_node in entity.nodes: if g.nodes[entity_node.root[-1]].id != node.id: continue # pragma: no cover url = url_for( 'admin_delete_single_type_duplicate', entity_id=entity.id, node_id=entity_node.id) offending_nodes.append( f'<a href="{url}">{uc_first(_("remove"))}</a> ' f'{entity_node.name}') data.append([ link(entity), entity.class_.name, link(g.nodes[node.id]), '<br><br><br><br><br>'.join(offending_nodes)]) return data
def check_links(): """ Check all existing links for CIDOC CRM validity and return the invalid ones.""" from openatlas.util.util import link from openatlas.models.entity import EntityMapper sql = """ SELECT DISTINCT l.property_code AS property, d.class_code AS domain, r.class_code AS range FROM model.link l JOIN model.entity d ON l.domain_id = d.id JOIN model.entity r ON l.range_id = r.id;""" g.cursor.execute(sql) invalid_links = [] for row in g.cursor.fetchall(): property_ = g.properties[row.property] domain_is_valid = property_.find_object('domain_class_code', row.domain) range_is_valid = property_.find_object('range_class_code', row.range) invalid_linking = [] if not domain_is_valid or not range_is_valid: invalid_linking.append({ 'property': row.property, 'domain': row.domain, 'range': row.range }) for item in invalid_linking: sql = """ SELECT l.id, l.property_code, l.domain_id, l.range_id, l.description, l.created, l.modified FROM model.link l JOIN model.entity d ON l.domain_id = d.id JOIN model.entity r ON l.range_id = r.id WHERE l.property_code = %(property)s AND d.class_code = %(domain)s AND r.class_code = %(range)s;""" g.cursor.execute( sql, { 'property': item['property'], 'domain': item['domain'], 'range': item['range'] }) for row2 in g.cursor.fetchall(): domain = EntityMapper.get_by_id(row2.domain_id) range_ = EntityMapper.get_by_id(row2.range_id) invalid_links.append({ 'domain': link(domain) + ' (' + domain.class_.code + ')', 'property': link(g.properties[row2.property_code]), 'range': link(range_) + ' (' + range_.class_.code + ')' }) return invalid_links
def class_entities(code: str) -> str: table = Table(['name'], rows=[[link(entity)] for entity in Entity.get_by_cidoc_class(code)]) return render_template( 'table.html', table=table, title=_('model'), crumbs=[[_('model'), url_for('model_index')], [_('classes'), url_for('cidoc_class_index')], link(g.cidoc_classes[code]), _('entities')])
def add_tabs_for_place(entity: Entity) -> dict[str, Tab]: tabs = {'source': Tab('source', entity=entity)} if entity.class_.name == 'place': tabs['event'] = Tab('event', entity=entity) tabs['reference'] = Tab('reference', entity=entity) if entity.class_.name == 'place': tabs['actor'] = Tab('actor', entity=entity) tabs['feature'] = Tab('feature', entity=entity) elif entity.class_.name == 'feature': tabs['stratigraphic_unit'] = Tab( 'stratigraphic_unit', entity=entity) elif entity.class_.name == 'stratigraphic_unit': tabs['artifact'] = Tab('artifact', entity=entity) tabs['human_remains'] = Tab('human_remains', entity=entity) entity.location = entity.get_linked_entity_safe('P53', types=True) events = [] # Collect events to display actors event_ids = [] # Keep track of event ids to prevent event doubles for event in entity.location.get_linked_entities( ['P7', 'P26', 'P27'], inverse=True): events.append(event) tabs['event'].table.rows.append(get_base_table_data(event)) event_ids.append(event.id) for event in entity.get_linked_entities('P24', inverse=True): if event.id not in event_ids: # Don't add again if already in table tabs['event'].table.rows.append(get_base_table_data(event)) events.append(event) if entity.class_.name == 'place': for link_ in entity.location.get_links( ['P74', 'OA8', 'OA9'], inverse=True): actor = Entity.get_by_id(link_.domain.id) tabs['actor'].table.rows.append([ link(actor), g.properties[link_.property.code].name, actor.class_.name, actor.first, actor.last, actor.description]) actor_ids = [] for event in events: for actor in event.get_linked_entities( ['P11', 'P14', 'P22', 'P23']): if actor.id in actor_ids: continue # pragma: no cover actor_ids.append(actor.id) tabs['actor'].table.rows.append([ link(actor), f"{_('participated at an event')}", event.class_.name, '', '', '']) return tabs
def admin_check_similar() -> str: form = SimilarForm() choices = ['source', 'event', 'actor', 'place', 'feature', 'stratigraphic unit', 'find', 'reference', 'file'] form.classes.choices = [(x, uc_first(_(x))) for x in choices] table = Table(['name', uc_first(_('count'))]) if form.validate_on_submit(): for sample_id, sample in EntityMapper.get_similar_named(form).items(): html = link(sample['entity']) for entity in sample['entities']: html += '<br/>' + link(entity) table.rows.append([html, len(sample['entities']) + 1]) table = table if table.rows else 'none found' return render_template('admin/check_similar.html', table=table, form=form)
def property_view(code: str) -> str: property_ = g.properties[code] domain = g.classes[property_.domain_class_code] range_ = g.classes[property_.range_class_code] tables = {'info': [('code', property_.code), ('name', property_.name), ('inverse', property_.name_inverse), ('domain', link(domain) + ' ' + domain.name), ('range', link(range_) + ' ' + range_.name)]} for table in ['super', 'sub']: tables[table] = Table(['code', 'name'], paging=False) for code in getattr(property_, table): tables[table].rows.append([link(g.properties[code]), g.properties[code].name]) return render_template('model/property_view.html', property=property_, tables=tables)
def property_index() -> str: classes = g.classes properties = g.properties table = Table(['code', 'name', 'inverse', 'domain', 'domain name', 'range', 'range name'], defs='''[{"orderDataType": "cidoc-model", "targets":[0, 3, 5]}, {"sType": "numeric", "targets": [0, 3, 5]}]''') for property_id, property_ in properties.items(): table.rows.append([link(property_), property_.name, property_.name_inverse, link(classes[property_.domain_class_code]), classes[property_.domain_class_code].name, link(classes[property_.range_class_code]), classes[property_.range_class_code].name]) return render_template('model/property.html', table=table)
def show_untyped_entities(id_: int) -> str: hierarchy = g.types[id_] table = Table(['name', 'class', 'first', 'last', 'description']) for entity in Type.get_untyped(hierarchy.id): table.rows.append([ link(entity), entity.class_.label, entity.first, entity.last, entity.description ]) return render_template('table.html', entity=hierarchy, table=table, crumbs=[[_('types'), url_for('type_index')], link(hierarchy), _('untyped entities')])
def get_profile_image_table_link( file: Entity, entity: Entity, extension: str, profile_image_id: Optional[int] = None) -> str: if file.id == profile_image_id: return link(_('unset'), url_for('file_remove_profile_image', entity_id=entity.id)) if extension in app.config['DISPLAY_FILE_EXTENSIONS'] or ( session['settings']['image_processing'] and extension in app.config['ALLOWED_IMAGE_EXT']): return link( _('set'), url_for('set_profile_image', id_=file.id, origin_id=entity.id)) return '' # pragma: no cover
def admin_check_dates() -> str: tabs = { 'dates': Tab('invalid_dates', table=Table( ['name', 'class', 'type', 'created', 'updated', 'description'])), 'link_dates': Tab('invalid_link_dates', table=Table(['link', 'domain', 'range'])), 'involvement_dates': Tab('invalid_involvement_dates', table=Table( ['actor', 'event', 'class', 'involvement', 'description'])) } for entity in Entity.get_invalid_dates(): tabs['dates'].table.rows.append([ link(entity), entity.class_.label, link(entity.standard_type), format_date(entity.created), format_date(entity.modified), entity.description ]) for link_ in Link.get_invalid_link_dates(): name = '' if link_.property.code == 'OA7': # pragma: no cover name = 'relation' elif link_.property.code == 'P107': # pragma: no cover name = 'member' elif link_.property.code in ['P11', 'P14', 'P22', 'P23']: name = 'involvement' tabs['link_dates'].table.rows.append([ link( _(name), url_for('link_update', id_=link_.id, origin_id=link_.domain.id)), link(link_.domain), link(link_.range) ]) for link_ in Link.invalid_involvement_dates(): event = link_.domain actor = link_.range data = [ link(actor), link(event), event.class_.label, link_.type.name if link_.type else '', link_.description, link(_('edit'), url_for('link_update', id_=link_.id, origin_id=actor.id)) ] tabs['involvement_dates'].table.rows.append(data) for tab in tabs.values(): tab.buttons = [manual('admin/data_integrity_checks')] if not tab.table.rows: # pragma: no cover tab.content = _('Congratulations, everything looks fine!') return render_template( 'tabs.html', tabs=tabs, title=_('admin'), crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-data"], _('check dates')])
def class_view(code: str) -> str: class_ = g.cidoc_classes[code] tables = {} for table in ['super', 'sub']: tables[table] = Table(paging=False, defs=[{ 'orderDataType': 'cidoc-model', 'targets': [0] }, { 'sType': 'numeric', 'targets': [0] }]) for code_ in getattr(class_, table): tables[table].rows.append( [link(g.cidoc_classes[code_]), g.cidoc_classes[code_].name]) tables['domains'] = Table(paging=False, defs=[{ 'orderDataType': 'cidoc-model', 'targets': [0] }, { 'sType': 'numeric', 'targets': [0] }]) tables['ranges'] = Table(paging=False, defs=[{ 'orderDataType': 'cidoc-model', 'targets': [0] }, { 'sType': 'numeric', 'targets': [0] }]) for property_ in g.properties.values(): if class_.code == property_.domain_class_code: tables['domains'].rows.append([link(property_), property_.name]) elif class_.code == property_.range_class_code: tables['ranges'].rows.append([link(property_), property_.name]) return render_template('model/class_view.html', class_=class_, tables=tables, info={ 'code': class_.code, 'name': class_.name }, title=_('model'), crumbs=[[_('model'), url_for('model_index')], [_('classes'), url_for('class_index')], class_.code])
def add_tabs_for_event(entity: Entity) -> dict[str, Tab]: tabs = {} for name in ['subs', 'source', 'actor']: tabs[name] = Tab(name, entity=entity) for sub_event in entity.get_linked_entities( 'P9', inverse=True, types=True): tabs['subs'].table.rows.append(get_base_table_data(sub_event)) tabs['actor'].table.header.insert(5, _('activity')) for link_ in entity.get_links(['P11', 'P14', 'P22', 'P23']): first = link_.first if not link_.first and entity.first: first = f'<span class="inactive">{entity.first}</span>' last = link_.last if not link_.last and entity.last: last = f'<span class="inactive">{entity.last}</span>' tabs['actor'].table.rows.append([ link(link_.range), link_.range.class_.label, link_.type.name if link_.type else '', first, last, g.properties[link_.property.code].name_inverse, link_.description, edit_link( url_for('link_update', id_=link_.id, origin_id=entity.id)), remove_link(link_.range.name, link_, entity, 'actor')]) entity.linked_places = [ location.get_linked_entity_safe('P53', True) for location in entity.get_linked_entities(['P7', 'P26', 'P27'])] return tabs
def file_index() -> str: table = Table(['date'] + Table.HEADERS['file']) file_stats = get_file_stats() for entity in EntityMapper.get_by_system_type('file', nodes=True): date = 'N/A' if entity.id in file_stats: date = format_date( datetime.datetime.utcfromtimestamp( file_stats[entity.id]['date'])) table.rows.append([ date, link(entity), entity.print_base_type(), convert_size(file_stats[entity.id]['size']) if entity.id in file_stats else 'N/A', file_stats[entity.id]['ext'] if entity.id in file_stats else 'N/A', truncate_string(entity.description) ]) if os.name != "posix": # pragma: no cover # For other operating systems e.g. Windows, we would need adaptions here return render_template('file/index.html', table=table, disk_space_values={}) statvfs = os.statvfs(app.config['UPLOAD_FOLDER_PATH']) disk_space = statvfs.f_frsize * statvfs.f_blocks free_space = statvfs.f_frsize * statvfs.f_bavail # Available space without reserved blocks disk_space_values = { 'total': convert_size(statvfs.f_frsize * statvfs.f_blocks), 'free': convert_size(statvfs.f_frsize * statvfs.f_bavail), 'percent': 100 - math.ceil(free_space / (disk_space / 100)) } return render_template('file/index.html', table=table, disk_space_values=disk_space_values)
def admin_log() -> str: form = LogForm() form.user.choices = [(0, _('all'))] + User.get_users_for_form() table = Table(['date', 'priority', 'type', 'message', 'user', 'info'], order=[[0, 'desc']]) logs = logger.get_system_logs(form.limit.data, form.priority.data, form.user.data) for row in logs: user = None if row['user_id']: try: user = link(User.get_by_id(row['user_id'])) except AttributeError: # pragma: no cover - user already deleted user = f"id {row['user_id']}" table.rows.append([ format_datetime(row['created']), f"{row['priority']} {app.config['LOG_LEVELS'][row['priority']]}", row['type'], row['message'], user, row['info'] ]) return render_template( 'admin/log.html', table=table, form=form, title=_('admin'), crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-general"], _('system log')])
def add_tabs_for_reference_system(entity: ReferenceSystem) -> dict[str, Tab]: tabs = {} for name in entity.classes: tabs[name] = Tab( name, entity=entity, table=Table([_('entity'), 'id', _('precision')])) for link_ in entity.get_links('P67'): name = link_.description if entity.resolver_url: name = \ f'<a href="{entity.resolver_url}{name}"' \ f' target="_blank" rel="noopener noreferrer">{name}</a>' tabs[link_.range.class_.name].table.rows.append([ link(link_.range), name, link_.type.name]) for name in entity.classes: tabs[name].buttons = [] if not tabs[name].table.rows and is_authorized('manager'): tabs[name].buttons = [button( _('remove'), url_for( 'reference_system_remove_class', system_id=entity.id, class_name=name))] return tabs
def update(id_: int) -> Union[str, Response]: entity = Entity.get_by_id(id_, types=True, aliases=True) check_update_access(entity) if entity.check_for_too_many_links_for_single_type(): abort(422) place_info = get_place_info_for_update(entity) form = build_form(entity.class_.name, entity, location=place_info['location']) if form.validate_on_submit(): if isinstance(entity, Type) and not check_type(entity, form): return redirect(url_for('view', id_=entity.id)) if was_modified(form, entity): # pragma: no cover del form.save flash(_('error modified'), 'error') return render_template( 'entity/update.html', form=form, entity=entity, modifier=link(logger.get_log_info(entity.id)['modifier'])) return redirect(save(form, entity)) populate_update_form(form, entity) if entity.class_.view in ['artifact', 'place']: entity.set_image_for_places() return render_template( 'entity/update.html', form=form, entity=entity, gis_data=place_info['gis_data'], overlays=place_info['overlays'], geonames_module=check_geonames_module(entity.class_.name), title=entity.name, crumbs=add_crumbs(entity.class_.name, entity, place_info['structure']))
def class_index() -> str: table = Table(['code', 'name'], defs='''[{"orderDataType": "cidoc-model", "targets":[0]}, {"sType": "numeric", "targets": [0]}]''') for class_id, class_ in g.classes.items(): table.rows.append([link(class_), class_.name]) return render_template('model/class.html', table=table)
def class_view(code: str) -> str: class_ = g.classes[code] tables = OrderedDict() # type: dict for table in ['super', 'sub']: tables[table] = Table(['code', 'name'], paging=False) for code in getattr(class_, table): tables[table].rows.append([link(g.classes[code]), g.classes[code].name]) tables['domains'] = Table(['code', 'name'], paging=False) tables['ranges'] = Table(['code', 'name'], paging=False) for key, property_ in g.properties.items(): if code == property_.domain_class_code: tables['domains'].rows.append([link(property_), property_.name]) elif code == property_.range_class_code: tables['ranges'].rows.append([link(property_), property_.name]) return render_template('model/class_view.html', class_=class_, tables=tables, data={'info': [('code', class_.code), ('name', class_.name)]})
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 property_view(code: str) -> str: property_ = g.properties[code] domain = g.cidoc_classes[property_.domain_class_code] range_ = g.cidoc_classes[property_.range_class_code] info = { 'code': property_.code, 'name': property_.name, 'inverse': property_.name_inverse, 'domain': f'{link(domain)} {domain.name}', 'range': f'{link(range_)} {range_.name}' } tables = {} for table in ['super', 'sub']: tables[table] = Table(paging=False, defs=[{ 'orderDataType': 'cidoc-model', 'targets': [0] }, { 'sType': 'numeric', 'targets': [0] }]) for code_ in getattr(property_, table): tables[table].rows.append( [link(g.properties[code_]), g.properties[code_].name]) return render_template( 'model/property_view.html', tables=tables, property_=property_, info=info, title=_('model'), crumbs=[[_('model'), url_for('model_index')], [_('properties'), url_for('property_index')], property_.code])
def property_view(code): property_ = g.properties[code] domain = g.classes[property_.domain_class_code] range_ = g.classes[property_.range_class_code] tables = { 'info': [ ('code', property_.code), ('name', property_.name), ('inverse', property_.name_inverse), ('domain', link(domain) + ' ' + domain.name), ('range', link(range_) + ' ' + range_.name)]} for table in ['super', 'sub']: tables[table] = {'id': table, 'header': ['code', 'name'], 'data': [], 'show_pager': False, 'sort': 'sortList: [[0, 0]],headers: {0: { sorter: "property_code" }}'} for code in getattr(property_, table): tables[table]['data'].append([link(g.properties[code]), g.properties[code].name]) return render_template('model/property_view.html', property=property_, tables=tables)
def import_index(): table = {'id': 'project', 'header': [_('project'), _('entities'), _('description')], 'data': []} for project in ImportMapper.get_all_projects(): table['data'].append([ link(project), format_number(project.count), truncate_string(project.description)]) return render_template('import/index.html', table=table)
def property_index(): classes = g.classes properties = g.properties table = {'id': 'properties', 'data': [], 'header': ['code', 'name', 'inverse', 'domain', 'domain name', 'range', 'range name'], 'sort': 'sortList: [[0, 0]],headers: {0: { sorter: "property_code" }, ' '3: { sorter: "class_code" }, 5: { sorter: "class_code" }}'} for property_id, property_ in properties.items(): table['data'].append([ link(property_), property_.name, property_.name_inverse, link(classes[property_.domain_class_code]), classes[property_.domain_class_code].name, link(classes[property_.range_class_code]), classes[property_.range_class_code].name]) return render_template('model/property.html', table=table)
def check_links(): """ Check all existing links for CIDOC CRM validity and return the invalid ones.""" from openatlas.util.util import link from openatlas.models.entity import EntityMapper sql = """ SELECT DISTINCT l.property_code AS property, d.class_code AS domain, r.class_code AS range FROM model.link l JOIN model.entity d ON l.domain_id = d.id JOIN model.entity r ON l.range_id = r.id;""" g.cursor.execute(sql) debug_model['link sql'] += 1 invalid_links = [] for row in g.cursor.fetchall(): property_ = g.properties[row.property] domain_is_valid = property_.find_object('domain_class_code', row.domain) range_is_valid = property_.find_object('range_class_code', row.range) invalid_linking = [] if not domain_is_valid or not range_is_valid: invalid_linking.append({ 'property': row.property, 'domain': row.domain, 'range': row.range}) for item in invalid_linking: sql = """ SELECT l.id, l.property_code, l.domain_id, l.range_id, l.description, l.created, l.modified FROM model.link l JOIN model.entity d ON l.domain_id = d.id JOIN model.entity r ON l.range_id = r.id WHERE l.property_code = %(property)s AND d.class_code = %(domain)s AND r.class_code = %(range)s;""" g.cursor.execute(sql, {'property': item['property'], 'domain': item['domain'], 'range': item['range']}) debug_model['link sql'] += 1 for row2 in g.cursor.fetchall(): domain = EntityMapper.get_by_id(row2.domain_id) range_ = EntityMapper.get_by_id(row2.range_id) invalid_links.append({'domain': link(domain) + ' (' + domain.class_.code + ')', 'property': link(g.properties[row2.property_code]), 'range': link(range_) + ' (' + range_.class_.code + ')'}) return invalid_links
def event_view(id_): event = EntityMapper.get_by_id(id_) event.set_dates() tables = { 'info': get_entity_data(event), 'file': {'id': 'files', 'data': [], 'header': app.config['TABLE_HEADERS']['file'] + [_('main image')]}, 'subs': {'id': 'sub-event', 'data': [], 'header': app.config['TABLE_HEADERS']['event']}, 'source': {'id': 'source', 'data': [], 'header': app.config['TABLE_HEADERS']['source']}, 'actor': {'id': 'actor', 'data': [], 'header': ['actor', 'class', 'involvement', 'first', 'last', 'description']}, 'reference': {'id': 'reference', 'data': [], 'header': app.config['TABLE_HEADERS']['reference'] + ['pages']}} for link_ in event.get_links(['P11', 'P14', 'P22', 'P23']): first = link_.first if not link_.first and event.first: first = '<span class="inactive" style="float:right">' + str(event.first) + '</span>' last = link_.last if not link_.last and event.last: last = '<span class="inactive" style="float:right">' + str(event.last) + '</span>' data = ([link(link_.range), g.classes[link_.range.class_.code].name, link_.type.name if link_.type else '', first, last, truncate_string(link_.description)]) if is_authorized('editor'): update_url = url_for('involvement_update', id_=link_.id, origin_id=event.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=event.id) + '#tab-actor' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, link_.range.name)) tables['actor']['data'].append(data) profile_image_id = event.get_profile_image_id() for link_ in event.get_links('P67', True): domain = link_.domain data = get_base_table_data(domain) if domain.view_name == 'file': # pragma: no cover extension = data[3].replace('.', '') data.append(get_profile_image_table_link(domain, event, extension, profile_image_id)) if not profile_image_id and extension in app.config['DISPLAY_FILE_EXTENSIONS']: profile_image_id = domain.id if domain.view_name not in ['source', 'file']: data.append(truncate_string(link_.description)) if is_authorized('editor'): update_url = url_for('reference_link_update', link_id=link_.id, origin_id=event.id) data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') if is_authorized('editor'): url = url_for('link_delete', id_=link_.id, origin_id=event.id) data.append(display_remove_link(url + '#tab-' + domain.view_name, domain.name)) tables[domain.view_name]['data'].append(data) for sub_event in event.get_linked_entities('P117', True): tables['subs']['data'].append(get_base_table_data(sub_event)) return render_template('event/view.html', event=event, tables=tables, profile_image_id=profile_image_id)
def class_view(code): class_ = g.classes[code] tables = OrderedDict() for table in ['super', 'sub']: tables[table] = {'id': table, 'header': ['code', 'name'], 'data': [], 'show_pager': False, 'sort': 'sortList: [[0, 0]],headers: {0: { sorter: "class_code" }}'} for code in getattr(class_, table): tables[table]['data'].append([link(g.classes[code]), g.classes[code].name]) tables['domains'] = { 'id': 'domains', 'header': ['code', 'name'], 'data': [], 'show_pager': False, 'sort': 'sortList: [[0, 0]],headers: {0: { sorter: "property_code" }}'} tables['ranges'] = { 'id': 'ranges', 'header': ['code', 'name'], 'data': [], 'show_pager': False, 'sort': 'sortList: [[0, 0]],headers: {0: { sorter: "property_code" }}'} for key, property_ in g.properties.items(): if code == property_.domain_class_code: tables['domains']['data'].append([link(property_), property_.name]) elif code == property_.range_class_code: tables['ranges']['data'].append([link(property_), property_.name]) return render_template('model/class_view.html', class_=class_, tables=tables, data={'info': [('code', class_.code), ('name', class_.name)]})
def import_project_view(id_): table = {'id': 'entities', 'data': [], 'header': [_('name'), _('class'), _('description'), 'origin ID', _('date')]} for entity in EntityMapper.get_by_project_id(id_): table['data'].append([ link(entity), entity.class_.name, truncate_string(entity.description), entity.origin_id, format_date(entity.created)]) project = ImportMapper.get_project_by_id(id_) return render_template('import/project_view.html', project=project, table=table)
def source_update(id_): source = EntityMapper.get_by_id(id_) form = build_form(SourceForm, 'Source', source, request) if form.validate_on_submit(): if was_modified(form, source): # pragma: no cover del form.save flash(_('error modified'), 'error') modifier = link(logger.get_log_for_advanced_view(source.id)['modifier']) return render_template('source/update.html', form=form, source=source, modifier=modifier) save(form, source) return redirect(url_for('source_view', id_=id_)) return render_template('source/update.html', form=form, source=source)
def build_search_table(form): table = {'id': 'search', 'data': [], 'header': ['name', 'class', 'first', 'last', 'description']} codes = [] for name in form.classes.data: codes += app.config['CLASS_CODES'][name] if name == 'actor': codes.append('E82') if name == 'place': codes.append('E41') for entity in EntityMapper.search(form.term.data, codes, form.desc.data, form.own.data): table['data'].append([ link(entity), entity.class_.name, entity.first, entity.last, truncate_string(entity.description)]) return table
def source_view(id_): source = EntityMapper.get_by_id(id_) tables = { 'info': get_entity_data(source), 'text': {'id': 'translation', 'data': [], 'header': ['text', 'type', 'content']}, 'file': {'id': 'files', 'data': [], 'header': app.config['TABLE_HEADERS']['file'] + [_('main image')]}, 'reference': {'id': 'source', 'data': [], 'header': app.config['TABLE_HEADERS']['reference'] + ['page']}} for text in source.get_linked_entities('P73'): tables['text']['data'].append([ link(text), next(iter(text.nodes)).name if text.nodes else '', truncate_string(text.description)]) for name in ['actor', 'event', 'place', 'feature', 'stratigraphic-unit', 'find']: tables[name] = {'id': name, 'header': app.config['TABLE_HEADERS'][name], 'data': []} for link_ in source.get_links('P67'): range_ = link_.range data = get_base_table_data(range_) if is_authorized('editor'): url = url_for('link_delete', id_=link_.id, origin_id=source.id) data.append(display_remove_link(url + '#tab-' + range_.table_name, range_.name)) tables[range_.table_name]['data'].append(data) profile_image_id = source.get_profile_image_id() for link_ in source.get_links(['P67', 'P128'], True): domain = link_.domain data = get_base_table_data(domain) if domain.view_name == 'file': # pragma: no cover extension = data[3].replace('.', '') data.append(get_profile_image_table_link(domain, source, extension, profile_image_id)) if not profile_image_id and extension in app.config['DISPLAY_FILE_EXTENSIONS']: profile_image_id = domain.id if domain.view_name not in ['file']: data.append(link_.description) if is_authorized('editor'): update_url = url_for('reference_link_update', link_id=link_.id, origin_id=source.id) data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') if is_authorized('editor'): url = url_for('link_delete', id_=link_.id, origin_id=source.id) data.append(display_remove_link(url + '#tab-' + domain.view_name, domain.name)) tables[domain.view_name]['data'].append(data) return render_template('source/view.html', source=source, tables=tables, profile_image_id=profile_image_id)
def event_update(id_): event = EntityMapper.get_by_id(id_) event.set_dates() form = build_form(EventForm, 'Event', event, request) if event.class_.code != 'E8': del form.given_place form.event_id.data = event.id if form.validate_on_submit(): if was_modified(form, event): # pragma: no cover del form.save flash(_('error modified'), 'error') modifier = link(logger.get_log_for_advanced_view(event.id)['modifier']) return render_template('event/update.html', form=form, event=event, modifier=modifier) save(form, event) return redirect(url_for('event_view', id_=id_)) super_event = event.get_linked_entity('P117') form.event.data = super_event.id if super_event else '' place = event.get_linked_entity('P7') form.place.data = place.get_linked_entity('P53', True).id if place else '' if event.class_.code == 'E8': # Form data for acquisition form.given_place.data = [entity.id for entity in event.get_linked_entities('P24')] return render_template('event/update.html', form=form, event=event)
def actor_update(id_): actor = EntityMapper.get_by_id(id_) actor.set_dates() code_class = {'E21': 'Person', 'E74': 'Group', 'E40': 'Legal Body'} form = build_form(ActorForm, code_class[actor.class_.code], actor, request) if form.validate_on_submit(): if was_modified(form, actor): # pragma: no cover del form.save flash(_('error modified'), 'error') modifier = link(logger.get_log_for_advanced_view(actor.id)['modifier']) return render_template('actor/update.html', form=form, actor=actor, modifier=modifier) save(form, actor) return redirect(url_for('actor_view', id_=id_)) residence = actor.get_linked_entity('P74') form.residence.data = residence.get_linked_entity('P53', True).id if residence else '' first = actor.get_linked_entity('OA8') form.appears_first.data = first.get_linked_entity('P53', True).id if first else '' last = actor.get_linked_entity('OA9') form.appears_last.data = last.get_linked_entity('P53', True).id if last else '' for alias in [x.name for x in actor.get_linked_entities('P131')]: form.alias.append_entry(alias) form.alias.append_entry('') return render_template('actor/update.html', form=form, actor=actor)
def class_index(): table = {'id': 'classes', 'header': ['code', 'name'], 'data': [], 'sort': 'sortList: [[0, 0]],headers: {0: { sorter: "class_code" }}'} for class_id, class_ in g.classes.items(): table['data'].append([link(class_), class_.name]) return render_template('model/class.html', table=table)
def actor_view(id_): actor = EntityMapper.get_by_id(id_) actor.set_dates() objects = [] info = get_entity_data(actor) residence = actor.get_linked_entity('P74') if residence: object_ = residence.get_linked_entity('P53', True) objects.append(object_) info.append((uc_first(_('residence')), link(object_))) first = actor.get_linked_entity('OA8') if first: object_ = first.get_linked_entity('P53', True) objects.append(object_) info.append((uc_first(_('appears first')), link(object_))) last = actor.get_linked_entity('OA9') if last: object_ = last.get_linked_entity('P53', True) objects.append(object_) info.append((uc_first(_('appears last')), link(object_))) tables = { 'info': info, 'file': {'id': 'files', 'data': [], 'header': app.config['TABLE_HEADERS']['file'] + [_('main image')]}, 'source': {'id': 'source', 'data': [], 'header': app.config['TABLE_HEADERS']['source']}, 'reference': {'id': 'reference', 'data': [], 'header': app.config['TABLE_HEADERS']['reference'] + ['pages']}, 'event': {'id': 'event', 'data': [], 'header': ['event', 'class', 'involvement', 'first', 'last', 'description']}, 'relation': {'id': 'relation', 'data': [], 'sort': 'sortList:[[0,0]]', 'header': ['relation', 'actor', 'first', 'last', 'description']}, 'member_of': {'id': 'member_of', 'data': [], 'header': ['member of', 'function', 'first', 'last', 'description']}} profile_image_id = actor.get_profile_image_id() for link_ in actor.get_links('P67', True): domain = link_.domain data = get_base_table_data(domain) if domain.view_name == 'file': extension = data[3].replace('.', '') data.append(get_profile_image_table_link(domain, actor, extension, profile_image_id)) if not profile_image_id and extension in app.config['DISPLAY_FILE_EXTENSIONS']: profile_image_id = domain.id if domain.view_name not in ['source', 'file']: data.append(truncate_string(link_.description)) if is_authorized('editor'): update_url = url_for('reference_link_update', link_id=link_.id, origin_id=actor.id) data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') if is_authorized('editor'): url = url_for('link_delete', id_=link_.id, origin_id=actor.id) data.append(display_remove_link(url + '#tab-' + domain.view_name, domain.name)) tables[domain.view_name]['data'].append(data) # Todo: Performance - getting every place of every object for every event is very costly for link_ in actor.get_links(['P11', 'P14', 'P22', 'P23'], True): event = link_.domain first = link_.first place = event.get_linked_entity('P7') if place: objects.append(place.get_linked_entity('P53', True)) if not link_.first and event.first: first = '<span class="inactive" style="float:right">' + str(event.first) + '</span>' last = link_.last if not link_.last and event.last: last = '<span class="inactive" style="float:right">' + str(event.last) + '</span>' data = ([link(event), g.classes[event.class_.code].name, link_.type.name if link_.type else '', first, last, truncate_string(link_.description)]) if is_authorized('editor'): update_url = url_for('involvement_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=actor.id) + '#tab-event' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, link_.domain.name)) tables['event']['data'].append(data) for link_ in actor.get_links('OA7') + actor.get_links('OA7', True): if actor.id == link_.domain.id: type_ = link_.type.get_name_directed() if link_.type else '' related = link_.range else: type_ = link_.type.get_name_directed(True) if link_.type else '' related = link_.domain data = ([type_, link(related), link_.first, link_.last, truncate_string(link_.description)]) if is_authorized('editor'): update_url = url_for('relation_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=actor.id) + '#tab-relation' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, related.name)) tables['relation']['data'].append(data) for link_ in actor.get_links('P107', True): data = ([link(link_.domain), link_.type.name if link_.type else '', link_.first, link_.last, truncate_string(link_.description)]) if is_authorized('editor'): update_url = url_for('member_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=actor.id) + '#tab-member-of' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, link_.domain.name)) tables['member_of']['data'].append(data) if actor.class_.code in app.config['CLASS_CODES']['group']: tables['member'] = {'id': 'member', 'data': [], 'header': ['member', 'function', 'first', 'last', 'description']} for link_ in actor.get_links('P107'): data = ([link(link_.range), link_.type.name if link_.type else '', link_.first, link_.last, truncate_string(link_.description)]) if is_authorized('editor'): update_url = url_for('member_update', id_=link_.id, origin_id=actor.id) unlink_url = url_for('link_delete', id_=link_.id, origin_id=actor.id) + '#tab-member' data.append('<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>') data.append(display_remove_link(unlink_url, link_.range.name)) tables['member']['data'].append(data) gis_data = GisMapper.get_all(objects) if objects else None if gis_data and gis_data['gisPointSelected'] == '[]': gis_data = None return render_template('actor/view.html', actor=actor, tables=tables, gis_data=gis_data, profile_image_id=profile_image_id)
def link(self, entity): return util.link(entity)