コード例 #1
0
ファイル: admin.py プロジェクト: thomaswoehlke/OpenAtlas
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)
コード例 #2
0
ファイル: admin.py プロジェクト: thomaswoehlke/OpenAtlas
def admin_check_dates() -> str:
    # Get invalid date combinations (e.g. begin after end)
    tables = {'link_dates': Table(['link', 'domain', 'range']),
              'involvement_dates': Table(['actor', 'event', 'class', 'involvement', 'description']),
              'dates': Table(['name', 'class', 'type', 'system type', 'created', 'updated',
                              'description'])}
    for entity in DateMapper.get_invalid_dates():
        tables['dates'].rows.append([link(entity), link(entity.class_), entity.print_base_type(),
                                     entity.system_type, format_date(entity.created),
                                     format_date(entity.modified),
                                     truncate_string(entity.description)])
    for link_ in DateMapper.get_invalid_link_dates():
        label = ''
        if link_.property.code == 'OA7':  # pragma: no cover
            label = 'relation'
        elif link_.property.code == 'P107':  # pragma: no cover
            label = 'member'
        elif link_.property.code in ['P11', 'P14', 'P22', 'P23']:
            label = 'involvement'
        url = url_for(label + '_update', id_=link_.id, origin_id=link_.domain.id)
        tables['link_dates'].rows.append(['<a href="' + url + '">' + uc_first(_(label)) + '</a>',
                                          link(link_.domain), link(link_.range)])
    for link_ in DateMapper.invalid_involvement_dates():
        event = link_.domain
        actor = link_.range
        update_url = url_for('involvement_update', id_=link_.id, origin_id=actor.id)
        data = ([link(actor), link(event), g.classes[event.class_.code].name,
                 link_.type.name if link_.type else '', truncate_string(link_.description),
                 '<a href="' + update_url + '">' + uc_first(_('edit')) + '</a>'])
        tables['involvement_dates'].rows.append(data)
    return render_template('admin/check_dates.html', tables=tables)
コード例 #3
0
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')])
コード例 #4
0
ファイル: admin.py プロジェクト: acdh-oeaw/OpenAtlas
def admin_check_link_duplicates(
        delete: Optional[str] = None) -> Union[str, Response]:
    if delete:
        count = Link.delete_link_duplicates()
        logger.log('info', 'admin', f"Deleted duplicate links: {count}")
        flash(f"{_('deleted links')}: {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.types[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']])
    if not table.rows:  # Check single types for multiple use
        table = Table(
            ['entity', 'class', 'base type', 'incorrect multiple types'])
        for row in Link.check_single_type_duplicates():
            remove_links = []
            for type_ in row['offending_types']:
                url = url_for(
                    'admin_delete_single_type_duplicate',
                    entity_id=row['entity'].id,
                    type_id=type_.id)
                remove_links.append(
                    f'<a href="{url}">{uc_first(_("remove"))}</a>'
                    f'{type_.name}')
            table.rows.append([
                link(row['entity']),
                row['entity'].class_.name,
                link(g.types[row['type'].id]),
                '<br><br><br><br><br>'.join(remove_links)])
    return render_template(
        'admin/check_link_duplicates.html',
        table=table,
        title=_('admin'),
        crumbs=[
            [_('admin'), f"{url_for('admin_index')}#tab-data"],
            _('check link duplicates')])
コード例 #5
0
ファイル: admin.py プロジェクト: thomaswoehlke/OpenAtlas
def admin_orphans() -> str:
    header = ['name', 'class', 'type', 'system type', 'created', 'updated', 'description']
    tables = {'orphans': Table(header),
              'unlinked': Table(header),
              'missing_files': Table(header),
              'circular': Table(['entity']),
              'nodes': Table(['name', 'root']),
              'orphaned_files': Table(['name', 'size', 'date', 'ext'])}
    tables['circular'].rows = [[link(entity)] for entity in EntityMapper.get_circular()]
    for entity in EntityMapper.get_orphans():
        name = 'unlinked' if entity.class_.code in app.config['CODE_CLASS'].keys() else 'orphans'
        tables[name].rows.append([link(entity),
                                  link(entity.class_),
                                  entity.print_base_type(),
                                  entity.system_type,
                                  format_date(entity.created),
                                  format_date(entity.modified),
                                  truncate_string(entity.description)])
    for node in NodeMapper.get_orphans():
        tables['nodes'].rows.append([link(node), link(g.nodes[node.root[-1]])])

    # Get orphaned file entities (no corresponding file)
    file_ids = []
    for entity in EntityMapper.get_by_system_type('file', nodes=True):
        file_ids.append(str(entity.id))
        if not get_file_path(entity):
            tables['missing_files'].rows.append([link(entity),
                                                 link(entity.class_),
                                                 entity.print_base_type(),
                                                 entity.system_type,
                                                 format_date(entity.created),
                                                 format_date(entity.modified),
                                                 truncate_string(entity.description)])

    # Get orphaned files (no corresponding entity)
    for file in os.scandir(app.config['UPLOAD_FOLDER_PATH']):
        name = file.name
        if name != '.gitignore' and splitext(file.name)[0] not in file_ids:
            confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?', name=name) + '\')"'
            tables['orphaned_files'].rows.append([
                name,
                convert_size(file.stat().st_size),
                format_date(datetime.datetime.utcfromtimestamp(file.stat().st_ctime)),
                splitext(name)[1],
                '<a href="' + url_for('download_file', filename=name) + '">' + uc_first(
                    _('download')) + '</a>',
                '<a href="' + url_for('admin_file_delete', filename=name) + '" ' +
                confirm + '>' + uc_first(_('delete')) + '</a>'])
    return render_template('admin/orphans.html', tables=tables)
コード例 #6
0
ファイル: user.py プロジェクト: nhmvienna/OpenAtlas
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')])
コード例 #7
0
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)
コード例 #8
0
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')])
コード例 #9
0
ファイル: user.py プロジェクト: nhmvienna/OpenAtlas
def user_view(id_: int) -> str:
    user = User.get_by_id(id_)
    info = {
        _('username'):
        user.username,
        _('group'):
        user.group,
        _('full name'):
        user.real_name,
        _('email'):
        user.email
        if is_authorized('manager') or user.settings['show_email'] else '',
        _('language'):
        user.settings['language'],
        _('last login'):
        format_date(user.login_last_success),
        _('failed logins'):
        user.login_failed_count if is_authorized('manager') else ''
    }
    return render_template(
        'user/view.html',
        user=user,
        info=info,
        title=user.username,
        crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-user"],
                user.username])
