def content_reader(meta): """ Loads the reader interface """ archive = open_archive() archive.add_view(meta.md5) file_path = request.params.get('path', meta.entry_point) file_path = meta.entry_point if file_path == '/' else file_path if file_path.startswith('/'): file_path = file_path[1:] referer = request.headers.get('Referer', '') base_path = i18n_url('content:sites_list') if str(base_path) not in referer: base_path = i18n_url('content:list') return dict(meta=meta, base_path=base_path, file_path=file_path)
def reset(): reset_token = request.params.get('reset_token') form = EmergencyResetForm(request.params) if not form.is_valid(): return dict(form=form, reset_token=reset_token) request.db.auth.execute(request.db.auth.Delete('users')) request.db.sessions.execute(request.db.sessions.Delete('sessions')) username = form.processed_data['username'] User.create(username, form.processed_data['password1'], is_superuser=True, db=request.db.auth, reset_token=reset_token) return template( 'ui/feedback.tpl', # Translators, used as page title on feedback page page_title=_('Emergency reset successful'), # Translators, used as link label on feedback page in "You # will be taken to log-in page..." redirect_target=_('log-in page'), # Translators, shown after emergency reset message=_("You may now log in as " "'{username}'.").format(username=username), status='success', redirect_url=i18n_url('auth:login_form'))
def reset(): reset_token = request.params.get('reset_token') form = EmergencyResetForm(request.params) if not form.is_valid(): return dict(form=form, reset_token=reset_token) db = request.db.sessions query = db.Delete('users') db.query(query) query = db.Delete('sessions') db.query(query) username = form.processed_data['username'] create_user(username, form.processed_data['password1'], is_superuser=True, db=request.db.sessions, overwrite=True, reset_token=reset_token) return template('feedback.tpl', # Translators, used as page title on feedback page page_title=_('Emergency reset successful'), # Translators, used as link label on feedback page in "You # will be taken to log-in page..." redirect_target=_('log-in page'), # Translators, shown after emergency reset message=_("You may now log in as " "'%(username)s'.") % {'username': username}, status='success', redirect_url=i18n_url('auth:login_form'))
def perform_backup(): dbpath = get_dbpath() bpath = get_backup_path() try: btime = backup(dbpath, bpath) logging.debug('Database backup took %s seconds', btime) except AssertionError as err: # Translators, error message displayed if database backup fails base_msg = _('Database backup could not be completed. ' 'The following error occurred:') message = ' '.join(map(unicode, [base_msg, err.message])) status = 'error' url = i18n_url('dashboard:main') # Translators, redirection target if database backup was successful target = _('Dashboard') else: # Translators, message displayed if database backup was successful base_msg = _('Database backup has been completed successfully.') took_msg = lazy_ngettext('The operation took {time} second', 'The operation took {time} seconds', btime).format(time=round(btime, 2)) message = ' '.join(map(unicode, [base_msg, took_msg])) status = 'success' url = get_file_url() # Translators, redirection target if database backup was successful target = _('the backup folder') # Translators, used as page title title = _('Database backup') return dict(status=status, page_title=title, message=message, redirect_url=url, redirect_target=target)
def reset(): next_path = request.params.get('next', '/') form = PasswordResetForm(request.params) if request.user.is_authenticated: # Set arbitrary non-empty value to prevent form error. We don't really # care about this field otherwise. form.reset_token.bind_value('not needed') if not form.is_valid(): return dict(next_path=next_path, form=form) if request.user.is_authenticated: username = request.user.username else: user = User.from_reset_token(form.processed_data['reset_token']) if not user: form._error = ValidationError('invalid_token', {'value': ''}) return dict(next_path=next_path, form=form) username = user.username User.set_password(username, form.processed_data['password1']) if request.user.is_authenticated: request.user.logout() login_url = i18n_url('auth:login_form') + set_qparam( next=next_path).to_qs() return template( 'ui/feedback.tpl', # Translators, used as page title on feedback page page_title=_('New password was set'), # Translators, used as link label on feedback page in "You # will be taken to log-in page..." redirect_target=_('log-in page'), # Translators, shown after password has been changed message=_("Password for username '{username}' has been " "set.").format(username=username), status='success', redirect_url=login_url)
def content_detail(path, meta): """Update view statistics and redirect to an opener.""" archive = open_archive() archive.add_view(meta.path) # as mixed content is possible in zipballs, it is allowed to specify which # content type is being viewed now explicitly, falling back to the first # one found in the content object content_type = request.params.get('content_type') if content_type is None: # pick first available content type present in content object as it was # not specified content_type = meta.content_type_names[0] url = i18n_url('files:path', path=meta.path) openers = request.app.supervisor.exts.openers opener_id = openers.first(content_type=content_type) # if there is no opener registered for this content_type, it will just # redirect to the file manager if opener_id: # found registered opener for content_type, so use it for displaying # the content item url += set_qparam(action='open', opener_id=opener_id).to_qs() if request.is_xhr: return str(url) return redirect(url)
def perform_backup(): dbpath = get_dbpath() bpath = get_backup_path() try: btime = backup(dbpath, bpath) logging.debug('Database backup took %s seconds', btime) except AssertionError as err: # Translators, error message displayed if database backup fails base_msg = _('Database backup could not be completed. ' 'The following error occurred:') message = ' '.join(map(unicode, [base_msg, err.message])) status = 'error' url = i18n_url('dashboard:main') # Translators, redirection target if database backup was successful target = _('Dashboard') else: # Translators, message displayed if database backup was successful base_msg = _('Database backup has been completed successfully.') took_msg = lazy_ngettext('The operation took %s second', 'The operation took %s seconds', btime) % round(btime, 2) message = ' '.join(map(unicode, [base_msg, took_msg])) status = 'success' url = get_file_url() # Translators, redirection target if database backup was successful target = _('the backup folder') # Translators, used as page title title = _('Database backup') return dict(status=status, page_title=title, message=message, redirect_url=url, redirect_target=target)
def content_list(): """ Show list of content """ # parse search query query = urlunquote(request.params.get('q', '')).strip() # parse language filter default_lang = request.user.options.get('content_language', None) lang = request.params.get('language', default_lang) request.user.options['content_language'] = lang # parse content type filter content_type = request.params.get('content_type') if content_type not in metadata.CONTENT_TYPES: content_type = None # parse pagination params page = Paginator.parse_page(request.params) per_page = Paginator.parse_per_page(request.params) # get content list filtered by above parsed filter params item_count = content_count(query, lang, content_type) pager = Paginator(item_count, page, per_page) offset, limit = pager.items metas = filter_content(query, lang, content_type, offset=offset, limit=limit) return dict(metadata=metas, pager=pager, vals=request.params.decode(), query=query, chosen_lang=lang, content_types=metadata.CONTENT_TYPES, chosen_content_type=content_type, base_path=i18n_url('content:list'), view=request.params.get('view'))
def get_path(self): """ Return the full target path based on the route If you need to conditionally construct the path, or pass it additional parameters, overload this method in your subclass. """ return i18n_url(self.route, **self.route_args)
def get_folder_view_url(fsobj): """ Returns the url of the default view for specified folder. """ default_view = fsobj.dirinfo.get(request.locale, 'view', None) varg = {'view': default_view} if default_view else {} return i18n_url('files:path', path=fsobj.rel_path, **varg)
def manage_downloads(): """ Manage the downloaded content """ action_handlers = {'add': add, 'add_all': add_all, 'delete': delete, 'delete_all': delete_all} action = request.forms.get('action') file_list = request.forms.getall('selection') try: handler = action_handlers[action] except KeyError: # Translators, used as error title shown to user when wrong action # code is submitted to server title = _("Invalid action") # Translators, used as error message shown to user when wrong action # code is submitted to server message = _('Invalid action, please use one of the form buttons.') status = 'error' feedback = dict(page_title=title, message=message, redirect_url=i18n_url('downloads:list'), redirect_target=_("Updates")) else: status = 'success' feedback = handler(file_list) return dict(status=status, **feedback)
def remove_content(content_id): """ Delete a single piece of content from archive """ redir_path = i18n_url('content:list') archive = open_archive() archive.remove_from_archive([content_id]) request.app.cache.invalidate(prefix='content') redirect(redir_path)
def get_folder_view_url(fsobj): """ Returns the url of the default view for specified folder. """ default_view = fsobj.meta.get('view', request.locale) varg = {'view': default_view} if default_view else {} return i18n_url('filemanager:list', path=fsobj.rel_path, **varg)
def content_list(): """ Show list of content """ result = prepare_content_list() result.update({'base_path': i18n_url('content:list'), 'page_title': _('Library'), 'empty_message': _('Content library is currently empty')}) return result
def leagues_list(): try: q = urlunquote(request.params["q"]) except KeyError: is_search = False else: is_search = True db = request.db["football"] if is_search: item_count = football.get_leagues_count(db, dict={"name": q}) page = Paginator.parse_page(request.params) pager = pager = Paginator(item_count, page, per_page=10) leagues = football.get_leagues(db, pager, dict={"name": q}, fixtures=False, teams=False) else: item_count = football.get_leagues_count(db) page = Paginator.parse_page(request.params) pager = pager = Paginator(item_count, page, per_page=10) leagues = football.get_leagues(db, pager, fixtures=False, teams=False) return dict( leagues=leagues, pager=pager, is_search=is_search, base_path=i18n_url("leagues:list"), view=request.params.get("view"), )
def content_sites_list(): """ Show list of multipage content only """ result = prepare_content_list(multipage=True) result.update({'base_path': i18n_url('content:sites_list'), 'page_title': _('Sites'), 'empty_message': _('There are no sites in the library.')}) return result
def get(self): self.read_token_file() # If user is already logged in, redirect to password reset page # There's no need to do anything heavy-handed in this case. if self.request.user.is_authenticated: return self.redirect(i18n_url('auth:password_reset')) return super(EmergencyReset, self).get()
def reset(): next_path = request.params.get('next', '/') form = PasswordResetForm(request.params) if request.user.is_authenticated: # Set arbitrary non-empty value to prevent form error. We don't really # care about this field otherwise. form.reset_token.bind_value('not needed') if not form.is_valid(): return dict(next_path=next_path, form=form) if request.user.is_authenticated: username = request.user.username else: user = get_user_by_reset_token(form.processed_data['reset_token']) if not user: form._error = ValidationError('invalid_token', {'value': ''}) return dict(next_path=next_path, form=form) username = user.username set_password(username, form.processed_data['password1']) if request.user.is_authenticated: request.user.logout() login_url = i18n_url('auth:login_form') + set_qparam( next=next_path).to_qs() return template('feedback.tpl', # Translators, used as page title on feedback page page_title=_('New password was set'), # Translators, used as link label on feedback page in "You # will be taken to log-in page..." redirect_target=_('log-in page'), # Translators, shown after password has been changed message=_("Password for username '%(username)s' has been " "set.") % {'username': username}, status='success', redirect_url=login_url)
def languages_save(): (form, region, region_languages) = validate_region() # languages were chosen for the selected region selected_languages = map(urlunquote, request.forms.getall('language')) has_invalid = any(lang not in region_languages for lang in selected_languages) if not selected_languages or has_invalid: # some of the chosen languages were invalid or no languages were chosen return dict(form=form, region=region, region_languages=region_languages, selected_languages=selected_languages, # Translators, message displayed as help text for # language selection message=_("Please select languages from the list below.")) # languages are valid, store them in setup file and inform other about it exts.setup.append({'contentfilter.region': region, 'contentfilter.languages': selected_languages}) set_fsal_whitelist(request.app.config) return dict(form=form, region=region, region_languages=region_languages, selected_languages=selected_languages, message=_("Content filter has been set."), redirect_url=i18n_url('dashboard:main'))
def plugin(supervisor): setup_path = i18n_url('setup:main') ignored_paths = [setup_path, i18n_url('setup:diag')] def plugin(callback): @functools.wraps(callback) def wrapper(*args, **kwargs): if (not supervisor.exts.setup_wizard.is_completed and not any([request.path == path[len(request.locale) + 1:] for path in ignored_paths])): if request.is_xhr: return template(NO_XHR_TEMPLATE) return redirect(setup_path) return callback(*args, **kwargs) return wrapper plugin.name = 'setup' return plugin
def remove_content(content_id): """ Delete a single piece of content from archive """ redir_path = i18n_url('content:list') archive = open_archive() failed = archive.remove_from_archive([content_id]) if failed: assert len(failed) == 1, 'Expected only one failure' return dict(redirect=redir_path) redirect(redir_path)
def get_view_path(fsobj): """ Return a view URL with specified file preselected. """ ext = fsobj.rel_path.rsplit('.', 1)[-1].lower() view = EXTENSION_VIEW_MAPPING.get(ext) if not view: return quoted_url('files:direct', path=fsobj.rel_path) parent = os.path.dirname(fsobj.rel_path) or '.' return i18n_url('files:path', path=parent, view=view, selected=fsobj.name)
def perform_rebuild(): try: rtime = rebuild() except Exception: logging.debug('DBMANAGE: Global lock could not be acquired') # Translators, error message displayed if database rebuild fails base_msg = _('Database could not be rebuilt. ' 'The following error occurred:') # Translators, error message displayed when locking fails during # database rebuild reason = _('Librarian could not enter maintenance mode and ' 'database rebuild was cancelled. Please make ' 'sure noone else is using Librarian and ' 'try again.') message = ' '.join(map(unicode, [base_msg, reason])) status = 'error' url = i18n_url('dashboard:main') # Translators, redirection target if database backup was successful target = _('Dashboard') else: # Translators, message displayed if database backup was successful base_msg = _('Content database has been rebuilt from scratch. A backup' ' copy of the original database has been created. ' 'You will find it in the files section.') # Translators, message displayed if database backup was successful took_msg = lazy_ngettext('The operation took %s second', 'The operation took %s seconds', rtime) % round(rtime, 2) message = ' '.join(map(unicode, [base_msg, took_msg])) # Translators, message displayed if database backup was successful status = 'success' url = i18n_url('content:list') # Translators, redirection target if database backup was successful target = _('Library') # Translators, used as page title title = _('Database rebuild') return dict(status=status, page_title=title, message=message, redirect_url=url, redirect_target=target)
def perform_rebuild(): try: rtime = rebuild() except LockFailureError: logging.debug('DBMANAGE: Global lock could not be acquired') # Translators, error message displayed if database rebuild fails base_msg = _('Database could not be rebuilt. ' 'The following error occurred:') # Translators, error message displayed when locking fails during # database rebuild reason = _('Librarian could not enter maintenance mode and ' 'database rebuild was cancelled. Please make ' 'sure noone else is using Librarian and ' 'try again.') message = ' '.join(map(unicode, [base_msg, reason])) status = 'error' url = i18n_url('dashboard:main') # Translators, redirection target if database backup was successful target = _('Dashboard') else: # Translators, message displayed if database backup was successful base_msg = _('Content database has been rebuilt from scratch. A backup' ' copy of the original database has been created. ' 'You will find it in the files section.') # Translators, message displayed if database backup was successful took_msg = lazy_ngettext('The operation took {time} second', 'The operation took {time} seconds', rtime).format(time=round(rtime, 2)) message = ' '.join(map(unicode, [base_msg, took_msg])) # Translators, message displayed if database backup was successful status = 'success' url = i18n_url(request.app.config['app.default_route']) # Translators, redirection target if database backup was successful target = _('Library') # Translators, used as page title title = _('Database rebuild') return dict(status=status, page_title=title, message=message, redirect_url=url, redirect_target=target)
def set_settings(): form = ONDDForm(request.forms) if not form.is_valid(): return dict(form=form) logging.info('ONDD: tuner settings updated') request.app.setup.append({'ondd': form.processed_data}) return dict(form=form, message=_('Transponder configuration saved.'), redirect_url=i18n_url('dashboard:main'))
def tag_cloud(): # base_path is used to construct a link to content list or sites page # filtered by tag (see _tag_list.tpl). base_path = request.params.get('base_path', i18n_url('content:list')) try: current = request.params.get('tag') except (ValueError, TypeError): current = None archive = open_archive() tags = archive.get_tag_cloud() return dict(tag_cloud=tags, tag=current, base_path=base_path)
def root_handler(): route = request.app.config['app.default_route'] if hasattr(request, 'default_route'): route = request.default_route if is_i18n_enabled(): url = i18n_url(route) else: url = request.app.get_url(route) redirect(url)
def show_file_list(path='.'): search = request.params.get('p') resp_format = request.params.get('f', '') conf = request.app.config is_missing = False is_search = False files = init_filemanager() if search: relpath = '.' up = '' dirs, file_list = files.get_search_results(search) is_search = True if not len(file_list) and len(dirs) == 1: redirect(i18n_url('files:path', path=dirs[0].path.replace('\\', '/'))) if not dirs and not file_list: is_missing = True readme = _('The files you were looking for could not be found') else: readme = _('This list represents the search results') else: is_search = False try: dir_contents = files.get_dir_contents(path) (path, relpath, dirs, file_list, readme) = dir_contents except files.DoesNotExist: is_missing = True relpath = '.' dirs = [] file_list = [] readme = _('This folder does not exist') except files.IsFileError as err: if resp_format == 'json': fstat = os.stat(path) response.content_type = 'application/json' return json.dumps(dict( name=os.path.basename(path), size=fstat[stat.ST_SIZE], )) options = {'download': request.params.get('filename', False)} return static_file(err.path, root=files.filedir, **options) up = os.path.normpath(os.path.join(path, '..')) up = os.path.relpath(up, conf['content.filedir']) if resp_format == 'json': response.content_type = 'application/json' return json.dumps(dict( dirs=dirs, files=dictify_file_list(file_list), readme=to_unicode(readme), is_missing=is_missing, is_search=is_search, )) return dict(path=relpath, dirs=dirs, files=file_list, up=up, readme=readme, is_missing=is_missing, is_search=is_search)
def root_handler(): route = request.app.config["app.default_route"] if hasattr(request, "default_route"): route = request.default_route if is_i18n_enabled(): url = i18n_url(route) else: url = request.app.get_url(route) redirect(url)
def setup_plugin(fn): """ On incoming requests, check if the setup process has been already completed and in case it wasn't, redirect to the setup wizard. Exclusions to this rule are paths belonging to the setup wizard itself and static paths. """ setup_path = i18n_url('setup:enter') excluded_paths = [setup_path, i18n_url('setup:diag')] is_excluded = lambda: any(request.path == path[len(request.locale) + 1:] for path in excluded_paths) @functools.wraps(fn) def wrapper(*args, **kwargs): if exts.setup_wizard.is_completed or is_excluded(): return fn(*args, **kwargs) if request.is_xhr: return template(NO_XHR_TEMPLATE) redirect(setup_path) return wrapper
def get(self): route = self.config['app.default_route'] route_args = self.config.get('app.default_route_args', []) route_args = dict(arg.split(':') for arg in route_args) if hasattr(self.request, 'default_route'): route = self.request.default_route if is_i18n_enabled(): url = i18n_url(route, **route_args) else: url = self.request.app.get_url(route, *route_args) self.redirect(url)
def perform_rebuild(): try: rtime = rebuild() except LockFailureError: logging.debug('DBMANAGE: Global lock could not be acquired') # Translators, error message displayed when locking fails during # database rebuild return dict(error=_('Librarian could not enter maintenance mode and ' 'database rebuild was cancelled. Please make ' 'sure noone else is using Librarian and ' 'try again.')) return dict(redirect=i18n_url('content:list'), time=rtime, fpath=get_file_url())
def get_view_path(fsobj): """ Return a view URL with specified file preselected. """ ext = fsobj.rel_path.rsplit('.', 1)[-1].lower() view = EXTENSION_VIEW_MAPPING.get(ext) if not view: return quoted_url('filemanager:direct', path=fsobj.rel_path) parent = os.path.dirname(fsobj.rel_path) or '.' return i18n_url('filemanager:list', path=parent, view=view, selected=fsobj.name)
def save_settings(): settings = request.app.supervisor.exts.settings form_cls = settings.get_form() form = form_cls(request.forms) if not form.is_valid(): return dict(form=form, groups=settings.groups) request.app.supervisor.exts.setup.append(form.processed_data) request.app.supervisor.exts.events.publish('SETTINGS_SAVED', form.processed_data) return dict(form=form, groups=settings.groups, message=_('Settings saved.'), redirect_url=i18n_url('dashboard:main'))
def remove_content(content): """ Delete a single piece of content from archive """ archive = open_archive() archive.remove_from_archive([content.md5]) request.app.exts.cache.invalidate(prefix='content') # Translators, used as page title of successful content removal feedback page_title = _("Content removed") # Translators, used as message of successful content removal feedback message = _("Content successfully removed.") return dict(status='success', page_title=page_title, message=message, redirect_url=i18n_url('content:list'), redirect_target=_("Library"))
def delete(file_list): spooldir = request.app.config['content.spooldir'] removed_count = downloads.remove_downloads(spooldir, content_ids=file_list) # Translators, used as confirmation title after the chosen updates were # deleted on the updates page title = _("Updates deleted") # Translators, used as confirmation message after the chosen updates were # deleted on the updates page message = lazy_ngettext("An update has been deleted.", "{update_count} updates have been deleted.", removed_count).format(update_count=removed_count) return dict(page_title=title, message=message, redirect_url=i18n_url('downloads:list'), redirect_target=_("Updates"))
def image_opener(path, meta): if not meta: return image(path, meta=None) kwargs = dict(content_url=i18n_url('files:path', path=meta.path), img_count=len(meta['image']['album'])) try: img_index = int(request.params.get('index', None)) except Exception: # no image index can be found or parsed, so show the whole album return album(path, meta, **kwargs) else: path = os.path.join(meta.path, meta['image']['album'][img_index]['file']) return image(path, meta, img_index=img_index, **kwargs)
def form_valid(self): self.clear_auth_databases() username = self.form.processed_data['username'] password = self.form.processed_data['password1'] self.recreate_user(username, password) body = template('ui/feedback.tpl', # Translators, used as page title on feedback page page_title=_('Emergency reset successful'), # Translators, used as link label on feedback page in # "You will be taken to log-in page..." redirect_target=_('log-in page'), # Translators, shown after emergency reset message=_("You may now log in as " "'{username}'.").format(username=username), status='success', redirect_url=i18n_url('auth:login')) return self.HTTPResponse(body=body)
def form_valid(self): username = self.form.processed_data['username'] User.set_password(username, self.form.processed_data['password1']) if self.request.user.is_authenticated: self.request.user.logout() login_url = self.add_next_parameter(i18n_url('auth:login')) body = template('ui/feedback.tpl', # Translators, used as page title on feedback page page_title=_('New password was set'), # Translators, used as link label on feedback page in # "You will be taken to log-in page..." redirect_target=_('log-in page'), # Translators, shown after password has been changed message=_("Password for username '{username}' has " "been set.").format(username=username), status='success', redirect_url=login_url) return self.HTTPResponse(body=body)
def form_valid(self): dest = self.form.processed_data['dest'] self.schedule_task() # Translators, message shown when the file moving operation is # successfully scheduled message = _('Files are now being moved to {destination}. You ' 'will be notified when the operation is ' 'finished.').format(destination=dest.humanized_name) if self.request.is_xhr: return dict(message=message) # Translators, used as page title when the file moving operation # is successfully started page_title = _("File consolidation scheduled") body = self.template_func('ui/feedback', status='success', page_title=page_title, message=message, redirect_url=i18n_url('dashboard:main'), redirect_target=_("settings")) return self.HTTPResponse(body=body)
def show_emergency_reset_form(): config = request.app.config token_path = config.get('emergency.file', '') if not os.path.isfile(token_path): # Not configured or missing emergency reset token file abort(404) with open(token_path, 'r') as f: token = f.read() if not token.strip(): # Token file is empty, so treat it as missing token file abort(404) # If user is already logged in, redirect to password reset page instead. # Thre's no need to do anything heavy-handed in this case. if request.user.is_authenticated: return redirect(i18n_url('auth:reset_form')) return dict(form=EmergencyResetForm(), reset_token=User.generate_reset_token())
def url(*args, **kw): return i18n_url(*args, **kw)
def form_valid(self): commands = self.config['wireless.restart_commands'] exts.tasks.schedule(restart_services, args=(commands, ), delay=5) return dict(message=_('Network settings have been saved. The device' ' is going to reboot now.'), redirect_url=i18n_url('dashboard:main'))
def get_path(self): return i18n_url(self.route) + '?next=' + request.fullpath
def get_parent_url(path, view=None): parent_path = get_parent_path(path) vargs = {'view': view} if view else {} return i18n_url('files:path', path=parent_path, **vargs)
def form_valid(self): logging.info('ONDD: tuner settings updated') return dict(form=self.form, message=_('Transponder configuration saved.'), redirect_url=i18n_url('dashboard:main'))
def form_valid(self): exts.setup.append(self.form.processed_data) exts.events.publish('SETTINGS_SAVED', self.form.processed_data) return dict(message=_('Settings saved.'), redirect_url=i18n_url('dashboard:main'))
def get_file_url(): suburl = request.app.config['dbmanage.backupdir'].replace('\\', '/') return i18n_url('files:path', path=suburl)
def get_parent_url(path): parent_path = os.path.dirname(path) return i18n_url('filemanager:list', path=parent_path)