Esempio n. 1
0
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)
Esempio n. 2
0
def get_disk_space_info() -> Optional[dict[str, Any]]:
    if os.name != "posix":  # pragma: no cover
        return None
    statvfs = os.statvfs(app.config['UPLOAD_DIR'])
    disk_space = statvfs.f_frsize * statvfs.f_blocks
    free_space = statvfs.f_frsize * statvfs.f_bavail
    return {
        '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))}
def export_csv():
    path = app.config['EXPORT_FOLDER_PATH'] + '/csv'
    writeable = True if os.access(path, os.W_OK) else False
    form = ExportCsvForm()
    if form.validate_on_submit() and writeable:
        Export.export_csv(form)
        logger.log('info', 'database', 'CSV export')
        flash(_('data was exported as CSV'), 'info')
        return redirect(url_for('export_csv'))
    table = {'id': 'csv', 'header': ['name', 'size'], 'data': [],
             'sort': 'sortList: [[0, 1]],headers: {0: { sorter: "text" }}'}
    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
        link = '<a href="{url}">{label}</a>'.format(url=url_for('download_csv', filename=name),
                                                    label=uc_first(_('download')))
        data = [name, convert_size(os.path.getsize(path + '/' + name)), link]
        if is_authorized('admin') and writeable:
            confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?', name=name) + '\')"'
            delete = '<a href="' + url_for('delete_csv', filename=name)
            delete += '" ' + confirm + '>' + uc_first(_('delete')) + '</a>'
            data.append(delete)
        table['data'].append(data)
    return render_template('export/export_csv.html', form=form, table=table, writeable=writeable)
Esempio n. 4
0
def export_csv() -> str:
    path = app.config['EXPORT_FOLDER_PATH'] + '/csv'
    writeable = True if os.access(path, os.W_OK) else False
    form = ExportCsvForm()
    if form.validate_on_submit() and writeable:
        Export.export_csv(form)
        logger.log('info', 'database', 'CSV export')
        flash(_('data was exported as CSV'), 'info')
        return redirect(url_for('export_csv'))
    table = Table(['name', 'size'], order='[[0, "desc"]]')
    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
        link = '<a href="{url}">{label}</a>'.format(url=url_for('download_csv',
                                                                filename=name),
                                                    label=uc_first(
                                                        _('download')))
        data = [name, convert_size(os.path.getsize(path + '/' + name)), link]
        if is_authorized('admin') and writeable:
            confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?',
                                                        name=name) + '\')"'
            delete = '<a href="' + url_for('delete_csv', filename=name)
            delete += '" ' + confirm + '>' + uc_first(_('delete')) + '</a>'
            data.append(delete)
        table.rows.append(data)
    return render_template('export/export_csv.html',
                           form=form,
                           table=table,
                           writeable=writeable)
def export_sql():
    path = app.config['EXPORT_FOLDER_PATH'] + '/sql'
    writeable = True if os.access(path, os.W_OK) else False
    form = ExportSqlForm()
    if form.validate_on_submit() and writeable:
        if Export.export_sql():
            logger.log('info', 'database', 'SQL export')
            flash(_('data was exported as SQL'), 'info')
        else:  # pragma: no cover
            logger.log('error', 'database', 'SQL export failed')
            flash(_('SQL export failed'), 'error')
        return redirect(url_for('export_sql'))
    table = {'id': 'sql', 'header': ['name', 'size'], 'data': [],
             'sort': 'sortList: [[0, 1]],headers: {0: { sorter: "text" }}'}
    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
        url = url_for('download_sql', filename=name)
        data = [name, convert_size(os.path.getsize(path + '/' + name)),
                '<a href="' + url + '">' + uc_first(_('download')) + '</a>']
        if is_authorized('admin') and writeable:
            confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?', name=name) + '\')"'
            delete = '<a href="' + url_for('delete_sql', filename=name)
            delete += '" ' + confirm + '>' + uc_first(_('delete')) + '</a>'
            data.append(delete)
        table['data'].append(data)
    return render_template('export/export_sql.html', form=form, table=table, writeable=writeable)
Esempio n. 6
0
def get_file_stats(
        path: Path = app.config['UPLOAD_DIR']) -> dict[int, dict[str, Any]]:
    stats: dict[int, dict[str, Any]] = {}
    for file_ in filter(lambda x: x.stem.isdigit(), path.iterdir()):
        stats[int(file_.stem)] = {
            'ext': file_.suffix,
            'size': convert_size(file_.stat().st_size),
            'date': file_.stat().st_ctime}
    return stats
Esempio n. 7
0
def file_index():
    table = {
        'id': 'files',
        'header': app.config['TABLE_HEADERS']['file'],
        'data': []
    }
    for file in EntityMapper.get_by_system_type('file'):
        table['data'].append(get_base_table_data(file))
    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)
Esempio n. 8
0
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)
Esempio n. 9
0
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)
Esempio n. 10
0
def get_table(type_: str, path: Path, writeable: bool) -> Table:
    table = Table(['name', 'size'], order=[[0, 'desc']])
    for file in [
            f for f in path.iterdir()
            if (path / f).is_file() and f.name != '.gitignore']:
        data = [
            file.name,
            convert_size(file.stat().st_size),
            link(
                _('download'),
                url_for(f'download_{type_}', filename=file.name))]
        if is_authorized('admin') and writeable:
            data.append(
                delete_link(
                    file.name,
                    url_for('delete_export', type_=type_, filename=file.name)))
        table.rows.append(data)
    return table
Esempio n. 11
0
def export_sql() -> str:
    path = app.config['EXPORT_FOLDER_PATH'] + '/sql'
    writeable = True if os.access(path, os.W_OK) else False
    form = ExportSqlForm()
    if form.validate_on_submit() and writeable:
        if Export.export_sql():
            logger.log('info', 'database', 'SQL export')
            flash(_('data was exported as SQL'), 'info')
        else:  # pragma: no cover
            logger.log('error', 'database', 'SQL export failed')
            flash(_('SQL export failed'), 'error')
        return redirect(url_for('export_sql'))
    table = Table(['name', 'size'], order='[[0, "desc"]]')
    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
        url = url_for('download_sql', filename=name)
        data = [
            name,
            convert_size(os.path.getsize(path + '/' + name)),
            '<a href="' + url + '">' + uc_first(_('download')) + '</a>'
        ]
        if is_authorized('admin') and writeable:
            confirm = ' onclick="return confirm(\'' + _('Delete %(name)s?',
                                                        name=name) + '\')"'
            delete = '<a href="' + url_for('delete_sql', filename=name)
            delete += '" ' + confirm + '>' + uc_first(_('delete')) + '</a>'
            data.append(delete)
        table.rows.append(data)
    return render_template('export/export_sql.html',
                           form=form,
                           table=table,
                           writeable=writeable)
Esempio n. 12
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')])
Esempio n. 13
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)