コード例 #10
0
ファイル: index.py プロジェクト: thomaswoehlke/OpenAtlas
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)
コード例 #11
0
ファイル: file.py プロジェクト: thomaswoehlke/OpenAtlas
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)
コード例 #12
0
def user_index():
    tables = {'user': {
        'id': 'user',
        'header': ['username', 'group', 'email', 'newsletter', 'created', 'last login', 'entities'],
        'data': []}}
    for user in UserMapper.get_all():
        count = UserMapper.get_created_entities_count(user.id)
        tables['user']['data'].append([
            link(user),
            user.group,
            user.email if is_authorized('manager') or user.settings['show_email'] else '',
            _('yes') if user.settings['newsletter'] else '',
            format_date(user.created),
            format_date(user.login_last_success),
            format_number(count) if count else ''])
    return render_template('user/index.html', tables=tables)
コード例 #13
0
def user_view(id_):
    user = UserMapper.get_by_id(id_)
    data = {'info': [
        (_('username'), link(user)),
        (_('group'), user.group),
        (_('full name'), user.real_name),
        (_('email'), user.email if is_authorized('manager') or user.settings['show_email'] else ''),
        (_('language'), user.settings['language']),
        (_('last login'), format_date(user.login_last_success)),
        (_('failed logins'), user.login_failed_count if is_authorized('manager') else '')]}
    return render_template('user/view.html', user=user, data=data)
コード例 #14
0
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)
コード例 #15
0
ファイル: admin.py プロジェクト: stefaneichert/OpenAtlas
def admin_check_link_duplicates(
        delete: Optional[str] = None) -> Union[str, Response]:
    if delete:
        count = Link.delete_link_duplicates()
        logger.log('info', 'admin', f"Deleted duplicate links: {count}")
        flash(f"{_('deleted links')}: {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 check single types for multiple use
        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'), f"{url_for('admin_index')}#tab-data"],
            _('check link duplicates')])
コード例 #16
0
ファイル: entity.py プロジェクト: acdh-oeaw/OpenAtlas
def add_note_tab(entity: Entity) -> Tab:
    tab = Tab('note', entity=entity)
    for note in current_user.get_notes_by_entity_id(entity.id):
        data = [
            format_date(note['created']),
            uc_first(_('public'))
            if note['public'] else uc_first(_('private')),
            link(User.get_by_id(note['user_id'])),
            note['text'],
            f'<a href="{url_for("note_view", id_=note["id"])}">'
            f'{uc_first(_("view"))}</a>']
        tab.table.rows.append(data)
    return tab
コード例 #17
0
ファイル: sql.py プロジェクト: thomaswoehlke/OpenAtlas
def sql_execute() -> str:
    path = app.config['EXPORT_FOLDER_PATH'] + '/sql'
    latest_file = None
    latest_file_date = None
    for file in [
            f for f in os.listdir(path)
            if os.path.isfile(os.path.join(path, f))
    ]:
        name = basename(file)
        if name == '.gitignore':
            continue
        file_date = datetime.utcfromtimestamp(
            os.path.getmtime(path + '/' + file))
        if not latest_file_date or file_date > latest_file_date:
            latest_file = file
            latest_file_date = file_date
    file_data = {'backup_to_old': True}
    if latest_file:
        yesterday = datetime.today() - timedelta(days=1)
        file_data['file'] = latest_file
        file_data[
            'backup_to_old'] = True if yesterday > latest_file_date else False
        file_data['size'] = convert_size(
            os.path.getsize(path + '/' + latest_file))
        file_data['date'] = format_date(latest_file_date)
    response = ''
    form = SqlForm()
    if form.validate_on_submit() and not file_data['backup_to_old']:
        g.execute('BEGIN')
        try:
            g.execute(form.statement.data)
            response = '<p>Rows affected: {count}</p>'.format(
                count=g.cursor.rowcount)
            try:
                response += '<p>{rows}</p>'.format(rows=g.cursor.fetchall())
            except:  # pragma: no cover
                pass  # Assuming it was no SELECT statement so returning just the rowcount
            g.execute('COMMIT')
            flash(_('SQL executed'), 'info')
        except Exception as e:
            g.cursor.execute('ROLLBACK')
            logger.log('error', 'database', 'transaction failed', e)
            response = e
            flash(_('error transaction'), 'error')
    return render_template('sql/execute.html',
                           form=form,
                           response=response,
                           file_data=file_data)
