def edit_valuespec(vs, value, buttontext=None, method="GET", varprefix="", validate=None, formname="form", consume_transid=True, focus=None): if html.request.var("filled_in") == formname and html.transaction_valid(): if consume_transid: html.check_transaction() messages = [] try: new_value = vs.from_html_vars(varprefix) vs.validate_value(new_value, varprefix) except MKUserError as e: messages.append("%s: %s" % (vs.title(), e.message)) html.add_user_error(e.varname, e.message) if validate and not html.has_user_errors(): try: validate(new_value) except MKUserError as e: messages.append(e.message) html.add_user_error(e.varname, e.message) if messages: html.show_error("".join(["%s<br>\n" % m for m in messages])) else: return new_value html.begin_form(formname, method=method) html.help(vs.help()) vs.render_input(varprefix, value) if buttontext is None: buttontext = _("Save") html.button("save", buttontext) # Should be ignored be hidden_fields, but I do not dare to change it there html.request.del_var("filled_in") html.hidden_fields() if focus: html.set_focus(focus) else: vs.set_focus(varprefix) html.end_form()
def handle_report_form(tardata, what): details = {} try: vs = vs_crash_report() details = vs.from_html_vars("_report") vs.validate_value(details, "_report") # Make the resulting page execute the crash report post request url_encoded_params = html.urlencode_vars(details.items() + [ ("crashdump", base64.b64encode(tardata)), ]) html.open_div(id_="pending_msg", style="display:none") html.message(_("Submitting crash report...")) html.close_div() html.open_div(id_="success_msg", style="display:none") html.message( _("Your crash report has been submitted (ID: ###ID###). Thanks for your participation, " "it is very important for the quality of Check_MK.<br><br>" "Please note:" "<ul>" "<li>In general we do <i>not</i> respond to crash reports, " "except we need further information from you.</li>" "<li>We read every feedback thoroughly, but this might happen " "not before a couple of weeks or even months have passed and is " "often aligned with our release cycle.</li>" "<li>If you are in need of a quick solution for your problem, then " "we can help you within the scope of professional support. If you " "already have a support contract, then please use your personal " "support email address to send us a mail refering to your crash " "report.<br>If you are interested in the details about support, " "you find details on <a href=\"https://checkmk.com/" "checkmk_support_contract.html\" target=_blank>our website</a>.")) html.close_div() html.open_div(id_="fail_msg", style="display:none") report_url = html.makeuri([ ("subject", "Check_MK Crash Report - " + get_version(what)), ], filename="mailto:" + get_crash_report_target(what)) html.show_error( _("Failed to send the crash report. Please download it manually and send it " "to <a href=\"%s\">%s</a>") % (report_url, get_crash_report_target(what))) html.close_div() html.javascript("cmk.crash_reporting.submit('https://checkmk.com/crash_report.php', " \ "'%s');" % url_encoded_params) except MKUserError as e: action_message = "%s" % e html.add_user_error(e.varname, action_message) return details
def page(self) -> None: watolib.init_wato_datastructures(with_wato_lock=True) profile_changed = False if html.request.has_var('_save') and html.check_transaction(): try: profile_changed = self._action() except MKUserError as e: html.add_user_error(e.varname, e) # Now, if in distributed environment where users can login to remote sites, set the trigger for # pushing the new user profile to the remote sites asynchronously if profile_changed and config.user.authorized_login_sites(): user_profile_async_replication_page() return self._show_form(profile_changed)
def page(self) -> None: watolib.init_wato_datastructures(with_wato_lock=True) title = self._page_title() breadcrumb = make_simple_page_breadcrumb(mega_menu_registry.menu_user(), title) html.header(title, breadcrumb, self._page_menu(breadcrumb)) if html.request.has_var('_save') and html.check_transaction(): try: self._action() except MKUserError as e: html.add_user_error(e.varname, e) for message in get_flashed_messages(): html.show_message(message) if html.has_user_errors(): html.show_user_errors() self._show_form()
def action(self): # type: () -> ActionResult if not html.check_transaction(): return None if html.request.var('_try'): try: self._validate_diag_html_vars() except MKUserError as e: html.add_user_error(e.varname, e) return None if html.request.var('_save'): # Save the ipaddress and/or community vs_host = self._vs_host() new = vs_host.from_html_vars('vs_host') vs_host.validate_value(new, 'vs_host') # If both snmp types have credentials set - snmpv3 takes precedence return_message = [] if "ipaddress" in new: return_message.append(_("IP address")) if "snmp_v3_credentials" in new: if "snmp_community" in new: return_message.append( _("SNMPv3 credentials (SNMPv2 community was discarded)" )) else: return_message.append(_("SNMPv3 credentials")) new["snmp_community"] = new["snmp_v3_credentials"] elif "snmp_community" in new: return_message.append(_("SNMP credentials")) msg = _("Updated attributes: ") + ", ".join(return_message) self._host.update_attributes(new) html.request.del_vars() html.request.set_var("host", self._hostname) html.request.set_var("folder", watolib.Folder.current().path()) return "edit_host", msg return None
def _get_time_range_of(self, what): varprefix = self.ident + "_" + what rangename = html.request.var(varprefix + "_range") if rangename == "abs": try: return time.mktime(time.strptime(html.request.var(varprefix), "%Y-%m-%d")) except Exception: html.add_user_error(varprefix, _("Please enter the date in the format YYYY-MM-DD.")) return None elif rangename == "unix": return html.request.get_integer_input_mandatory(varprefix) try: count = html.request.get_integer_input_mandatory(varprefix) secs = count * int(rangename) return int(time.time()) - secs except Exception: html.request.set_var(varprefix, "") return None
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 html.request.get_ascii_input("filled_in") == formname and html.transaction_valid(): if not preview and consume_transid: html.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)) html.add_user_error(e.varname, e) except Exception as e: messages.append("%s: %s" % (vs_dict.title() or _("Properties"), e)) html.add_user_error(None, e) if validate and not html.has_user_errors(): try: validate(new_value[keyname]) except MKUserError as e: messages.append("%s" % e) html.add_user_error(e.varname, 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 html.request.del_var("filled_in") html.hidden_fields() html.end_form()
def render( self, rows: Rows, show_checkboxes: bool, num_columns: int, show_filters: List[Filter], unfiltered_amount_of_rows: int, ) -> None: view_spec = self.view.spec home = ("mobile.py", "Home", "home") page = html.request.var("page") if not page: if view_spec.get("mustsearch"): page = "filter" else: page = "data" title = views.view_title(self.view.spec, self.view.context) navbar = [("data", _("Results"), "grid", 'results_button'), ("filter", _("Filter"), "search", '')] if config.user.may("general.act"): navbar.append(("commands", _("Commands"), "gear", '')) # Should we show a page with context links? context_links = list( views.collect_context_links(self.view, rows, mobile=True, only_types=['views'])) if context_links: navbar.append(("context", _("Context"), "arrow-r", '')) page_id = "view_" + view_spec["name"] if page == "filter": jqm_page_header(_("Filter / Search"), left_button=home, id_="filter") _show_filter_form(show_filters) jqm_page_navfooter(navbar, 'filter', page_id) elif page == "commands": # Page: Commands if config.user.may("general.act"): jqm_page_header(_("Commands"), left_button=home, id_="commands") show_commands = True if html.request.has_var("_do_actions"): try: show_commands = do_commands( self.view.datasource.infos[0], rows) except MKUserError as e: html.show_error("%s" % e) html.add_user_error(e.varname, e) show_commands = True if show_commands: _show_command_form(self.view.datasource, rows) jqm_page_navfooter(navbar, 'commands', page_id) elif page == "data": # Page: data rows of view jqm_page_header( title, left_button=home, right_button=("javascript:document.location.reload();", _("Reload"), "refresh"), id_="data") html.open_div(id_="view_results") if len(rows) == 0: html.write(_("No hosts/services found.")) else: try: if cmk.gui.view_utils.row_limit_exceeded( unfiltered_amount_of_rows, self.view.row_limit): cmk.gui.view_utils.query_limit_exceeded_warn( self.view.row_limit, config.user) del rows[self.view.row_limit:] self.view.layout.render( rows, view_spec, self.view.group_cells, self.view.row_cells, num_columns, show_checkboxes and not html.do_actions(), ) except Exception as e: logger.exception("error rendering mobile view") html.write(_("Error showing view: %s") % e) html.close_div() jqm_page_navfooter(navbar, 'data', page_id) # Page: Context buttons elif page == "context": jqm_page_header(_("Context"), left_button=home, id_="context") _show_context_links(context_links) jqm_page_navfooter(navbar, 'context', page_id)
def _do_login(self) -> None: """handle the sent login form""" if not html.request.var('_login'): return try: username_var = html.request.get_unicode_input('_username', '') assert username_var is not None username = UserId(username_var.rstrip()) if not username: raise MKUserError('_username', _('No username given.')) password = html.request.var('_password', '') if not password: raise MKUserError('_password', _('No password given.')) default_origtarget = config.url_prefix() + "check_mk/" origtarget = html.get_url_input("_origtarget", default_origtarget) # Disallow redirections to: # - logout.py: Happens after login # - side.py: Happens when invalid login is detected during sidebar refresh if "logout.py" in origtarget or 'side.py' in origtarget: origtarget = default_origtarget # '<user_id>' -> success # False -> failed result = userdb.hook_login(username, password) if result: assert isinstance(result, str) # use the username provided by the successful login function, this function # might have transformed the username provided by the user. e.g. switched # from mixed case to lower case. username = result # When single user session mode is enabled, check that there is not another # active session userdb.ensure_user_can_init_session(username) # reset failed login counts userdb.on_succeeded_login(username) # The login succeeded! Now: # a) Set the auth cookie # b) Unset the login vars in further processing # c) Redirect to really requested page _create_auth_session(username) # Never use inplace redirect handling anymore as used in the past. This results # in some unexpected situations. We simpy use 302 redirects now. So we have a # clear situation. # userdb.need_to_change_pw returns either False or the reason description why the # password needs to be changed change_pw_result = userdb.need_to_change_pw(username) if change_pw_result: raise HTTPRedirect( 'user_change_pw.py?_origtarget=%s&reason=%s' % (html.urlencode(origtarget), change_pw_result)) raise HTTPRedirect(origtarget) userdb.on_failed_login(username) raise MKUserError(None, _('Invalid credentials.')) except MKUserError as e: html.add_user_error(e.varname, e)
def edit_dictionaries( dictionaries, # type: List[Tuple[str, Union[Transform, Dictionary]]] value, # type: Dict[str, Any] focus=None, # type: Optional[str] hover_help=True, # type: bool validate=None, # type: Optional[Callable[[Any], None]] buttontext=None, # type: Optional[Text] title=None, # type: Optional[Text] buttons=None, # type: List[Tuple[str, Text, str]] method="GET", # type: str preview=False, # type: bool varprefix="", # type: str formname="form", # type: str consume_transid=True # type: bool ): if html.request.get_ascii_input( "filled_in") == formname and html.transaction_valid(): if not preview and consume_transid: html.check_transaction() messages = [] # type: List[Text] new_value = {} # type: 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)) html.add_user_error(e.varname, e) except Exception as e: messages.append("%s: %s" % (vs_dict.title() or _("Properties"), e)) html.add_user_error(None, e) if validate and not html.has_user_errors(): try: validate(new_value[keyname]) except MKUserError as e: messages.append("%s" % e) html.add_user_error(e.varname, 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() if buttons: for name, button_title, _icon in buttons: html.button(name, button_title) else: if buttontext is None: buttontext = _("Save") html.button("save", buttontext) # Should be ignored be hidden_fields, but I do not dare to change it there html.request.del_var("filled_in") html.hidden_fields() html.end_form()
def _show_page_user_profile(change_pw): start_async_replication = False if not config.user.id: raise MKUserError(None, _('Not logged in.')) if not config.user.may('general.edit_profile') and not config.user.may( 'general.change_password'): raise MKAuthException( _("You are not allowed to edit your user profile.")) if not config.wato_enabled: raise MKAuthException( _('User profiles can not be edited (WATO is disabled).')) success = None if html.request.has_var('_save') and html.check_transaction(): users = userdb.load_users(lock=True) try: # Profile edit (user options like language etc.) if config.user.may('general.edit_profile'): if not change_pw: set_lang = html.get_checkbox('_set_lang') language = html.request.var('language') # Set the users language if requested if set_lang: if language == '': language = None # Set custom language users[config.user.id]['language'] = language config.user.language = language html.set_language_cookie(language) else: # Remove the customized language if 'language' in users[config.user.id]: del users[config.user.id]['language'] config.user.reset_language() # load the new language cmk.gui.i18n.localize(config.user.language) user = users.get(config.user.id) if config.user.may('general.edit_notifications' ) and user.get("notifications_enabled"): value = forms.get_input( watolib.get_vs_flexible_notifications(), "notification_method") users[config.user.id]["notification_method"] = value # Custom attributes if config.user.may('general.edit_user_attributes'): for name, attr in userdb.get_user_attributes(): if attr.user_editable(): if not attr.permission() or config.user.may( attr.permission()): vs = attr.valuespec() value = vs.from_html_vars('ua_' + name) vs.validate_value(value, "ua_" + name) users[config.user.id][name] = value # Change the password if requested password_changed = False if config.user.may('general.change_password'): cur_password = html.request.var('cur_password') password = html.request.var('password') password2 = html.request.var('password2', '') if change_pw: # Force change pw mode if not cur_password: raise MKUserError( "cur_password", _("You need to provide your current password.")) if not password: raise MKUserError( "password", _("You need to change your password.")) if cur_password == password: raise MKUserError( "password", _("The new password must differ from your current one." )) if cur_password and password: if userdb.hook_login(config.user.id, cur_password) is False: raise MKUserError("cur_password", _("Your old password is wrong.")) if password2 and password != password2: raise MKUserError( "password2", _("The both new passwords do not match.")) watolib.verify_password_policy(password) users[config.user.id]['password'] = hash_password(password) users[config.user.id]['last_pw_change'] = int(time.time()) if change_pw: # Has been changed, remove enforcement flag del users[config.user.id]['enforce_pw_change'] # Increase serial to invalidate old cookies if 'serial' not in users[config.user.id]: users[config.user.id]['serial'] = 1 else: users[config.user.id]['serial'] += 1 password_changed = True # Now, if in distributed environment where users can login to remote sites, # set the trigger for pushing the new auth information to the slave sites # asynchronous if config.user.authorized_login_sites(): start_async_replication = True userdb.save_users(users) if password_changed: # Set the new cookie to prevent logout for the current user login.set_auth_cookie(config.user.id) success = True except MKUserError as e: html.add_user_error(e.varname, e) else: users = userdb.load_users() watolib.init_wato_datastructures(with_wato_lock=True) # When in distributed setup, display the replication dialog instead of the normal # profile edit dialog after changing the password. if start_async_replication: user_profile_async_replication_page() return if change_pw: title = _("Change Password") else: title = _("Edit User Profile") html.header(title) # Rule based notifications: The user currently cannot simply call the according # WATO module due to WATO permission issues. So we cannot show this button # right now. if not change_pw: rulebased_notifications = watolib.load_configuration_settings().get( "enable_rulebased_notifications") if rulebased_notifications and config.user.may( 'general.edit_notifications'): html.begin_context_buttons() url = "wato.py?mode=user_notifications_p" html.context_button(_("Notifications"), url, "notifications") html.end_context_buttons() else: reason = html.request.var('reason') if reason == 'expired': html.p( _('Your password is too old, you need to choose a new password.' )) else: html.p( _('You are required to change your password before proceeding.' )) if success: html.reload_sidebar() if change_pw: html.show_message(_("Your password has been changed.")) raise HTTPRedirect(html.request.var('_origtarget', 'index.py')) else: html.show_message(_("Successfully updated user profile.")) # Ensure theme changes are applied without additional user interaction html.immediate_browser_redirect(0.5, html.makeuri([])) if html.has_user_errors(): html.show_user_errors() user = users.get(config.user.id) if user is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return # Returns true if an attribute is locked and should be read only. Is only # checked when modifying an existing user locked_attributes = userdb.locked_attributes(user.get('connector')) def is_locked(attr): return attr in locked_attributes html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(_("Personal Settings")) if not change_pw: forms.section(_("Name"), simple=True) html.write_text(user.get("alias", config.user.id)) if config.user.may( 'general.change_password') and not is_locked('password'): forms.section(_("Current Password")) html.password_input('cur_password', autocomplete="new-password") forms.section(_("New Password")) html.password_input('password', autocomplete="new-password") forms.section(_("New Password Confirmation")) html.password_input('password2', autocomplete="new-password") if not change_pw and config.user.may('general.edit_profile'): select_language(user) # Let the user configure how he wants to be notified if not rulebased_notifications \ and config.user.may('general.edit_notifications') \ and user.get("notifications_enabled"): forms.section(_("Notifications")) html.help( _("Here you can configure how you want to be notified about host and service problems and " "other monitoring events.")) watolib.get_vs_flexible_notifications().render_input( "notification_method", user.get("notification_method")) if config.user.may('general.edit_user_attributes'): for name, attr in userdb.get_user_attributes(): if attr.user_editable(): vs = attr.valuespec() forms.section(_u(vs.title())) value = user.get(name, vs.default_value()) if not attr.permission() or config.user.may( attr.permission()): vs.render_input("ua_" + name, value) html.help(_u(vs.help())) else: html.write(vs.value_to_text(value)) # Save button forms.end() html.button("_save", _("Save")) html.close_div() html.hidden_fields() html.end_form() html.footer()
def edit_dictionaries(dictionaries, value, focus=None, hover_help=True, validate=None, buttontext=None, title=None, buttons=None, method="GET", preview=False, varprefix="", formname="form", consume_transid=True): # Convert list of entries/dictionaries sections = [] for keyname, d in dictionaries: if isinstance(d, list): sections.append((keyname, title or _("Properties"), d)) else: sections.append((keyname, None, d)) # valuespec Dictionary, title used from dict if html.request.var("filled_in") == formname and html.transaction_valid(): if not preview and consume_transid: html.check_transaction() messages = [] new_value = {} for keyname, _section_title, entries in sections: if isinstance(entries, list): new_value[keyname] = value.get(keyname, {}).copy() for name, vs in entries: if len(sections) == 1: vp = varprefix else: vp = keyname + "_" + varprefix try: v = vs.from_html_vars(vp + name) vs.validate_value(v, vp + name) new_value[keyname][name] = v except MKUserError as e: messages.append("%s: %s" % (vs.title(), e)) html.add_user_error(e.varname, e) else: new_value[keyname] = {} try: edited_value = entries.from_html_vars(keyname) entries.validate_value(edited_value, keyname) new_value[keyname].update(edited_value) except MKUserError as e: messages.append("%s: %s" % (entries.title() or _("Properties"), e)) html.add_user_error(e.varname, e) except Exception as e: messages.append("%s: %s" % (entries.title() or _("Properties"), e)) html.add_user_error(None, e) if validate and not html.has_user_errors(): try: validate(new_value[keyname]) except MKUserError as e: messages.append(e) html.add_user_error(e.varname, 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, title1, entries in sections: subvalue = value.get(keyname, {}) if isinstance(entries, list): header(title1) first = True for name, vs in entries: section(vs.title()) html.help(vs.help()) if name in subvalue: v = subvalue[name] else: v = vs.default_value() if len(sections) == 1: vp = varprefix else: vp = keyname + "_" + varprefix vs.render_input(vp + name, v) if (not focus and first) or (name == focus): vs.set_focus(vp + name) first = False else: entries.render_input_as_form(keyname, subvalue) end() if buttons: for name, button_title, _icon in buttons: html.button(name, button_title) else: if buttontext is None: buttontext = _("Save") html.button("save", buttontext) # Should be ignored be hidden_fields, but I do not dare to change it there html.request.del_var("filled_in") html.hidden_fields() html.end_form()
def _wato_page_handler(current_mode: str, mode_permissions: Optional[List[PermissionName]], mode_class: Type[WatoMode]) -> None: try: init_wato_datastructures(with_wato_lock=not html.is_transaction()) except Exception: # Snapshot must work in any case if current_mode == 'snapshot': pass else: raise # Check general permission for this mode if mode_permissions is not None and not config.user.may("wato.seeall"): _ensure_mode_permissions(mode_permissions) mode = mode_class() # Do actions (might switch mode) if html.is_transaction(): try: config.user.need_permission("wato.edit") # Even if the user has seen this mode because auf "seeall", # he needs an explicit access permission for doing changes: if config.user.may("wato.seeall"): if mode_permissions: _ensure_mode_permissions(mode_permissions) if cmk.gui.watolib.read_only.is_enabled( ) and not cmk.gui.watolib.read_only.may_override(): raise MKUserError(None, cmk.gui.watolib.read_only.message()) result = mode.action() if isinstance(result, (tuple, str, bool)): raise MKGeneralException( f"WatoMode \"{current_mode}\" returns unsupported return value: {result!r}" ) # We assume something has been modified and increase the config generation ID by one. update_config_generation() if config.wato_use_git: do_git_commit() # Handle two cases: # a) Don't render the page content after action # (a confirm dialog is displayed by the action, or a non-HTML content was sent) # b) Redirect to another page if isinstance(result, FinalizeRequest): raise result except MKUserError as e: html.add_user_error(e.varname, str(e)) except MKAuthException as e: reason = e.args[0] html.add_user_error(None, reason) breadcrumb = make_main_menu_breadcrumb( mode.main_menu()) + mode.breadcrumb() page_menu = mode.page_menu(breadcrumb) wato_html_head(title=mode.title(), breadcrumb=breadcrumb, page_menu=page_menu, show_body_start=display_options.enabled(display_options.H), show_top_heading=display_options.enabled(display_options.T)) if not html.is_transaction() or (cmk.gui.watolib.read_only.is_enabled() and cmk.gui.watolib.read_only.may_override()): _show_read_only_warning() # Show outcome of failed action on this page if html.has_user_errors(): html.show_user_errors() # Show outcome of previous page (that redirected to this one) for message in get_flashed_messages(): html.show_message(message) # Show content mode.handle_page() if is_sidebar_reload_needed(): html.reload_whole_page() wato_html_footer(show_body_end=display_options.enabled(display_options.H))
def _wato_page_handler(current_mode: str, mode_permissions: List[PermissionName], mode_class: Type[WatoMode]) -> None: try: init_wato_datastructures(with_wato_lock=not html.is_transaction()) except Exception: # Snapshot must work in any case if current_mode == 'snapshot': pass else: raise # Check general permission for this mode if mode_permissions is not None and not config.user.may("wato.seeall"): _ensure_mode_permissions(mode_permissions) mode = mode_class() # Do actions (might switch mode) action_message: Optional[str] = None if html.is_transaction(): try: config.user.need_permission("wato.edit") # Even if the user has seen this mode because auf "seeall", # he needs an explicit access permission for doing changes: if config.user.may("wato.seeall"): if mode_permissions: _ensure_mode_permissions(mode_permissions) if cmk.gui.watolib.read_only.is_enabled( ) and not cmk.gui.watolib.read_only.may_override(): raise MKUserError(None, cmk.gui.watolib.read_only.message()) result = mode.action() if isinstance(result, tuple): newmode, action_message = result else: newmode = result # We assume something has been modified and increase the config generation ID by one. update_config_generation() # If newmode is False, then we shall immediately abort. # This is e.g. the case, if the page outputted non-HTML # data, such as a tarball (in the export function). We must # be sure not to output *any* further data in that case. if newmode is False: return # if newmode is not None, then the mode has been changed if newmode is not None: assert not isinstance(newmode, bool) if newmode == "": # no further information: configuration dialog, etc. if action_message: html.show_message(action_message) wato_html_footer() return mode_permissions, mode_class = _get_mode_permission_and_class( newmode) current_mode = newmode mode = mode_class() html.request.set_var("mode", newmode) # will be used by makeuri # Check general permissions for the new mode if mode_permissions is not None and not config.user.may( "wato.seeall"): for pname in mode_permissions: if '.' not in pname: pname = "wato." + pname config.user.need_permission(pname) except MKUserError as e: action_message = "%s" % e html.add_user_error(e.varname, action_message) except MKAuthException as e: reason = e.args[0] action_message = reason html.add_user_error(None, reason) breadcrumb = make_main_menu_breadcrumb( mode.main_menu()) + mode.breadcrumb() page_menu = mode.page_menu(breadcrumb) wato_html_head(title=mode.title(), breadcrumb=breadcrumb, page_menu=page_menu, show_body_start=display_options.enabled(display_options.H), show_top_heading=display_options.enabled(display_options.T)) if not html.is_transaction() or (cmk.gui.watolib.read_only.is_enabled() and cmk.gui.watolib.read_only.may_override()): _show_read_only_warning() # Show outcome of action if html.has_user_errors(): html.show_user_errors() elif action_message: html.show_message(action_message) # Show content mode.handle_page() if is_sidebar_reload_needed(): html.reload_sidebar() if config.wato_use_git and html.is_transaction(): do_git_commit() wato_html_footer(show_footer=display_options.enabled(display_options.Z), show_body_end=display_options.enabled(display_options.H))