def edit_dictionaries(dictionaries: 'Sequence[Tuple[str, Union[Transform, Dictionary]]]', value: Dict[str, Any], focus: Optional[str] = None, hover_help: bool = True, validate: Optional[Callable[[Any], None]] = None, title: Optional[str] = None, method: str = "GET", preview: bool = False, varprefix: str = "", formname: str = "form", consume_transid: bool = True): if request.get_ascii_input("filled_in") == formname and transactions.transaction_valid(): if not preview and consume_transid: transactions.check_transaction() messages: List[str] = [] new_value: Dict[str, Dict[str, Any]] = {} for keyname, vs_dict in dictionaries: dict_varprefix = varprefix + keyname new_value[keyname] = {} try: edited_value = vs_dict.from_html_vars(dict_varprefix) vs_dict.validate_value(edited_value, dict_varprefix) new_value[keyname].update(edited_value) except MKUserError as e: messages.append("%s: %s" % (vs_dict.title() or _("Properties"), e)) user_errors.add(e) except Exception as e: messages.append("%s: %s" % (vs_dict.title() or _("Properties"), e)) user_errors.add(MKUserError(None, str(e))) if validate and not user_errors: try: validate(new_value[keyname]) except MKUserError as e: messages.append(str(e)) user_errors.add(e) if messages: messages_joined = "".join(["%s<br>\n" % m for m in messages]) if not preview: html.show_error(messages_joined) else: raise MKUserError(None, messages_joined) else: return new_value html.begin_form(formname, method=method) for keyname, vs_dict in dictionaries: dict_varprefix = varprefix + keyname subvalue = value.get(keyname, {}) vs_dict.render_input_as_form(dict_varprefix, subvalue) end() # Should be ignored be hidden_fields, but I do not dare to change it there request.del_var("filled_in") html.hidden_fields() html.end_form()
def action(self) -> ActionResult: varname = request.var("_varname") if not varname: return None action = request.var("_action") config_variable = config_variable_registry[varname]() def_value = self._default_values[varname] if not transactions.check_transaction(): return None if varname in self._current_settings: self._current_settings[ varname] = not self._current_settings[varname] else: self._current_settings[varname] = not def_value msg = _("Changed Configuration variable %s to %s.") % ( varname, "on" if self._current_settings[varname] else "off", ) watolib.save_global_settings(self._current_settings) watolib.add_change( "edit-configvar", msg, domains=[config_variable.domain()], need_restart=config_variable.need_restart(), ) if action == "_reset": flash(msg) return redirect(mode_url("globalvars"))
def action(self) -> ActionResult: if not transactions.check_transaction(): return None test_id = request.var("_test_id") site_id = request.var("_site_id") status_id = request.get_integer_input_mandatory("_status_id", 0) if not test_id: raise MKUserError("_ack_test_id", _("Needed variable missing")) if request.var("_do") in ["ack", "unack"]: if not site_id: raise MKUserError("_ack_site_id", _("Needed variable missing")) if site_id not in activation_sites(): raise MKUserError("_ack_site_id", _("Invalid site given")) if request.var("_do") == "ack": self._acknowledge_test(test_id, site_id, status_id) elif request.var("_do") == "unack": self._unacknowledge_test(test_id, site_id, status_id) elif request.var("_do") == "disable": self._disable_test(test_id) elif request.var("_do") == "enable": self._enable_test(test_id) else: raise NotImplementedError() return None
def action(self) -> ActionResult: if request.var("_reset"): if not transactions.check_transaction(): return None try: del self._current_settings[self._varname] except KeyError: pass msg = escape_html_permissive( _("Resetted configuration variable %s to its default.") % self._varname) else: new_value = self._valuespec.from_html_vars("ve") self._valuespec.validate_value(new_value, "ve") self._current_settings[self._varname] = new_value msg = HTML( _("Changed global configuration variable %s to %s.") % ( escaping.escape_attribute(self._varname), self._valuespec.value_to_html(new_value), )) self._save() watolib.add_change( "edit-configvar", msg, sites=self._affected_sites(), domains=[self._config_variable.domain()], need_restart=self._config_variable.need_restart(), ) return redirect(self._back_url())
def action(self) -> ActionResult: if transactions.check_transaction(): value = self._vs_key().from_html_vars("key") request.del_var("key_p_passphrase") self._vs_key().validate_value(value, "key") key_file = self._get_uploaded(value, "key_file") if not key_file: raise MKUserError(None, _("You need to provide a key file.")) if (not key_file.startswith( "-----BEGIN ENCRYPTED PRIVATE KEY-----\n") or "-----END ENCRYPTED PRIVATE KEY-----\n" not in key_file or "-----BEGIN CERTIFICATE-----\n" not in key_file or not key_file.endswith("-----END CERTIFICATE-----\n")): raise MKUserError( None, _("The file does not look like a valid key file.")) self._upload_key(key_file, value) # FIXME: This leads to a circular import otherwise. This module (cmk.gui.key_mgmt) is # clearly outside of either cmk.gui.plugins.wato and cmk.gui.cee.plugins.wato so this # is obviously a very simple module-layer violation. This whole module should either # * be moved into cmk.gui.cee.plugins.wato # * or cmk.gui.cee.plugins.wato.module_registry should be moved up # Either way, this is outside my scope right now and shall be fixed. from cmk.gui.plugins.wato.utils.base_modes import mode_url return HTTPRedirect(mode_url(self.back_mode), code=302) return None
def action(self) -> ActionResult: if html.request.var("_reset"): if not transactions.check_transaction(): return None try: del self._current_settings[self._varname] except KeyError: pass msg: Union[ HTML, str] = _("Resetted configuration variable %s to its default." ) % self._varname else: new_value = self._valuespec.from_html_vars("ve") self._valuespec.validate_value(new_value, "ve") self._current_settings[self._varname] = new_value msg = _("Changed global configuration variable %s to %s.") \ % (self._varname, self._valuespec.value_to_text(new_value)) # FIXME: THIS HTML(...) is needed because we do not know what we get from value_to_text!! msg = HTML(msg) self._save() watolib.add_change("edit-configvar", msg, sites=self._affected_sites(), domains=[self._config_variable.domain()], need_restart=self._config_variable.need_restart()) return redirect(self._back_url())
def action(self) -> ActionResult: if not transactions.check_transaction(): return None vs = self._valuespec() self._connection_cfg = vs.from_html_vars("connection") vs.validate_value(self._connection_cfg, "connection") self._connection_cfg["type"] = "ldap" if self._new: self._connections.insert(0, self._connection_cfg) self._connection_id = self._connection_cfg["id"] else: self._connection_cfg["id"] = self._connection_id self._connections[self._connection_nr] = self._connection_cfg assert self._connection_id is not None if self._new: log_what = "new-ldap-connection" log_text = _("Created new LDAP connection") else: log_what = "edit-ldap-connection" log_text = _("Changed LDAP connection %s") % self._connection_id self._add_change(log_what, log_text) save_connection_config(self._connections) config.user_connections = self._connections # make directly available on current page if html.request.var("_save"): return redirect(mode_url("ldap_config")) # Handle the case where a user hit "Save & Test" during creation return redirect(self.mode_url(_test="1", id=self._connection_id))
def action(self) -> ActionResult: if transactions.check_transaction(): keys = self.load() try: key_id_str = request.var("key") if key_id_str is None: raise Exception( "cannot happen") # is this really the case? key_id = int(key_id_str) except ValueError: raise MKUserError(None, _("You need to provide a valid key id.")) if key_id not in keys: raise MKUserError(None, _("You need to provide a valid key id.")) private_key = keys[key_id]["private_key"] value = self._vs_key().from_html_vars("key") self._vs_key().validate_value(value, "key") decrypt_private_key(private_key, value["passphrase"]) self._send_download(keys, key_id) return FinalizeRequest(code=200) return None
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("tags")) vs = self._valuespec() aux_tag_spec = vs.from_html_vars("aux_tag") vs.validate_value(aux_tag_spec, "aux_tag") self._aux_tag = cmk.utils.tags.AuxTag(aux_tag_spec) self._aux_tag.validate() changed_hosttags_config = cmk.utils.tags.TagConfig() changed_hosttags_config.parse_config(self._tag_config_file.load_for_reading()) if self._new: changed_hosttags_config.aux_tag_list.append(self._aux_tag) else: changed_hosttags_config.aux_tag_list.update(self._id, self._aux_tag) try: changed_hosttags_config.validate_config() except MKGeneralException as e: raise MKUserError(None, "%s" % e) self._tag_config_file.save(changed_hosttags_config.get_dict_format()) return redirect(mode_url("tags"))
def page_notify(): if not user.may("general.notify"): raise MKAuthException(_("You are not allowed to use the notification module.")) title = _("Notify users") breadcrumb = make_simple_page_breadcrumb(mega_menu_registry.menu_setup(), title) menu = _page_menu(breadcrumb) html.header(title, breadcrumb, menu) vs_notify = _vs_notify() if transactions.check_transaction(): try: msg = vs_notify.from_html_vars("_notify") vs_notify.validate_value(msg, "_notify") _process_notify_message(msg) except MKUserError as e: html.user_error(e) html.begin_form("notify", method="POST") vs_notify.render_input_as_form("_notify", {}) html.hidden_fields() html.end_form() html.footer()
def action(self) -> ActionResult: delname = request.var("_delete") if not delname: return redirect(mode_url("timeperiods")) if not transactions.check_transaction(): return redirect(mode_url("timeperiods")) if delname in watolib.timeperiods.builtin_timeperiods(): raise MKUserError("_delete", _("Builtin timeperiods can not be modified")) usages = self._find_usages_of_timeperiod(delname) if usages: message = "<b>%s</b><br>%s:<ul>" % \ (_("You cannot delete this timeperiod."), _("It is still in use by")) for title, link in usages: message += '<li><a href="%s">%s</a></li>\n' % (link, title) message += "</ul>" raise MKUserError(None, message) del self._timeperiods[delname] watolib.timeperiods.save_timeperiods(self._timeperiods) watolib.add_change("edit-timeperiods", _("Deleted timeperiod %s") % delname) return redirect(mode_url("timeperiods"))
def action(self) -> ActionResult: try: transactions.check_transaction() user.save_file("parentscan", dict(self._settings._asdict())) self._job.set_function(self._job.do_execute, self._settings, self._get_tasks()) self._job.start() except Exception as e: if config.debug: raise logger.exception("Failed to start parent scan") raise MKUserError( None, _("Failed to start parent scan: %s") % ("%s" % e).replace("\n", "\n<br>") ) raise HTTPRedirect(self._job.detail_url())
def handle_acknowledgement(): if not transactions.check_transaction(): return if request.var("_werk_ack"): werk_id = request.get_integer_input_mandatory("_werk_ack") if werk_id not in g_werks: raise MKUserError("werk", _("This werk does not exist.")) werk = g_werks[werk_id] if werk["compatible"] == "incomp_unack": acknowledge_werk(werk) html.show_message( _("Werk %s - %s has been acknowledged.") % (render_werk_id(werk, with_link=True), render_werk_title(werk)) ) load_werks() # reload ack states after modification render_unacknowleged_werks() elif request.var("_ack_all"): num = len(unacknowledged_incompatible_werks()) acknowledge_all_werks() flash(_("%d incompatible Werks have been acknowledged.") % num) load_werks() # reload ack states after modification html.reload_whole_page()
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(self.mode_url()) connections = load_connection_config(lock=True) if html.request.has_var("_delete"): index = html.request.get_integer_input_mandatory("_delete") connection = connections[index] self._add_change( "delete-ldap-connection", _("Deleted LDAP connection %s") % (connection["id"])) del connections[index] save_connection_config(connections) elif html.request.has_var("_move"): from_pos = html.request.get_integer_input_mandatory("_move") to_pos = html.request.get_integer_input_mandatory("_index") connection = connections[from_pos] self._add_change( "move-ldap-connection", _("Changed position of LDAP connection %s to %d") % (connection["id"], to_pos)) del connections[from_pos] # make to_pos now match! connections[to_pos:to_pos] = [connection] save_connection_config(connections) return redirect(self.mode_url())
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("tags")) vs = self._valuespec() tag_group_spec = vs.from_html_vars("tag_group") vs.validate_value(tag_group_spec, "tag_group") # Create new object with existing host tags changed_hosttags_config = cmk.utils.tags.TagConfig() changed_hosttags_config.parse_config( self._tag_config_file.load_for_modification()) changed_tag_group = cmk.utils.tags.TagGroup(tag_group_spec) self._tag_group = changed_tag_group if self._new: # Inserts and verifies changed tag group changed_hosttags_config.insert_tag_group(changed_tag_group) try: changed_hosttags_config.validate_config() except MKGeneralException as e: raise MKUserError(None, "%s" % e) self._save_tags_and_update_hosts( changed_hosttags_config.get_dict_format()) add_change( "edit-hosttags", _("Created new host tag group '%s'") % changed_tag_group.id) flash( _("Created new host tag group '%s'") % changed_tag_group.title) return redirect(mode_url("tags")) # Updates and verifies changed tag group changed_hosttags_config.update_tag_group(changed_tag_group) try: changed_hosttags_config.validate_config() except MKGeneralException as e: raise MKUserError(None, "%s" % e) remove_tag_ids, replace_tag_ids = identify_modified_tags( changed_tag_group, self._untainted_tag_group) tg_id = self._tag_group.id if tg_id is None: raise Exception("tag group ID not set") operation = OperationReplaceGroupedTags(tg_id, remove_tag_ids, replace_tag_ids) # Now check, if any folders, hosts or rules are affected message = _rename_tags_after_confirmation(self.breadcrumb(), operation) if message is False: return FinalizeRequest(code=200) self._save_tags_and_update_hosts( changed_hosttags_config.get_dict_format()) add_change("edit-hosttags", _("Edited host tag group %s (%s)") % (message, self._id)) if isinstance(message, str): flash(message) return redirect(mode_url("tags"))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("folder", folder=watolib.Folder.current().path())) count = request.get_integer_input_mandatory("count") folders = request.get_integer_input_mandatory("folders") levels = request.get_integer_input_mandatory("levels") created = self._create_random_hosts(watolib.Folder.current(), count, folders, levels) flash(_("Added %d random hosts.") % created) return redirect(mode_url("folder", folder=watolib.Folder.current().path()))
def confirm_with_preview(msg: Union[str, HTML], confirm_options: List[Tuple[str, str]], method: str = "POST") -> Optional[bool]: """Show a confirm dialog to the user BE AWARE: In case you just want to have some action confirmed by the user, you should use the javascript powere confirm dialg (make_confirm, add_confirm_on_submit, ...). This method is used only in places where we explicitly need to show important information to the user before he can decide whether or not to confirm the action. The confirm dialog is normally not a dialog which need to be protected by a transid itselfs. It is only a intermediate step to the real action But there are use cases where the confirm dialog is used during rendering a normal page, for example when deleting a dashlet from a dashboard. In such cases, the transid must be added by the confirm dialog. """ if html.request.var("_do_actions") == _("Cancel"): # User has pressed "Cancel", now invalidate the unused transid transactions.check_transaction() return None # None --> "Cancel" if not any( html.request.has_var(varname) for _title, varname in confirm_options): mobile = is_mobile(request, response) if mobile: html.open_center() html.open_div(class_="really") html.write_text(msg) html.begin_form("confirm", method=method, add_transid=False) html.hidden_fields(add_action_vars=True) for title, varname in confirm_options: html.button(varname, title, "really") html.button("_do_actions", _("Cancel")) html.end_form() html.close_div() if mobile: html.close_center() return False # False --> "Dialog shown, no answer yet" # Now check the transaction. True: "Yes", None --> Browser reload of "yes" page return True if transactions.check_transaction() else None
def action(self) -> ActionResult: if request.var("_action") != "discard": return None if not transactions.check_transaction(): return None if not self._may_discard_changes(): return None if not self.has_changes(): return None # Now remove all currently pending changes by simply restoring the last automatically # taken snapshot. Then activate the configuration. This should revert all pending changes. file_to_restore = self._get_last_wato_snapshot_file() if not file_to_restore: raise MKUserError(None, _("There is no WATO snapshot to be restored.")) msg = _("Discarded pending changes (Restored %s)") % file_to_restore # All sites and domains can be affected by a restore: Better restart everything. watolib.add_change( "changes-discarded", msg, domains=watolib.ABCConfigDomain.enabled_domains(), need_restart=True, ) self._extract_snapshot(file_to_restore) activate_changes.execute_activate_changes([ d.get_domain_request([]) for d in watolib.ABCConfigDomain.enabled_domains() ]) for site_id in activation_sites(): self.confirm_site_changes(site_id) build_index_background() html.header( self.title(), breadcrumb=self.breadcrumb(), show_body_start=display_options.enabled(display_options.H), show_top_heading=display_options.enabled(display_options.T), ) html.open_div(class_="wato") html.show_message(_("Successfully discarded all pending changes.")) html.javascript("hide_changes_buttons();") html.footer() return FinalizeRequest(code=200)
def action(self) -> ActionResult: if transactions.check_transaction(): value = self._vs_key().from_html_vars("key") # Remove the secret key from known URL vars. Otherwise later constructed URLs # which use the current page context will contain the passphrase which could # leak the secret information request.del_var("key_p_passphrase") self._vs_key().validate_value(value, "key") self._create_key(value) return redirect(mode_url(self.back_mode)) return None
def action(self) -> ActionResult: user.need_permission("wato.services") tasks = get_tasks(self._get_hosts_to_discover(), self._bulk_size) try: transactions.check_transaction() self._job.set_function( self._job.do_execute, self._mode, self._do_scan, self._error_handling, tasks ) self._job.start() except Exception as e: if config.debug: raise logger.exception("Failed to start bulk discovery") raise MKUserError( None, _("Failed to start discovery: %s") % ("%s" % e).replace("\n", "\n<br>") ) raise HTTPRedirect(self._job.detail_url())
def action(self) -> ActionResult: if not transactions.check_transaction(): return None if self._job.is_active() or self._diagnostics_parameters is None: return redirect(self._job.detail_url()) self._job.set_function(self._job.do_execute, self._diagnostics_parameters) self._job.start() return redirect(self._job.detail_url())
def action(self) -> ActionResult: if not transactions.check_transaction(): return None vs_ical = self._vs_ical() ical = vs_ical.from_html_vars("ical") vs_ical.validate_value(ical, "ical") filename, _ty, content = ical['file'] try: # TODO(ml): If we could open the file in text mode, we would not # need to `decode()` here. data = self._parse_ical(content.decode("utf-8"), ical['horizon']) except Exception as e: if config.debug: raise raise MKUserError('ical_file', _('Failed to parse file: %s') % e) get_vars = { 'timeperiod_p_alias': data.get('descr', data.get('name', filename)), } for day in defines.weekday_ids(): get_vars['%s_0_from' % day] = '' get_vars['%s_0_until' % day] = '' # Default to whole day if not ical["times"]: ical["times"] = [((0, 0), (24, 0))] get_vars['timeperiod_p_exceptions_count'] = "%d" % len(data['events']) for index, event in enumerate(data['events']): index += 1 get_vars['timeperiod_p_exceptions_%d_0' % index] = event['date'] get_vars['timeperiod_p_exceptions_indexof_%d' % index] = "%d" % index get_vars['timeperiod_p_exceptions_%d_1_count' % index] = "%d" % len(ical["times"]) for n, time_spec in enumerate(ical["times"]): n += 1 start_time = ":".join("%02d" % x for x in time_spec[0]) end_time = ":".join("%02d" % x for x in time_spec[1]) get_vars['timeperiod_p_exceptions_%d_1_%d_from' % (index, n)] = start_time get_vars['timeperiod_p_exceptions_%d_1_%d_until' % (index, n)] = end_time get_vars['timeperiod_p_exceptions_%d_1_indexof_%d' % (index, n)] = "%d" % index return redirect(mode_url("edit_timeperiod", **get_vars))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("tags")) if request.has_var("_delete"): return self._delete_tag_group() if request.has_var("_del_aux"): return self._delete_aux_tag() if request.var("_move"): return self._move_tag_group() return redirect(mode_url("tags"))
def action(self) -> ActionResult: if not transactions.transaction_valid(): return redirect(mode_url("folder")) attributes = watolib.collect_attributes(self._host_type_name(), new=True) cluster_nodes = self._get_cluster_nodes() hostname = request.get_ascii_input_mandatory("host") Hostname().validate_value(hostname, "host") folder = watolib.Folder.current() if transactions.check_transaction(): folder.create_hosts([(hostname, attributes, cluster_nodes)]) self._host = folder.load_host(hostname) inventory_url = watolib.folder_preserving_link( [ ("mode", "inventory"), ("host", self._host.name()), ("_scan", "1"), ] ) create_msg = ( None if self._host.is_ping_host() else ( _( "Successfully created the host. Now you should do a " '<a href="%s">service discovery</a> in order to auto-configure ' "all services to be checked on this host." ) % inventory_url ) ) if request.var("_save"): return redirect(inventory_url) if create_msg: flash(create_msg) if request.var("diag_host"): return redirect( mode_url("diag_host", folder=folder.path(), host=self._host.name(), _try="1") ) return redirect(mode_url("folder", folder=folder.path()))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(mode_url("%s_groups" % self.type_name)) alias = request.get_unicode_input_mandatory("alias").strip() self.group = {"alias": alias} self._determine_additional_group_data() if self._new: self._name = request.get_ascii_input_mandatory("name").strip() watolib.add_group(self._name, self.type_name, self.group) else: watolib.edit_group(self._name, self.type_name, self.group) return redirect(mode_url("%s_groups" % self.type_name))
def action(self) -> ActionResult: if not transactions.check_transaction(): return redirect(self.mode_url()) if not request.var("_delete"): return redirect(self.mode_url()) delname = request.var("_delete") for index, attr in enumerate(self._attrs): if attr["name"] == delname: self._attrs.pop(index) save_custom_attrs_to_mk_file(self._all_attrs) self._update_config() add_change("edit-%sattrs" % self._type, _("Deleted attribute %s") % (delname)) return redirect(self.mode_url())
def page(self) -> None: title = self._page_title() breadcrumb = self._breadcrumb() html.header(title, breadcrumb, self._page_menu(breadcrumb)) if transactions.check_transaction(): try: self._action() except MKUserError as e: user_errors.add(e) for message in get_flashed_messages(): html.show_message(message) html.show_user_errors() self._show_form()
def page(self) -> None: title = self._page_title() breadcrumb = make_simple_page_breadcrumb(mega_menu_registry.menu_user(), title) html.header(title, breadcrumb, self._page_menu(breadcrumb)) if request.has_var("_save") and transactions.check_transaction(): try: self._action() except MKUserError as e: user_errors.add(e) for message in get_flashed_messages(): html.show_message(message) html.show_user_errors() self._show_form()
def action(self) -> ActionResult: if not transactions.check_transaction(): return None user.need_permission("wato.edit_hosts") changed_attributes = watolib.collect_attributes("bulk", new=False) host_names = get_hostnames_from_checkboxes() for host_name in host_names: host = watolib.Folder.current().host(host_name) host.update_attributes(changed_attributes) # call_hook_hosts_changed() is called too often. # Either offer API in class Host for bulk change or # delay saving until end somehow flash(_("Edited %d hosts") % len(host_names)) return redirect(watolib.Folder.current().url())
def action(self) -> ActionResult: folder = watolib.Folder.current() if not transactions.check_transaction(): return redirect(mode_url("folder", folder=folder.path())) if request.var("_update_dns_cache") and self._should_use_dns_cache(): user.need_permission("wato.update_dns_cache") update_dns_cache_result = update_dns_cache(self._host.site_id()) infotext = (_("Successfully updated IP addresses of %d hosts.") % update_dns_cache_result.n_updated) if update_dns_cache_result.failed_hosts: infotext += "<br><br><b>Hostnames failed to lookup:</b> " + ", ".join( [ "<tt>%s</tt>" % h for h in update_dns_cache_result.failed_hosts ]) flash(infotext) return None if request.var("delete"): # Delete this host folder.delete_hosts([self._host.name()]) return redirect(mode_url("folder", folder=folder.path())) attributes = watolib.collect_attributes( "host" if not self._is_cluster() else "cluster", new=False) host = watolib.Host.host(self._host.name()) if host is None: flash(f"Host {self._host.name()} could not be found.") return None host.edit(attributes, self._get_cluster_nodes()) self._host = folder.load_host(self._host.name()) if request.var("_save"): return redirect( mode_url("inventory", folder=folder.path(), host=self._host.name())) if request.var("diag_host"): return redirect( mode_url("diag_host", folder=folder.path(), host=self._host.name(), _start_on_load="1")) return redirect(mode_url("folder", folder=folder.path()))