コード例 #18
0
ファイル: imports.py プロジェクト: thomaswoehlke/OpenAtlas
def import_project_view(id_: int) -> str:
    table = Table(
        [_('name'),
         _('class'),
         _('description'), 'origin ID',
         _('date')])
    for entity in EntityMapper.get_by_project_id(id_):
        table.rows.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)
コード例 #19
0
def get_table(view: str) -> Table:
    header = g.table_headers[view]
    if view == 'file':
        header = ['date'] + header
        if session['settings']['image_processing'] \
                and current_user.settings['table_show_icons']:
            header.insert(1, _('icon'))
    table = Table(header)
    if view == 'file':
        if not g.file_stats:
            g.file_stats = get_file_stats()
        for entity in Entity.get_by_class('file', nodes=True):
            date = 'N/A'
            if entity.id in g.file_stats:
                date = format_date(
                    datetime.datetime.utcfromtimestamp(
                        g.file_stats[entity.id]['date']))
            data = [
                date,
                link(entity),
                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
            ]
            if session['settings']['image_processing'] \
                    and current_user.settings['table_show_icons']:
                data.insert(1, file_preview(entity.id))
            table.rows.append(data)

    elif view == 'reference_system':
        for system in g.reference_systems.values():
            table.rows.append([
                link(system), system.count if system.count else '',
                external_url(system.website_url),
                external_url(system.resolver_url), system.placeholder,
                link(g.nodes[system.precision_default_id])
                if system.precision_default_id else '', system.description
            ])
    else:
        classes = 'place' if view == 'place' else g.view_class_mapping[view]
        entities = Entity.get_by_class(classes, nodes=True, aliases=True)
        table.rows = [get_base_table_data(entity) for entity in entities]
    return table
コード例 #20
0
def user_activity(user_id=0):
    form = ActivityForm()
    form.user.choices = [(0, _('all'))] + UserMapper.get_users()
    table = {'id': 'activity', 'header': ['date', 'user', 'action', 'entity'], 'data': []}
    if form.validate_on_submit():
        activities = UserMapper.get_activities(form.limit.data, form.user.data, form.action.data)
    elif user_id:
        form.user.data = user_id
        activities = UserMapper.get_activities(100, user_id, 'all')
    else:
        activities = UserMapper.get_activities(100, 0, 'all')
    for row in activities:
        entity = EntityMapper.get_by_id(row.entity_id, True)
        user = UserMapper.get_by_id(row.user_id)
        table['data'].append([
            format_date(row.created),
            link(user) if user else 'id ' + str(row.user_id),
            _(row.action),
            link(entity) if entity else 'id ' + str(row.entity_id)])
    return render_template('user/activity.html', table=table, form=form)
コード例 #21
0
def user_activity(user_id: Optional[int] = 0) -> str:
    form = ActivityForm()
    form.user.choices = [(0, _('all'))] + UserMapper.get_users()
    if form.validate_on_submit():
        activities = UserMapper.get_activities(form.limit.data, form.user.data,
                                               form.action.data)
    elif user_id:
        form.user.data = user_id
        activities = UserMapper.get_activities(100, user_id, 'all')
    else:
        activities = UserMapper.get_activities(100, 0, 'all')
    table = Table(['date', 'user', 'action', 'entity'])
    for row in activities:
        entity = EntityMapper.get_by_id(row.entity_id, ignore_not_found=True)
        user = UserMapper.get_by_id(row.user_id)
        table.rows.append([
            format_date(row.created),
            link(user) if user else 'id ' + str(row.user_id),
            _(row.action),
            link(entity) if entity else 'id ' + str(row.entity_id)
        ])
    return render_template('user/activity.html', table=table, form=form)
コード例 #22
0
def import_project_view(id_: int) -> str:
    project = Import.get_project_by_id(id_)
    tabs = {
        'info':
        Tab('info',
            content=render_template('import/project_view.html',
                                    project=project)),
        'entities':
        Tab('entities',
            table=Table(['name', 'class', 'description', 'origin ID', 'date']))
    }
    for entity in Entity.get_by_project_id(id_):
        tabs['entities'].table.rows.append([
            link(entity), entity.class_.label, entity.description,
            entity.origin_id,
            format_date(entity.created)
        ])
    return render_template(
        'tabs.html',
        tabs=tabs,
        title=_('import'),
        crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-data"],
                [_('import'), url_for('import_index')], project.name])
コード例 #23
0
def admin_orphans(delete=None):
    if delete:
        count = EntityMapper.delete_orphans(delete)
        flash(_('info orphans deleted:') + ' ' + str(count), 'info')
        return redirect(url_for('admin_orphans'))
    header = [
        'name', 'class', 'type', 'system type', 'created', 'updated',
        'description'
    ]
    tables = {
        'orphans': {
            'id': 'orphans',
            'header': header,
            'data': []
        },
        'unlinked': {
            'id': 'unlinked',
            'header': header,
            'data': []
        },
        'nodes': {
            'id': 'nodes',
            'header': ['name', 'root'],
            'data': []
        },
        'missing_files': {
            'id': 'missing_files',
            'header': header,
            'data': []
        },
        'orphaned_files': {
            'id': 'orphaned_files',
            'data': [],
            'header': ['name', 'size', 'date', 'ext']
        }
    }
    for entity in EntityMapper.get_orphans():
        name = 'unlinked' if entity.class_.code in app.config[
            'CODE_CLASS'].keys() else 'orphans'
        tables[name]['data'].append([
            link(entity),
            link(entity.class_),
            entity.print_base_type(), entity.system_type,
            format_date(entity.created),
            format_date(entity.modified),
            truncate_string(entity.description)
        ])
    for node in NodeMapper.get_orphans():
        tables['nodes']['data'].append(
            [link(node), link(g.nodes[node.root[-1]])])

    file_ids = []
    # Get orphaned file entities (no corresponding file)
    for entity in EntityMapper.get_by_system_type('file'):
        file_ids.append(str(entity.id))
        if not get_file_path(entity):
            tables['missing_files']['data'].append([
                link(entity),
                link(entity.class_),
                entity.print_base_type(), entity.system_type,
                format_date(entity.created),
                format_date(entity.modified),
                truncate_string(entity.description)
            ])

    # Get orphaned files (no corresponding entity)
    path = app.config['UPLOAD_FOLDER_PATH']
    for file in [
            f for f in os.listdir(path)
            if os.path.isfile(os.path.join(path, f))
    ]:
        name = basename(file)
        file_path = path + '/' + name
        if name != '.gitignore' and splitext(name)[0] not in file_ids:
            tables['orphaned_files']['data'].append([
                name,
                convert_size(os.path.getsize(file_path)),
                format_date(
                    datetime.datetime.fromtimestamp(
                        os.path.getmtime(file_path))),
                splitext(name)[1],
                '<a href="' + url_for('download_file', filename=name) + '">' +
                uc_first(_('download')) + '</a>'
            ])
    return render_template('admin/orphans.html', tables=tables)
コード例 #24
0
def admin_index(action: Optional[str] = None,
                id_: Optional[int] = None) -> Union[str, Response]:
    if is_authorized('manager'):
        if id_ and action == 'delete_user':
            user = User.get_by_id(id_)
            if not user \
                    or user.id == current_user.id \
                    or (user.group == 'admin' and not is_authorized('admin')):
                abort(403)
            User.delete(id_)
            flash(_('user deleted'), 'info')
        elif action == 'remove_logo':
            Settings.set_logo()
            return redirect(f"{url_for('admin_index')}#tab-file")
    tables = {
        'user':
        Table([
            'username', 'name', 'group', 'email', 'newsletter', 'created',
            'last login', 'entities'
        ],
              defs=[{
                  'className': 'dt-body-right',
                  'targets': 7
              }]),
        'content':
        Table(['name'] + list(app.config['LANGUAGES']))
    }
    for user in User.get_all():
        count = User.get_created_entities_count(user.id)
        email = user.email \
            if is_authorized('manager') or user.settings['show_email'] else ''
        tables['user'].rows.append([
            link(user), user.real_name, user.group, email,
            _('yes') if user.settings['newsletter'] else '',
            format_date(user.created),
            format_date(user.login_last_success),
            format_number(count) if count else ''
        ])
    for item, languages in get_content().items():
        content = [uc_first(_(item))]
        for language in app.config['LANGUAGES']:
            content.append(sanitize(languages[language], 'text'))
        content.append(link(_('edit'), url_for('admin_content', item=item)))
        tables['content'].rows.append(content)
    form = None
    if is_authorized('admin'):
        form = TestMailForm()
        if form.validate_on_submit(
        ) and g.settings['mail']:  # pragma: no cover
            subject = _('Test mail from %(site_name)s',
                        site_name=g.settings['site_name'])
            body = _('This test mail was sent by %(username)s',
                     username=current_user.username)
            body += f" {_('at')} '{request.headers['Host']}"
            if send_mail(subject, body, form.receiver.data):
                flash(
                    _('A test mail was sent to %(email)s.',
                      email=form.receiver.data), 'info')
        else:
            form.receiver.data = current_user.email
    tabs = {
        'files':
        Tab(_('files'),
            buttons=[
                manual('entity/file'),
                button(_('edit'), url_for('admin_settings', category='files'))
                if is_authorized('manager') else '',
                button(_('list'), url_for('index', view='file')),
                button(_('file'), url_for('insert', class_='file'))
            ],
            content=render_template('admin/file.html',
                                    info=get_form_settings(FilesForm()),
                                    disk_space_info=get_disk_space_info())),
        'user':
        Tab(_('user'),
            table=tables['user'],
            buttons=[
                manual('admin/user'),
                button(_('activity'), url_for('user_activity')),
                button(_('newsletter'), url_for('admin_newsletter'))
                if is_authorized('manager') and g.settings['mail'] else '',
                button(_('user'), url_for('user_insert'))
                if is_authorized('manager') else ''
            ])
    }
    if is_authorized('admin'):
        tabs['general'] = Tab(
            'general',
            content=display_info(get_form_settings(GeneralForm())),
            buttons=[
                manual('admin/general'),
                button(_('edit'), url_for('admin_settings',
                                          category='general')),
                button(_('system log'), url_for('admin_log'))
            ])
        tabs['email'] = Tab(
            'email',
            content=display_info(get_form_settings(MailForm())),
            buttons=[
                manual('admin/mail'),
                button(_('edit'), url_for('admin_settings', category='mail'))
            ])
        if g.settings['mail']:
            tabs['email'].content += display_form(form)
    if is_authorized('manager'):
        tabs['modules'] = Tab(_('modules'),
                              content=f"""
                <h1>{_('Defaults for new user')}</h1>
                {display_info(get_form_settings(ModulesForm()))}""",
                              buttons=[
                                  manual('admin/modules'),
                                  button(
                                      _('edit'),
                                      url_for('admin_settings',
                                              category='modules'))
                              ])
        tabs['map'] = Tab('map',
                          content=display_info(get_form_settings(MapForm())),
                          buttons=[
                              manual('admin/map'),
                              button(_('edit'),
                                     url_for('admin_settings', category='map'))
                          ])
        tabs['content'] = Tab('content',
                              content=tables['content'].display(),
                              buttons=[manual('admin/content')])
    if is_authorized('contributor'):
        tabs['data'] = Tab('data',
                           content=render_template(
                               'admin/data.html',
                               imports=Import.get_all_projects(),
                               info=get_form_settings(ApiForm())))
    return render_template('tabs.html',
                           tabs=tabs,
                           title=_('admin'),
                           crumbs=[_('admin')])
コード例 #25
0
def admin_orphans() -> str:
    header = [
        'name', 'class', 'type', 'system type', 'created', 'updated',
        'description'
    ]
    tabs = {
        'orphans':
        Tab('orphans', table=Table(header)),
        'unlinked':
        Tab('unlinked', table=Table(header)),
        'types':
        Tab('type',
            table=Table(
                ['name', 'root'],
                [[link(type_), link(g.types[type_.root[0]])]
                 for type_ in Type.get_type_orphans()])),
        'missing_files':
        Tab('missing_files', table=Table(header)),
        'orphaned_files':
        Tab('orphaned_files', table=Table(['name', 'size', 'date', 'ext'])),
        'circular':
        Tab('circular_dependencies',
            table=Table(['entity'],
                        [[link(e)]
                         for e in Entity.get_entities_linked_to_itself()]))
    }

    for entity in filter(lambda x: not isinstance(x, ReferenceSystem),
                         Entity.get_orphans()):
        tabs['unlinked' if entity.class_.
             view else 'orphans'].table.rows.append([
                 link(entity),
                 link(entity.class_),
                 link(entity.standard_type), entity.class_.label,
                 format_date(entity.created),
                 format_date(entity.modified), entity.description
             ])

    # Orphaned file entities with no corresponding file
    entity_file_ids = []
    for entity in Entity.get_by_class('file', types=True):
        entity_file_ids.append(entity.id)
        if not get_file_path(entity):
            tabs['missing_files'].table.rows.append([
                link(entity),
                link(entity.class_),
                link(entity.standard_type), entity.class_.label,
                format_date(entity.created),
                format_date(entity.modified), entity.description
            ])

    # Orphaned files with no corresponding entity
    for file in app.config['UPLOAD_DIR'].iterdir():
        if file.name != '.gitignore' \
                and os.path.isfile(file) \
                and int(file.stem) not in entity_file_ids:
            tabs['orphaned_files'].table.rows.append([
                file.stem,
                convert_size(file.stat().st_size),
                format_date(
                    datetime.datetime.utcfromtimestamp(file.stat().st_ctime)),
                file.suffix,
                link(_('download'), url_for('download_file',
                                            filename=file.name)),
                delete_link(file.name,
                            url_for('admin_file_delete', filename=file.name))
            ])

    for tab in tabs.values():
        tab.buttons = [manual('admin/data_integrity_checks')]
        if not tab.table.rows:
            tab.content = _('Congratulations, everything looks fine!')
    if tabs['orphaned_files'].table.rows and is_authorized('admin'):
        text = uc_first(_('delete all files without corresponding entities?'))
        tabs['orphaned_files'].buttons.append(
            button(_('delete all files'),
                   url_for('admin_file_delete', filename='all'),
                   onclick=f"return confirm('{text}')"))
    return render_template(
        'tabs.html',
        tabs=tabs,
        title=_('admin'),
        crumbs=[[_('admin'), f"{url_for('admin_index')}#tab-data"],
                _('orphans')])
コード例 #26
0
def overview() -> str:
    tabs = {
        'info':
        Tab('info'),
        'bookmarks':
        Tab('bookmarks', table=Table(['name', 'class', 'begin', 'end'])),
        'notes':
        Tab('notes',
            table=Table(
                ['date', _('visibility'), 'entity', 'class',
                 _('note')]))
    }
    tables = {
        'overview':
        Table(paging=False,
              defs=[{
                  'className': 'dt-body-right',
                  'targets': 1
              }]),
        'latest':
        Table(paging=False, order=[[0, 'desc']])
    }
    if current_user.is_authenticated and hasattr(current_user, 'bookmarks'):
        for entity_id in current_user.bookmarks:
            entity = Entity.get_by_id(entity_id)
            tabs['bookmarks'].table.rows.append([
                link(entity), entity.class_.label, entity.first, entity.last,
                bookmark_toggle(entity.id, True)
            ])
        for note in User.get_notes_by_user_id(current_user.id):
            entity = Entity.get_by_id(note['entity_id'])
            tabs['notes'].table.rows.append([
                format_date(note['created']),
                uc_first(_('public') if note['public'] else _('private')),
                link(entity), entity.class_.label, note['text'],
                f'<a href="{url_for("note_view", id_=note["id"])}">'
                f'{uc_first(_("view"))}</a>'
            ])
        for name, count in Entity.get_overview_counts().items():
            if count:
                url = url_for('index', view=g.class_view_mapping[name])
                if name == 'administrative_unit':
                    url = f"{url_for('node_index')}#menu-tab-places"
                elif name == 'type':
                    url = url_for('node_index')
                elif name == 'find':
                    url = url_for('index', view='artifact')
                elif name in [
                        'feature', 'human_remains', 'stratigraphic_unit',
                        'source_translation'
                ]:
                    url = ''
                tables['overview'].rows.append([
                    link(g.classes[name].label, url)
                    if url else g.classes[name].label,
                    format_number(count)
                ])
        for entity in Entity.get_latest(8):
            tables['latest'].rows.append([
                format_date(entity.created),
                link(entity), entity.class_.label, entity.first, entity.last,
                link(logger.get_log_for_advanced_view(entity.id)['creator'])
            ])
    tabs['info'].content = render_template('index/index.html',
                                           intro=get_translation('intro'),
                                           tables=tables)
    return render_template('tabs.html', tabs=tabs, crumbs=['overview'])
コード例 #27
0
ファイル: entity.py プロジェクト: nhmvienna/OpenAtlas
def entity_view(id_: int) -> Union[str, Response]:
    if id_ in g.nodes:  # Nodes have their own view
        entity = g.nodes[id_]
        if not entity.root:
            if entity.class_.name == 'administrative_unit':
                tab_hash = '#menu-tab-places_collapse-'
            elif entity.standard:
                tab_hash = '#menu-tab-standard_collapse-'
            elif entity.value_type:
                tab_hash = '#menu-tab-value_collapse-'
            else:
                tab_hash = '#menu-tab-custom_collapse-'
            return redirect(f"{url_for('node_index')}{tab_hash}{id_}")
    elif id_ in g.reference_systems:
        entity = g.reference_systems[id_]
    else:
        entity = Entity.get_by_id(id_, nodes=True, aliases=True)
        if not entity.class_.view:
            flash(_("This entity can't be viewed directly."), 'error')
            abort(400)

    event_links = None  # Needed for actor
    overlays = None  # Needed for place
    tabs = {'info': Tab('info')}
    if isinstance(entity, Node):
        tabs['subs'] = Tab('subs', entity=entity)
        tabs['entities'] = Tab('entities', entity=entity)
        root = g.nodes[entity.root[-1]] if entity.root else None
        if root and root.value_type:  # pragma: no cover
            tabs['entities'].table.header = [
                _('name'), _('value'),
                _('class'), _('info')
            ]
        for item in entity.get_linked_entities(['P2', 'P89'],
                                               inverse=True,
                                               nodes=True):
            if item.class_.name in ['location', 'reference_system']:
                continue  # pragma: no cover
            if item.class_.name == 'object_location':  # pragma: no cover
                item = item.get_linked_entity_safe('P53', inverse=True)
            data = [link(item)]
            if root and root.value_type:  # pragma: no cover
                data.append(format_number(item.nodes[entity]))
            data.append(item.class_.label)
            data.append(item.description)
            tabs['entities'].table.rows.append(data)
        for sub_id in entity.subs:
            sub = g.nodes[sub_id]
            tabs['subs'].table.rows.append(
                [link(sub), sub.count, sub.description])
        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_entities_by_node(entity):
                tabs['entities'].table.rows.append([
                    link(Entity.get_by_id(row['domain_id'])),
                    link(Entity.get_by_id(row['range_id']))
                ])
    elif isinstance(entity, ReferenceSystem):
        for form_id, form in entity.get_forms().items():
            tabs[form['name']] = Tab(form['name'], entity=entity)
            tabs[form['name']].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>'
            tab_name = link_.range.class_.name
            tabs[tab_name].table.rows.append(
                [link(link_.range), name, link_.type.name])
        for form_id, form in entity.get_forms().items():
            tabs[form['name']].buttons = []
            if not tabs[form['name']].table.rows and is_authorized('manager'):
                tabs[form['name']].buttons = [
                    button(
                        _('remove'),
                        url_for('reference_system_remove_form',
                                system_id=entity.id,
                                form_id=form_id))
                ]
    elif entity.class_.view == 'actor':
        for name in [
                'source', 'event', 'relation', 'member_of', 'member',
                'artifact'
        ]:
            tabs[name] = Tab(name, entity=entity)
        event_links = entity.get_links(['P11', 'P14', 'P22', 'P23', 'P25'],
                                       True)
        for link_ in event_links:
            event = link_.domain
            places = event.get_linked_entities(['P7', 'P26', 'P27'])
            link_.object_ = None  # Needed for first/last appearance
            for place in places:
                object_ = place.get_linked_entity_safe('P53', True)
                entity.linked_places.append(object_)
                link_.object_ = object_
            first = link_.first
            if not link_.first and event.first:
                first = f'<span class="inactive">{event.first}</span>'
            last = link_.last
            if not link_.last and event.last:
                last = f'<span class="inactive">{event.last}</span>'
            data = [
                link(event), event.class_.label,
                _('moved') if link_.property.code == 'P25' else link(
                    link_.type), first, last, link_.description
            ]
            if link_.property.code == 'P25':
                data += ['']
            else:
                add_edit_link(
                    data,
                    url_for('involvement_update',
                            id_=link_.id,
                            origin_id=entity.id))
            add_remove_link(data, link_.domain.name, link_, entity, 'event')
            tabs['event'].table.rows.append(data)
        for link_ in entity.get_links('OA7') + entity.get_links('OA7', True):
            type_ = ''
            if entity.id == link_.domain.id:
                related = link_.range
                if link_.type:
                    type_ = link(link_.type.get_name_directed(),
                                 url_for('entity_view', id_=link_.type.id))
            else:
                related = link_.domain
                if link_.type:
                    type_ = link(link_.type.get_name_directed(True),
                                 url_for('entity_view', id_=link_.type.id))
            data = [
                type_,
                link(related), link_.first, link_.last, link_.description
            ]
            add_edit_link(
                data,
                url_for('relation_update', id_=link_.id, origin_id=entity.id))
            add_remove_link(data, related.name, link_, entity, 'relation')
            tabs['relation'].table.rows.append(data)
        for link_ in entity.get_links('P107', True):
            data = [
                link(link_.domain),
                link(link_.type), link_.first, link_.last, link_.description
            ]
            add_edit_link(
                data,
                url_for('member_update', id_=link_.id, origin_id=entity.id))
            add_remove_link(data, link_.domain.name, link_, entity,
                            'member-of')
            tabs['member_of'].table.rows.append(data)
        if entity.class_.name != 'group':
            del tabs['member']
        else:
            for link_ in entity.get_links('P107'):
                data = [
                    link(link_.range),
                    link(link_.type), link_.first, link_.last,
                    link_.description
                ]
                add_edit_link(
                    data,
                    url_for('member_update', id_=link_.id,
                            origin_id=entity.id))
                add_remove_link(data, link_.range.name, link_, entity,
                                'member')
                tabs['member'].table.rows.append(data)
        for link_ in entity.get_links('P52', True):
            data = [
                link(link_.domain), link_.domain.class_.label,
                link(link_.domain.standard_type), link_.domain.first,
                link_.domain.last, link_.domain.description
            ]
            tabs['artifact'].table.rows.append(data)
    elif entity.class_.view == 'artifact':
        tabs['source'] = Tab('source', entity=entity)
    elif entity.class_.view == 'event':
        for name in ['subs', 'source', 'actor']:
            tabs[name] = Tab(name, entity=entity)
        for sub_event in entity.get_linked_entities('P117',
                                                    inverse=True,
                                                    nodes=True):
            tabs['subs'].table.rows.append(get_base_table_data(sub_event))
        tabs['actor'].table.header.insert(5, _('activity'))  # Activity column
        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>'
            data = [
                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
            ]
            add_edit_link(
                data,
                url_for('involvement_update',
                        id_=link_.id,
                        origin_id=entity.id))
            add_remove_link(data, link_.range.name, link_, entity, 'actor')
            tabs['actor'].table.rows.append(data)
        entity.linked_places = [
            location.get_linked_entity_safe('P53', True)
            for location in entity.get_linked_entities(['P7', 'P26', 'P27'])
        ]
    elif entity.class_.view == 'file':
        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_)
            add_remove_link(data, 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)
            add_edit_link(
                data,
                url_for('reference_link_update',
                        link_id=link_.id,
                        origin_id=entity.id))
            add_remove_link(data, link_.domain.name, link_, entity,
                            'reference')
            tabs['reference'].table.rows.append(data)
    elif entity.class_.view == 'place':
        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['find'] = Tab('find', entity=entity)
            tabs['human_remains'] = Tab('human_remains', entity=entity)
        entity.location = entity.get_linked_entity_safe('P53', nodes=True)
        event_ids = []  # Keep track of inserted events to prevent doubles
        for event in entity.location.get_linked_entities(['P7', 'P26', 'P27'],
                                                         inverse=True):
            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))
        if 'actor' in tabs:
            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
                ])
    elif entity.class_.view == 'reference':
        for name in [
                'source', 'event', 'actor', 'place', 'feature',
                'stratigraphic_unit', 'human_remains', 'artifact', 'file'
        ]:
            tabs[name] = Tab(name, entity=entity)
        for link_ in entity.get_links('P67'):
            range_ = link_.range
            data = get_base_table_data(range_)
            data.append(link_.description)
            add_edit_link(
                data,
                url_for('reference_link_update',
                        link_id=link_.id,
                        origin_id=entity.id))
            add_remove_link(data, range_.name, link_, entity,
                            range_.class_.name)
            tabs[range_.class_.view].table.rows.append(data)
    elif entity.class_.view == 'source':
        for name in [
                'actor', 'artifact', 'feature', 'event', 'human_remains',
                'place', 'stratigraphic_unit', 'text'
        ]:
            tabs[name] = Tab(name, entity=entity)
        for text in entity.get_linked_entities('P73', nodes=True):
            tabs['text'].table.rows.append([
                link(text),
                next(iter(text.nodes)).name if text.nodes else '',
                text.description
            ])
        for link_ in entity.get_links('P67'):
            range_ = link_.range
            data = get_base_table_data(range_)
            add_remove_link(data, range_.name, link_, entity,
                            range_.class_.name)
            tabs[range_.class_.view].table.rows.append(data)

    if entity.class_.view in [
            'actor', 'artifact', 'event', 'place', 'source', 'type'
    ]:
        if entity.class_.view != 'reference' and not isinstance(entity, Node):
            tabs['reference'] = Tab('reference', entity=entity)
        if entity.class_.view == 'artifact':
            tabs['event'] = Tab('event', entity=entity)
            for link_ in entity.get_links('P25', True):
                data = get_base_table_data(link_.domain)
                tabs['event'].table.rows.append(data)
        tabs['file'] = Tab('file', entity=entity)
        entity.image_id = entity.get_profile_image_id()
        if entity.class_.view == 'place' and is_authorized('editor') and \
                current_user.settings['module_map_overlay']:
            tabs['file'].table.header.append(uc_first(_('overlay')))
        for link_ in entity.get_links('P67', inverse=True):
            domain = link_.domain
            data = get_base_table_data(domain)
            if domain.class_.view == 'file':  # pragma: no cover
                extension = data[3]
                data.append(
                    get_profile_image_table_link(domain, entity, extension,
                                                 entity.image_id))
                if not entity.image_id \
                        and extension in app.config['DISPLAY_FILE_EXTENSIONS']:
                    entity.image_id = domain.id
                if entity.class_.view == 'place' \
                        and is_authorized('editor') \
                        and current_user.settings['module_map_overlay']:
                    overlays = Overlay.get_by_object(entity)
                    if extension in app.config['DISPLAY_FILE_EXTENSIONS']:
                        if domain.id in overlays:
                            add_edit_link(
                                data,
                                url_for('overlay_update',
                                        id_=overlays[domain.id].id))
                        else:
                            data.append(
                                link(
                                    _('link'),
                                    url_for('overlay_insert',
                                            image_id=domain.id,
                                            place_id=entity.id,
                                            link_id=link_.id)))
                    else:  # pragma: no cover
                        data.append('')
            if domain.class_.view not in ['source', 'file']:
                data.append(link_.description)
                add_edit_link(
                    data,
                    url_for('reference_link_update',
                            link_id=link_.id,
                            origin_id=entity.id))
                if domain.class_.view == 'reference_system':
                    entity.reference_systems.append(link_)
                    continue
            add_remove_link(data, domain.name, link_, entity,
                            domain.class_.view)
            tabs[domain.class_.view].table.rows.append(data)

    structure = None  # Needed for place
    gis_data = None  # Needed for place
    if entity.class_.view in ['artifact', 'place']:
        structure = get_structure(entity)
        if structure:
            for item in structure['subunits']:
                tabs[item.class_.name].table.rows.append(
                    get_base_table_data(item))
        gis_data = Gis.get_all([entity], structure)
        if gis_data['gisPointSelected'] == '[]' \
                and gis_data['gisPolygonSelected'] == '[]' \
                and gis_data['gisLineSelected'] == '[]' \
                and (not structure or not structure['super_id']):
            gis_data = {}

    if not gis_data:
        gis_data = Gis.get_all(entity.linked_places) \
            if entity.linked_places else None
    entity.info_data = get_entity_data(entity, event_links=event_links)
    tabs['note'] = Tab('note', entity=entity)
    for note in current_user.get_notes_by_entity_id(entity.id):
        data = [
            format_date(note['created']),
            uc_first(_('public'))
            if note['public'] else uc_first(_('private')),
            link(User.get_by_id(note['user_id'])), note['text'],
            f'<a href="{url_for("note_view", id_=note["id"])}">'
            f'{uc_first(_("view"))}</a>'
        ]
        tabs['note'].table.rows.append(data)
    if 'file' in tabs and current_user.settings['table_show_icons'] and \
            session['settings']['image_processing']:
        tabs['file'].table.header.insert(1, uc_first(_('icon')))
        for row in tabs['file'].table.rows:
            row.insert(
                1,
                file_preview(
                    int(row[0].replace('<a href="/entity/',
                                       '').split('"')[0])))
    tabs['info'].content = render_template(
        'entity/view.html',
        buttons=add_buttons(entity),
        entity=entity,
        gis_data=gis_data,
        structure=structure,  # Needed for place views
        overlays=overlays,  # Needed for place views
        title=entity.name)
    return render_template('tabs.html',
                           tabs=tabs,
                           gis_data=gis_data,
                           crumbs=add_crumbs(entity, structure),
                           entity=entity)