示例#1
0
    def _show_subfolder_infos(self, subfolder):
        html.open_div(class_="infos")
        html.open_div(class_="infos_content")
        groups = load_contact_group_information()
        permitted_groups, _folder_contact_groups, _use_for_services = subfolder.groups(
        )
        for num, pg in enumerate(permitted_groups):
            cgalias = groups.get(pg, {'alias': pg})['alias']
            html.icon(_("Contactgroups that have permission on this folder"),
                      "contactgroups")
            html.write_text(' %s' % cgalias)
            html.br()
            if num > 1 and len(permitted_groups) > 4:
                html.write_text(
                    _('<i>%d more contact groups</i><br>') %
                    (len(permitted_groups) - num - 1))
                break

        num_hosts = subfolder.num_hosts_recursively()
        if num_hosts == 1:
            html.write_text(_("1 Host"))
        elif num_hosts > 0:
            html.write_text("%d %s" % (num_hosts, _("Hosts")))
        else:
            html.i(_("(no hosts)"))
        html.close_div()
        html.close_div()
示例#2
0
    def _sidebar_head(self):
        html.open_div(id_="side_header")
        html.div('', id_="side_fold")
        html.open_a(href=config.user.get_attribute("start_url")
                    or config.start_url,
                    target="main",
                    title=_("Go to main overview"))
        html.div("", id_="side_bg")

        if config.sidebar_show_version_in_sidebar:
            html.open_div(id_="side_version")
            html.open_a(href="version.py",
                        target="main",
                        title=_("Open release notes"))
            html.write(self._get_check_mk_edition_title())
            html.br()
            html.write(cmk_version.__version__)

            if werks.may_acknowledge():
                num_unacknowledged_werks = werks.num_unacknowledged_incompatible_werks(
                )
                if num_unacknowledged_werks:
                    html.span(num_unacknowledged_werks,
                              class_="unack_werks",
                              title=_("%d unacknowledged incompatible werks") %
                              num_unacknowledged_werks)

        html.close_a()
        html.close_div()
        html.close_a()
        html.close_div()
示例#3
0
def page_login() -> None:
    title = _("Check_MK Mobile")
    mobile_html_head(title)
    jqm_page_header(title, id_="login")
    html.div(_("Welcome to Check_MK Mobile."), id_="loginhead")

    html.begin_form("login", method='POST', add_transid=False)
    # Keep information about original target URL
    default_origtarget = "index.py" if html.myfile in ["login", "logout"
                                                       ] else html.makeuri([])
    origtarget = html.get_url_input("_origtarget", default_origtarget)
    html.hidden_field('_origtarget', escaping.escape_attribute(origtarget))

    html.text_input("_username", label=_("Username:"******"username")
    html.password_input("_password",
                        size=None,
                        label=_("Password:"******"current-password")
    html.br()
    html.button("_login", _('Login'))
    html.set_focus("_username")
    html.end_form()
    html.open_div(id_="loginfoot")
    html.img("themes/classic/images/logo_cmk_small.png", class_="logomk")
    html.div(HTML(
        _("&copy; <a target=\"_blank\" href=\"https://checkmk.com\">tribe29 GmbH</a>"
          )),
             class_="copyright")
    html.close_div()  # close content-div
    html.close_div()
    html.close_div()  # close page-div
    mobile_html_foot()
示例#4
0
def page_login():
    title = _("Check_MK Mobile")
    mobile_html_head(title)
    jqm_page_header(title, id_="login")
    html.div(_("Welcome to Check_MK Mobile."), id_="loginhead")

    html.begin_form("login", method='POST', add_transid=False)
    # Keep information about original target URL
    origtarget = html.request.var('_origtarget', '')
    if not origtarget and not html.myfile == 'login':
        origtarget = html.request.requested_url
    html.hidden_field('_origtarget', html.attrencode(origtarget))

    html.text_input("_username", label=_("Username:"******"_password", size=None, label=_("Password:"******"_login", _('Login'))
    html.set_focus("_username")
    html.end_form()
    html.open_div(id_="loginfoot")
    html.img("themes/classic/images/logo_cmk_small.png", class_="logomk")
    html.div(HTML(
        _("&copy; <a target=\"_blank\" href=\"https://checkmk.com\">tribe29 GmbH</a>"
          )),
             class_="copyright")
    jqm_page_footer()
    mobile_html_foot()
示例#5
0
    def render_input(self, varprefix, value):
        value = convert_cgroups_from_tuple(value)

        # If we're just editing a host, then some of the checkboxes will be missing.
        # This condition is not very clean, but there is no other way to savely determine
        # the context.
        is_host = bool(
            html.request.var("host")) or html.request.var("mode") == "newhost"
        is_search = varprefix == "host_search"

        # Only show contact groups I'm currently in and contact
        # groups already listed here.
        self.load_data()
        self._vs_contactgroups().render_input(varprefix + self.name(),
                                              value['groups'])

        html.hr()

        if is_host:
            html.checkbox(varprefix + self.name() + "_use",
                          value["use"],
                          label=_("Add these contact groups to the host"))

        elif not is_search:
            html.checkbox(
                varprefix + self.name() + "_recurse_perms",
                value["recurse_perms"],
                label=_(
                    "Give these groups also <b>permission on all subfolders</b>"
                ))
            html.hr()
            html.checkbox(
                varprefix + self.name() + "_use",
                value["use"],
                label=
                _("Add these groups as <b>contacts</b> to all hosts <b>in this folder</b>"
                  ))
            html.br()
            html.checkbox(
                varprefix + self.name() + "_recurse_use",
                value["recurse_use"],
                label=
                _("Add these groups as <b>contacts</b> to all hosts <b>in all subfolders of this folder</b>"
                  ))

        html.hr()
        html.help(
            _("With this option contact groups that are added to hosts are always "
              "being added to services, as well. This only makes a difference if you have "
              "assigned other contact groups to services via rules in <i>Host & Service Parameters</i>. "
              "As long as you do not have any such rule a service always inherits all contact groups "
              "from its host."))
        html.checkbox(
            varprefix + self.name() + "_use_for_services",
            value.get("use_for_services", False),
            label=_("Always add host contact groups also to its services")
            if is_host else
            _("Always add these groups as <b>contacts</b> to all services <b>in all subfolders of this folder</b>"
              ))
示例#6
0
    def _render_tag_tree_level(self, tree_spec, path, cwd, title,
                               tree) -> None:
        if not self._is_tag_subdir(
                path=path, cwd=cwd) and not self._is_tag_subdir(path=cwd,
                                                                cwd=path):
            return

        container: ContextManager[bool] = nullcontext(False)
        if path != cwd and self._is_tag_subdir(path, cwd):
            bullet = self._tag_tree_bullet(self._tag_tree_worst_state(tree),
                                           path, False)
            if self._tag_tree_has_svc_problems(tree):
                bullet += html.render_icon_button(
                    self._tag_tree_url(tree_spec, path, "svcproblems"),
                    _("Show the service problems contained in this branch"),
                    "svc_problems",
                    target="main",
                )

            if path:
                container = foldable_container(
                    treename="tag-tree",
                    id_=".".join(map(str, path)),
                    isopen=False,
                    title=bullet + title,
                    icon="foldable_sidebar",
                )

        with container:
            for (node_title, node_value), subtree in sorted(
                    tree.get("_children", {}).items()):
                subpath = path + [node_value or ""]
                url = self._tag_tree_url(tree_spec, subpath, "allhosts")

                if "_num_hosts" in subtree:
                    node_title += " (%d)" % subtree["_num_hosts"]

                node_title = html.render_a(node_title, href=url, target="main")

                if "_children" not in subtree:
                    if self._is_tag_subdir(path, cwd):
                        html.write_html(
                            self._tag_tree_bullet(subtree.get("_state", 0),
                                                  subpath, True))
                        if subtree.get("_svc_problems"):
                            url = self._tag_tree_url(tree_spec, subpath,
                                                     "svcproblems")
                            html.icon_button(
                                url,
                                _("Show the service problems contained in this branch"
                                  ),
                                "svc_problems",
                                target="main",
                            )
                        html.write_html(node_title)
                        html.br()
                else:
                    self._render_tag_tree_level(tree_spec, subpath, cwd,
                                                node_title, subtree)
示例#7
0
 def _iconlink(self, text, url, icon):
     html.open_a(class_=["iconlink", "link"], target="main", href=url)
     html.icon(icon="/webconf/images/icon_%s.png" % icon,
               title=None,
               cssclass="inline")
     html.write(text)
     html.close_a()
     html.br()
示例#8
0
    def _render_tag_tree_level(self, tree_spec, path, cwd, title, tree):
        if (not self._is_tag_subdir(path=path, cwd=cwd)
                and not self._is_tag_subdir(path=cwd, cwd=path)):
            return

        if path != cwd and self._is_tag_subdir(path, cwd):
            bullet = self._tag_tree_bullet(self._tag_tree_worst_state(tree),
                                           path, False)
            if self._tag_tree_has_svc_problems(tree):
                bullet += html.render_icon_button(
                    self._tag_tree_url(tree_spec, path, "svcproblems"),
                    _("Show the service problems contained in this branch"),
                    "svc_problems",
                    target="main")

            if path:
                html.begin_foldable_container(
                    "tag-tree",
                    ".".join(map(str, path)),
                    False,
                    HTML(bullet + title),
                    icon="foldable_sidebar",
                )

        for (node_title,
             node_value), subtree in sorted(tree.get("_children", {}).items()):
            subpath = path + [node_value or ""]
            url = self._tag_tree_url(tree_spec, subpath, "allhosts")

            if "_num_hosts" in subtree:
                node_title += " (%d)" % subtree["_num_hosts"]

            node_title = html.render_a(node_title, href=url, target="main")

            if "_children" not in subtree:
                if self._is_tag_subdir(path, cwd):
                    html.write(
                        self._tag_tree_bullet(subtree.get("_state", 0),
                                              subpath, True))
                    if subtree.get("_svc_problems"):
                        url = self._tag_tree_url(tree_spec, subpath,
                                                 "svcproblems")
                        html.icon_button(
                            url,
                            _("Show the service problems contained in this branch"
                              ),
                            "svc_problems",
                            target="main")
                    html.write(node_title)
                    html.br()
            else:
                self._render_tag_tree_level(tree_spec, subpath, cwd,
                                            node_title, subtree)

        if path and path != cwd and self._is_tag_subdir(path, cwd):
            html.end_foldable_container()
示例#9
0
    def _show_job_info(self):
        if self._job_snapshot.is_active():
            html.h3(_("Current status of synchronization process"))
            html.set_browser_reload(0.8)
        else:
            html.h3(_("Result of last synchronization process"))

        job_manager = gui_background_job.GUIBackgroundJobManager()
        job_manager.show_job_details_from_snapshot(job_snapshot=self._job_snapshot)
        html.br()
示例#10
0
 def display(self):
     html.begin_checkbox_group()
     for state, state_name in sorted(defines.interface_oper_states().items()):
         if state >= 8:
             continue  # skip artificial state 8 (degraded) and 9 (admin down)
         varname = self.ident + "_" + str(state)
         html.checkbox(varname, True, label=state_name)
         if state in (4, 7):
             html.br()
     html.end_checkbox_group()
示例#11
0
 def display(self, value: FilterHTTPVariables) -> None:
     html.begin_checkbox_group()
     for state, state_name in sorted(defines.interface_oper_states().items()):
         if not isinstance(state, int):  # needed because of silly types
             continue
         if state >= 8:
             continue  # skip artificial state 8 (degraded) and 9 (admin down)
         varname = self.ident + "_" + str(state)
         html.checkbox(varname, bool(value.get(varname, True)), label=state_name)
         if state in (4, 7):
             html.br()
     html.end_checkbox_group()
示例#12
0
文件: werks.py 项目: xorsiz0r/checkmk
def render_unacknowleged_werks():
    werks = unacknowledged_incompatible_werks()
    if werks and not html.request.has_var("show_unack"):
        html.open_div(class_=["warning"])
        html.write_text(
            _("<b>Warning:</b> There are %d unacknowledged incompatible werks:"
              ) % len(werks))
        html.br()
        html.br()
        html.a(_("Show unacknowledged incompatible werks"),
               href=makeuri_contextless(request, [("show_unack", "1"),
                                                  ("wo_compatibility", "3")]))
        html.close_div()
示例#13
0
文件: utils.py 项目: dnlldl/checkmk
    def render_input(self, varprefix: str, value: str) -> None:
        if self._label:
            html.write(self._label)
            html.nbsp()

        if value is None:
            clean_choices = self.choices()
        else:
            # Need to create an on the fly metric option
            clean_choices = [
                next(((metric_id, metric_detail['title'])
                      for metric_id, metric_detail in metric_info.items()
                      if metric_id == value), (value, value.title()))
            ]

        html.write(_("Select metric: "))
        html.dropdown(varprefix,
                      self._options_for_html(clean_choices),
                      deflt=self._option_for_html(value),
                      class_="metric-selector",
                      style="width: 250px;",
                      read_only=self._read_only)

        vs_host = MonitoredHostname(
            label=_("Filter metric selection by hostname: "),
            placeholder=_("Hint a hostname"),
            size=20,
        )
        html.br()
        host_varprefix = varprefix + "_hostname_hint"
        vs_host.render_input(host_varprefix, None)
        html.javascript(
            "cmk.valuespecs.transfer_context_onchange('context_host_p_host', %s)"
            % json.dumps(host_varprefix))

        completion_js = '(() => ({host: document.getElementsByName(%s)[0].value}))()' % json.dumps(
            host_varprefix)
        vs_service = MonitoredServiceDescription(
            label=_("Filter metric selection by service: "),
            placeholder=_("Hint a service"),
            completion_params_js=completion_js,
            size=20)
        service_varprefix = varprefix + "_service_hint"
        html.br()
        vs_service.render_input(service_varprefix, None)
        html.javascript(
            "cmk.valuespecs.transfer_context_onchange('context_service_p_service', %s)"
            % json.dumps(service_varprefix))
示例#14
0
    def page(self):
        html.begin_form("random")
        forms.header(_("Add random hosts"))
        forms.section(_("Number to create"))
        html.write_text("%s: " % _("Hosts to create in each folder"))
        html.text_input("count", default_value="10", cssclass="number")
        html.set_focus("count")
        html.br()
        html.write_text("%s: " % _("Number of folders to create in each level"))
        html.text_input("folders", default_value="10", cssclass="number")
        html.br()
        html.write_text("%s: " % _("Levels of folders to create"))
        html.text_input("levels", default_value="1", cssclass="number")

        forms.end()
        html.hidden_fields()
        html.end_form()
示例#15
0
def render_unacknowleged_werks():
    werks = unacknowledged_incompatible_werks()
    if werks and may_acknowledge():
        html.begin_context_buttons()
        html.context_button(_("Acknowledge all"), html.makeactionuri([("_ack_all", "1")]),
                            "werk_ack")
        html.end_context_buttons()

    if werks and not html.request.has_var("show_unack"):
        html.open_div(class_=["warning"])
        html.write_text(
            _("<b>Warning:</b> There are %d unacknowledged incompatible werks:") % len(werks))
        html.br()
        html.br()
        html.a(_("Show unacknowledged incompatible werks"),
               href=html.makeuri_contextless([("show_unack", "1"), ("wo_compatibility", "3")]))
        html.close_div()
示例#16
0
    def page(self):
        html.begin_form("random")
        forms.header(_("Create Random Hosts"))
        forms.section(_("Number to create"))
        html.write_text("%s: " % _("Hosts to create in each folder"))
        html.number_input("count", 10)
        html.set_focus("count")
        html.br()
        html.write_text("%s: " % _("Number of folders to create in each level"))
        html.number_input("folders", 10)
        html.br()
        html.write_text("%s: " % _("Levels of folders to create"))
        html.number_input("levels", 1)

        forms.end()
        html.button("start", _("Start!"), "submit")
        html.hidden_fields()
        html.end_form()
示例#17
0
    def _show_tree_selection(self):
        html.begin_form("vtree")

        html.dropdown("vtree",
                      self._tree_choices(),
                      deflt="%s" % self._current_tree_id,
                      onchange='virtual_host_tree_changed(this)',
                      style="width:210px" if self._current_tree_path else None)

        # Give chance to change one level up, if we are in a subtree
        if self._current_tree_path:
            upurl = "javascript:virtual_host_tree_enter('%s')" % "|".join(
                self._current_tree_path[:-1])
            html.icon_button(upurl, _("Go up one tree level"), "back")

        html.br()
        html.end_form()
        html.final_javascript(self._javascript())
示例#18
0
 def display(self, value: FilterHTTPVariables) -> None:
     html.text_input(self._varprefix + "name")
     html.br()
     display_filter_radiobuttons(
         varname=self._varprefix + "match",
         options=[
             ("exact", _("exact match")),
             ("regex", _("regular expression, substring match")),
         ],
         default="exact",
         value=value,
     )
     html.br()
     html.open_span(class_="min_max_row")
     html.write_text(_("Min.&nbsp;Version: "))
     html.text_input(
         self._varprefix + "version_from",
         default_value=value.get(self._varprefix + "version_from", ""),
         size=9,
     )
     html.write_text(" &nbsp; ")
     html.write_text(_("Max.&nbsp;Vers.: "))
     html.text_input(
         self._varprefix + "version_to",
         default_value=value.get(self._varprefix + "version_from", ""),
         size=9,
     )
     html.close_span()
     html.br()
     html.checkbox(
         self._varprefix + "negate",
         False,
         label=_("Negate: find hosts <b>not</b> having this package"),
     )
示例#19
0
 def display(self) -> None:
     html.text_input(self._varprefix + "name")
     html.br()
     html.begin_radio_group(horizontal=True)
     html.radiobutton(self._varprefix + "match",
                      "exact",
                      True,
                      label=_("exact match"))
     html.radiobutton(self._varprefix + "match",
                      "regex",
                      False,
                      label=_("regular expression, substring match"))
     html.end_radio_group()
     html.br()
     html.open_span(class_="min_max_row")
     html.write_text(_("Min.&nbsp;Version: "))
     html.text_input(self._varprefix + "version_from", size=9)
     html.write_text(" &nbsp; ")
     html.write_text(_("Max.&nbsp;Vers.: "))
     html.text_input(self._varprefix + "version_to", size=9)
     html.close_span()
     html.br()
     html.checkbox(
         self._varprefix + "negate",
         False,
         label=_("Negate: find hosts <b>not</b> having this package"))
示例#20
0
    def page(self):
        # Show outcome of host validation. Do not validate new hosts
        errors = None
        if self._mode == "edit":
            errors = (watolib.validate_all_hosts([self._host.name()]).get(
                self._host.name(), []) + self._host.validation_errors())

        if errors:
            html.open_div(class_="info")
            html.open_table(class_="validationerror",
                            boder="0",
                            cellspacing="0",
                            cellpadding="0")
            html.open_tr()

            html.open_td(class_="img")
            html.icon("validation_error")
            html.close_td()

            html.open_td()
            html.open_p()
            html.h3(_("Warning: This host has an invalid configuration!"))
            html.open_ul()
            for error in errors:
                html.li(error)
            html.close_ul()
            html.close_p()

            if html.form_submitted():
                html.br()
                html.b(_("Your changes have been saved nevertheless."))
            html.close_td()

            html.close_tr()
            html.close_table()
            html.close_div()

        lock_message = ""
        locked_hosts = watolib.Folder.current().locked_hosts()
        if locked_hosts:
            if locked_hosts is True:
                lock_message = _(
                    "Host attributes locked (You cannot edit this host)")
            elif isinstance(locked_hosts, str):
                lock_message = locked_hosts
        if lock_message:
            html.div(lock_message, class_="info")

        html.begin_form("edit_host", method="POST")
        html.prevent_password_auto_completion()

        basic_attributes = [
            # attribute name, valuepec, default value
            ("host", self._vs_host_name(), self._host.name()),
        ]

        if self._is_cluster():
            basic_attributes += [
                # attribute name, valuepec, default value
                (
                    "nodes",
                    self._vs_cluster_nodes(),
                    self._host.cluster_nodes() if self._host else [],
                ),
            ]

        configure_attributes(
            new=self._mode != "edit",
            hosts={self._host.name(): self._host}
            if self._mode != "new" else {},
            for_what="host" if not self._is_cluster() else "cluster",
            parent=watolib.Folder.current(),
            basic_attributes=basic_attributes,
        )

        if self._mode != "edit":
            html.set_focus("host")

        forms.end()
        html.hidden_fields()
        html.end_form()
示例#21
0
    def _output_analysed_ruleset(self,
                                 all_rulesets,
                                 rulespec,
                                 svc_desc_or_item,
                                 svc_desc,
                                 known_settings=None):
        if known_settings is None:
            known_settings = self._PARAMETERS_UNKNOWN

        def rule_url(rule):
            return watolib.folder_preserving_link([
                ('mode', 'edit_rule'),
                ('varname', varname),
                ('rule_folder', rule.folder.path()),
                ('rulenr', rule.index()),
                ('host', self._hostname),
                ('item', watolib.mk_repr(svc_desc_or_item)
                 if svc_desc_or_item else ''),
                ('service', watolib.mk_repr(svc_desc) if svc_desc else ''),
            ])

        varname = rulespec.name
        valuespec = rulespec.valuespec

        url = watolib.folder_preserving_link([
            ('mode', 'edit_ruleset'),
            ('varname', varname),
            ('host', self._hostname),
            ('item', watolib.mk_repr(svc_desc_or_item)),
            ('service', watolib.mk_repr(svc_desc)),
        ])

        forms.section(html.render_a(rulespec.title, url))

        ruleset = all_rulesets.get(varname)
        setting, rules = ruleset.analyse_ruleset(self._hostname,
                                                 svc_desc_or_item, svc_desc)

        html.open_table(class_="setting")
        html.open_tr()
        html.open_td(class_="reason")

        # Show reason for the determined value
        if len(rules) == 1:
            rule_folder, rule_index, rule = rules[0]
            url = rule_url(rule)
            html.a(_("Rule %d in %s") % (rule_index + 1, rule_folder.title()),
                   href=rule_url(rule))

        elif len(rules) > 1:
            html.a("%d %s" % (len(rules), _("Rules")), href=url)

        else:
            html.i(_("Default Value"))
        html.close_td()

        # Show the resulting value or factory setting
        html.open_td(
            class_=["settingvalue", "used" if len(rules) > 0 else "unused"])

        if isinstance(known_settings,
                      dict) and "tp_computed_params" in known_settings:
            computed_at = known_settings["tp_computed_params"]["computed_at"]
            html.write_text(
                _("Timespecific parameters computed at %s") %
                cmk.utils.render.date_and_time(computed_at))
            html.br()
            known_settings = known_settings["tp_computed_params"]["params"]

        # In some cases we now the settings from a check_mk automation
        if known_settings is self._PARAMETERS_OMIT:
            return

        # Special handling for logwatch: The check parameter is always None. The actual
        # patterns are configured in logwatch_rules. We do not have access to the actual
        # patterns here but just to the useless "None". In order not to complicate things
        # we simply display nothing here.
        if varname == "logwatch_rules":
            pass

        elif known_settings is not self._PARAMETERS_UNKNOWN:
            try:
                html.write(valuespec.value_to_text(known_settings))
            except Exception as e:
                if config.debug:
                    raise
                html.write_text(
                    _("Invalid parameter %r: %s") % (known_settings, e))

        else:
            # For match type "dict" it can be the case the rule define some of the keys
            # while other keys are taken from the factory defaults. We need to show the
            # complete outcoming value here.
            if rules and ruleset.match_type() == "dict":
                if rulespec.factory_default is not watolib.Rulespec.NO_FACTORY_DEFAULT \
                    and rulespec.factory_default is not watolib.Rulespec.FACTORY_DEFAULT_UNUSED:
                    fd = rulespec.factory_default.copy()
                    fd.update(setting)
                    setting = fd

            if valuespec and not rules:  # show the default value
                if rulespec.factory_default is watolib.Rulespec.FACTORY_DEFAULT_UNUSED:
                    # Some rulesets are ineffective if they are empty
                    html.write_text(_("(unused)"))

                elif rulespec.factory_default is not watolib.Rulespec.NO_FACTORY_DEFAULT:
                    # If there is a factory default then show that one
                    setting = rulespec.factory_default
                    html.write(valuespec.value_to_text(setting))

                elif ruleset.match_type() in ("all", "list"):
                    # Rulesets that build lists are empty if no rule matches
                    html.write_text(_("(no entry)"))

                else:
                    # Else we use the default value of the valuespec
                    html.write(
                        valuespec.value_to_text(valuespec.default_value()))

            # We have a setting
            elif valuespec:
                if ruleset.match_type() == "all":
                    html.write(", ".join(
                        [valuespec.value_to_text(e) for e in setting]))
                else:
                    html.write(valuespec.value_to_text(setting))

            # Binary rule, no valuespec, outcome is True or False
            else:
                icon_name = "rule_%s%s" % ("yes" if setting else "no",
                                           "_off" if not rules else '')
                html.icon(title=_("yes") if setting else _("no"),
                          icon=icon_name)
        html.close_td()
        html.close_tr()
        html.close_table()
示例#22
0
    def _show_login_page(self) -> None:
        html.set_render_headfoot(False)
        html.add_body_css_class("login")
        html.header(config.get_page_heading(), Breadcrumb(), javascripts=[])

        default_origtarget = ("index.py" if html.myfile in ["login", "logout"]
                              else makeuri(global_request, []))
        origtarget = html.get_url_input("_origtarget", default_origtarget)

        # Never allow the login page to be opened in the iframe. Redirect top page to login page.
        # This will result in a full screen login page.
        html.javascript('''if(top != self) {
    window.top.location.href = location;
}''')

        # When someone calls the login page directly and is already authed redirect to main page
        if html.myfile == 'login' and _check_auth(html.request):
            raise HTTPRedirect(origtarget)

        html.open_div(id_="login")

        html.open_div(id_="login_window")

        html.div("" if "hide_version" in config.login_screen else
                 cmk_version.__version__,
                 id_="version")

        html.begin_form("login",
                        method='POST',
                        add_transid=False,
                        action='login.py')
        html.hidden_field('_login', '1')
        html.hidden_field('_origtarget', origtarget)
        html.label("%s:" % _('Username'),
                   id_="label_user",
                   class_=["legend"],
                   for_="_username")
        html.br()
        html.text_input("_username", id_="input_user")
        html.label("%s:" % _('Password'),
                   id_="label_pass",
                   class_=["legend"],
                   for_="_password")
        html.br()
        html.password_input("_password", id_="input_pass", size=None)

        if html.has_user_errors():
            html.open_div(id_="login_error")
            html.show_user_errors()
            html.close_div()

        html.open_div(id_="button_text")
        html.button("_login", _('Login'))
        html.close_div()
        html.close_div()

        html.open_div(id_="foot")

        if config.login_screen.get("login_message"):
            html.open_div(id_="login_message")
            html.show_message(config.login_screen["login_message"])
            html.close_div()

        footer: List[Union[HTML, str]] = []
        for title, url, target in config.login_screen.get("footer_links", []):
            footer.append(html.render_a(title, href=url, target=target))

        if "hide_version" not in config.login_screen:
            footer.append("Version: %s" % cmk_version.__version__)

        footer.append("&copy; %s" % html.render_a(
            "tribe29 GmbH", href="https://checkmk.com", target="_blank"))

        html.write(HTML(" - ").join(footer))

        if cmk_version.is_raw_edition():
            html.br()
            html.br()
            html.write(
                _('You can use, modify and distribute Check_MK under the terms of the <a href="%s" target="_blank">'
                  'GNU GPL Version 2</a>.') % "https://checkmk.com/gpl.html")

        html.close_div()

        html.set_focus('_username')
        html.hidden_fields()
        html.end_form()
        html.close_div()

        html.footer()
示例#23
0
    def page(self):
        # Let exceptions from loading notification scripts happen now
        watolib.load_notification_scripts()

        html.begin_form("user", method="POST")
        html.prevent_password_auto_completion()

        forms.header(_("Identity"))

        # ID
        forms.section(_("Username"), simple=not self._is_new_user)
        if self._is_new_user:
            vs_user_id = UserID(allow_empty=False)

        else:
            vs_user_id = FixedValue(self._user_id)
        vs_user_id.render_input("user_id", self._user_id)

        def lockable_input(name, dflt):
            if not self._is_locked(name):
                html.text_input(name, self._user.get(name, dflt), size=50)
            else:
                html.write_text(self._user.get(name, dflt))
                html.hidden_field(name, self._user.get(name, dflt))

        # Full name
        forms.section(_("Full name"))
        lockable_input('alias', self._user_id)
        html.help(_("Full name or alias of the user"))

        # Email address
        forms.section(_("Email address"))
        email = self._user.get("email", "")
        if not self._is_locked("email"):
            EmailAddressUnicode().render_input("email", email)
        else:
            html.write_text(email)
            html.hidden_field("email", email)

        html.help(
            _("The email address is optional and is needed "
              "if the user is a monitoring contact and receives notifications "
              "via Email."))

        forms.section(_("Pager address"))
        lockable_input('pager', '')
        html.help(_("The pager address is optional "))

        if cmk.is_managed_edition():
            forms.section(self._vs_customer.title())
            self._vs_customer.render_input("customer", managed.get_customer_id(self._user))

            html.help(self._vs_customer.help())

        vs_sites = self._vs_sites()
        forms.section(vs_sites.title())
        authorized_sites = self._user.get("authorized_sites", vs_sites.default_value())
        if not self._is_locked("authorized_sites"):
            vs_sites.render_input("authorized_sites", authorized_sites)
        else:
            html.write_html(vs_sites.value_to_text(authorized_sites))
        html.help(vs_sites.help())

        self._show_custom_user_attributes('ident')

        forms.header(_("Security"))
        forms.section(_("Authentication"))

        is_automation = self._user.get("automation_secret", None) is not None
        html.radiobutton("authmethod", "password", not is_automation,
                         _("Normal user login with password"))
        html.open_ul()
        html.open_table()
        html.open_tr()
        html.td(_("password:"******"_password_" + self._pw_suffix(), autocomplete="new-password")
            html.close_td()
            html.close_tr()

            html.open_tr()
            html.td(_("repeat:"))
            html.open_td()
            html.password_input("_password2_" + self._pw_suffix(), autocomplete="new-password")
            html.write_text(" (%s)" % _("optional"))
            html.close_td()
            html.close_tr()

            html.open_tr()
            html.td("%s:" % _("Enforce change"))
            html.open_td()
            # Only make password enforcement selection possible when user is allowed to change the PW
            if self._is_new_user or config.user_may(self._user_id,
                                                    'general.edit_profile') and config.user_may(
                                                        self._user_id, 'general.change_password'):
                html.checkbox("enforce_pw_change",
                              self._user.get("enforce_pw_change", False),
                              label=_("Change password at next login or access"))
            else:
                html.write_text(
                    _("Not permitted to change the password. Change can not be enforced."))
        else:
            html.i(_('The password can not be changed (It is locked by the user connector).'))
            html.hidden_field('_password', '')
            html.hidden_field('_password2', '')

        html.close_td()
        html.close_tr()
        html.close_table()
        html.close_ul()

        html.radiobutton("authmethod", "secret", is_automation,
                         _("Automation secret for machine accounts"))

        html.open_ul()
        html.text_input("_auth_secret",
                        self._user.get("automation_secret", ""),
                        size=30,
                        id_="automation_secret")
        html.write_text(" ")
        html.open_b(style=["position: relative", "top: 4px;"])
        html.write(" &nbsp;")
        html.icon_button("javascript:cmk.wato.randomize_secret('automation_secret', 20);",
                         _("Create random secret"), "random")
        html.close_b()
        html.close_ul()

        html.help(
            _("If you want the user to be able to login "
              "then specify a password here. Users without a login make sense "
              "if they are monitoring contacts that are just used for "
              "notifications. The repetition of the password is optional. "
              "<br>For accounts used by automation processes (such as fetching "
              "data from views for further procession), set the method to "
              "<u>secret</u>. The secret will be stored in a local file. Processes "
              "with read access to that file will be able to use Multisite as "
              "a webservice without any further configuration."))

        # Locking
        forms.section(_("Disable password"), simple=True)
        if not self._is_locked('locked'):
            html.checkbox("locked",
                          self._user.get("locked", False),
                          label=_("disable the login to this account"))
        else:
            html.write_text(
                _('Login disabled') if self._user.get("locked", False) else _('Login possible'))
            html.hidden_field('locked', '1' if self._user.get("locked", False) else '')
        html.help(
            _("Disabling the password will prevent a user from logging in while "
              "retaining the original password. Notifications are not affected "
              "by this setting."))

        forms.section(_("Idle timeout"))
        idle_timeout = self._user.get("idle_timeout")
        if not self._is_locked("idle_timeout"):
            watolib.get_vs_user_idle_timeout().render_input("idle_timeout", idle_timeout)
        else:
            html.write_text(idle_timeout)
            html.hidden_field("idle_timeout", idle_timeout)

        # Roles
        forms.section(_("Roles"))
        entries = self._roles.items()
        entries.sort(key=lambda x: (x[1]["alias"], x[0]))
        is_member_of_at_least_one = False
        for role_id, role in entries:
            if not self._is_locked("roles"):
                html.checkbox("role_" + role_id, role_id in self._user.get("roles", []))
                url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)])
                html.a(role["alias"], href=url)
                html.br()
            else:
                is_member = role_id in self._user.get("roles", [])
                if is_member:
                    is_member_of_at_least_one = True
                    url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)])
                    html.a(role["alias"], href=url)
                    html.br()

                html.hidden_field("role_" + role_id, '1' if is_member else '')
        if self._is_locked('roles') and not is_member_of_at_least_one:
            html.i(_('No roles assigned.'))
        self._show_custom_user_attributes('security')

        # Contact groups
        forms.header(_("Contact Groups"), isopen=False)
        forms.section()
        groups_page_url = watolib.folder_preserving_link([("mode", "contact_groups")])
        group_assign_url = watolib.folder_preserving_link([("mode", "rulesets"),
                                                           ("group", "grouping")])
        if not self._contact_groups:
            html.write(
                _("Please first create some <a href='%s'>contact groups</a>") % groups_page_url)
        else:
            entries = sorted([(group['alias'] or c, c) for c, group in self._contact_groups.items()
                             ])
            is_member_of_at_least_one = False
            for alias, gid in entries:
                is_member = gid in self._user.get("contactgroups", [])

                if not self._is_locked('contactgroups'):
                    html.checkbox("cg_" + gid, gid in self._user.get("contactgroups", []))
                else:
                    if is_member:
                        is_member_of_at_least_one = True
                    html.hidden_field("cg_" + gid, '1' if is_member else '')

                if not self._is_locked('contactgroups') or is_member:
                    url = watolib.folder_preserving_link([("mode", "edit_contact_group"),
                                                          ("edit", gid)])
                    html.a(alias, href=url)
                    html.br()

            if self._is_locked('contactgroups') and not is_member_of_at_least_one:
                html.i(_('No contact groups assigned.'))

        html.help(
            _("Contact groups are used to assign monitoring "
              "objects to users. If you haven't defined any contact groups yet, "
              "then first <a href='%s'>do so</a>. Hosts and services can be "
              "assigned to contact groups using <a href='%s'>rules</a>.<br><br>"
              "If you do not put the user into any contact group "
              "then no monitoring contact will be created for the user.") %
            (groups_page_url, group_assign_url))

        forms.header(_("Notifications"), isopen=False)
        if not self._rbn_enabled():
            forms.section(_("Enabling"), simple=True)
            html.checkbox("notifications_enabled",
                          self._user.get("notifications_enabled", False),
                          label=_("enable notifications"))
            html.help(
                _("Notifications are sent out "
                  "when the status of a host or service changes."))

            # Notification period
            forms.section(_("Notification time period"))
            choices = [(id_, "%s" % (tp["alias"])) for (id_, tp) in self._timeperiods.items()]
            html.dropdown("notification_period",
                          choices,
                          deflt=self._user.get("notification_period"),
                          ordered=True)
            html.help(
                _("Only during this time period the "
                  "user will get notifications about host or service alerts."))

            # Notification options
            notification_option_names = {  # defined here: _() must be executed always!
                "host": {
                    "d": _("Host goes down"),
                    "u": _("Host gets unreachble"),
                    "r": _("Host goes up again"),
                },
                "service": {
                    "w": _("Service goes into warning state"),
                    "u": _("Service goes into unknown state"),
                    "c": _("Service goes into critical state"),
                    "r": _("Service recovers to OK"),
                },
                "both": {
                    "f": _("Start or end of flapping state"),
                    "s": _("Start or end of a scheduled downtime"),
                }
            }

            forms.section(_("Notification Options"))
            for title, what, opts in [(_("Host events"), "host", "durfs"),
                                      (_("Service events"), "service", "wucrfs")]:
                html.write_text("%s:" % title)
                html.open_ul()

                user_opts = self._user.get(what + "_notification_options", opts)
                for opt in opts:
                    opt_name = notification_option_names[what].get(
                        opt, notification_option_names["both"].get(opt))
                    html.checkbox(what + "_" + opt, opt in user_opts, label=opt_name)
                    html.br()
                html.close_ul()

            html.help(
                _("Here you specify which types of alerts "
                  "will be notified to this contact. Note: these settings will only be saved "
                  "and used if the user is member of a contact group."))

            forms.section(_("Notification Method"))
            watolib.get_vs_flexible_notifications().render_input(
                "notification_method", self._user.get("notification_method"))

        else:
            forms.section(_("Fallback notifications"), simple=True)

            html.checkbox("fallback_contact",
                          self._user.get("fallback_contact", False),
                          label=_("Receive fallback notifications"))

            html.help(
                _("In case none of your notification rules handles a certain event a notification "
                  "will be sent to this contact. This makes sure that in that case at least <i>someone</i> "
                  "gets notified. Furthermore this contact will be used for notifications to any host or service "
                  "that is not known to the monitoring. This can happen when you forward notifications "
                  "from the Event Console.<br><br>Notification fallback can also configured in the global "
                  "setting <a href=\"wato.py?mode=edit_configvar&varname=notification_fallback_email\">"
                  "Fallback email address for notifications</a>."))

        self._show_custom_user_attributes('notify')

        forms.header(_("Personal Settings"), isopen=False)
        select_language(self._user)
        self._show_custom_user_attributes('personal')

        # Later we could add custom macros here, which then could be used
        # for notifications. On the other hand, if we implement some check_mk
        # --notify, we could directly access the data in the account with the need
        # to store values in the monitoring core. We'll see what future brings.
        forms.end()
        html.button("save", _("Save"))
        if self._is_new_user:
            html.set_focus("user_id")
        else:
            html.set_focus("alias")
        html.hidden_fields()
        html.end_form()
示例#24
0
def simplelink(text, url, target="main"):
    link(text, url, target)
    html.br()
示例#25
0
def iconlink(text, url, icon):
    html.open_a(class_=["iconlink", "link"], target="main", href=url)
    html.icon(icon, cssclass="inline")
    html.write_text(text)
    html.close_a()
    html.br()
示例#26
0
def simplelink(text: Union[str, HTML], url: str, target: str = "main") -> None:
    link(text, url, target)
    html.br()
示例#27
0
    def _show_start_form(self):
        html.begin_form("parentscan", method="POST")
        html.hidden_fields()

        # Mode of action
        html.open_p()
        if not self._complete_folder:
            num_selected = len(get_hosts_from_checkboxes())
            html.write_text(
                _("You have selected <b>%d</b> hosts for parent scan. ") %
                num_selected)
        html.p(
            _("The parent scan will try to detect the last gateway "
              "on layer 3 (IP) before a host. This will be done by "
              "calling <tt>traceroute</tt>. If a gateway is found by "
              "that way and its IP address belongs to one of your "
              "monitored hosts, that host will be used as the hosts "
              "parent. If no such host exists, an artifical ping-only "
              "gateway host will be created if you have not disabled "
              "this feature."))

        forms.header(_("Settings for Parent Scan"))

        self._settings = config.user.load_file(
            "parentscan", {
                "where": "subfolder",
                "alias": _("Created by parent scan"),
                "recurse": True,
                "select": "noexplicit",
                "timeout": 8,
                "probes": 2,
                "ping_probes": 5,
                "max_ttl": 10,
                "force_explicit": False,
            })

        # Selection
        forms.section(_("Selection"))
        if self._complete_folder:
            html.checkbox("recurse",
                          self._settings["recurse"],
                          label=_("Include all subfolders"))
            html.br()
        html.radiobutton(
            "select", "noexplicit", self._settings["select"] == "noexplicit",
            _("Skip hosts with explicit parent definitions (even if empty)") +
            "<br>")
        html.radiobutton(
            "select", "no", self._settings["select"] == "no",
            _("Skip hosts hosts with non-empty parents (also if inherited)") +
            "<br>")
        html.radiobutton("select", "ignore",
                         self._settings["select"] == "ignore",
                         _("Scan all hosts") + "<br>")

        # Performance
        forms.section(_("Performance"))
        html.open_table()
        html.open_tr()
        html.open_td()
        html.write_text(_("Timeout for responses") + ":")
        html.close_td()
        html.open_td()
        html.number_input("timeout", self._settings["timeout"], size=2)
        html.write_text(_("sec"))
        html.close_td()
        html.close_tr()

        html.open_tr()
        html.open_td()
        html.write_text(_("Number of probes per hop") + ":")
        html.close_td()
        html.open_td()
        html.number_input("probes", self._settings["probes"], size=2)
        html.close_td()
        html.close_tr()

        html.open_tr()
        html.open_td()
        html.write_text(_("Maximum distance (TTL) to gateway") + ":")
        html.close_td()
        html.open_td()
        html.number_input("max_ttl", self._settings["max_ttl"], size=2)
        html.close_td()
        html.close_tr()

        html.open_tr()
        html.open_td()
        html.write_text(_("Number of PING probes") + ":")
        html.help(
            _("After a gateway has been found, Check_MK checks if it is reachable "
              "via PING. If not, it is skipped and the next gateway nearer to the "
              "monitoring core is being tried. You can disable this check by setting "
              "the number of PING probes to 0."))
        html.close_td()
        html.open_td()
        html.number_input("ping_probes",
                          self._settings.get("ping_probes", 5),
                          size=2)
        html.close_td()
        html.close_tr()
        html.close_table()

        # Configuring parent
        forms.section(_("Configuration"))
        html.checkbox(
            "force_explicit",
            self._settings["force_explicit"],
            label=
            _("Force explicit setting for parents even if setting matches that of the folder"
              ))

        # Gateway creation
        forms.section(_("Creation of gateway hosts"))
        html.write_text(_("Create gateway hosts in"))
        html.open_ul()

        html.radiobutton(
            "where", "subfolder", self._settings["where"] == "subfolder",
            _("in the subfolder <b>%s/Parents</b>") %
            watolib.Folder.current_disk_folder().title())

        html.br()
        html.radiobutton(
            "where", "here", self._settings["where"] == "here",
            _("directly in the folder <b>%s</b>") %
            watolib.Folder.current_disk_folder().title())
        html.br()
        html.radiobutton("where", "there", self._settings["where"] == "there",
                         _("in the same folder as the host"))
        html.br()
        html.radiobutton("where", "nowhere",
                         self._settings["where"] == "nowhere",
                         _("do not create gateway hosts"))
        html.close_ul()
        html.write_text(_("Alias for created gateway hosts") + ": ")
        html.text_input("alias", self._settings["alias"])

        forms.end()

        # Start button
        html.button("_start", _("Start"))
        html.hidden_fields()
        html.end_form()
示例#28
0
def foldable_container(
    *,
    treename: str,
    id_: str,
    isopen: bool,
    title: HTMLContent,
    indent: Union[str, None, bool] = True,
    first: bool = False,
    icon: Optional[str] = None,
    fetch_url: Optional[str] = None,
    title_url: Optional[str] = None,
    title_target: Optional[str] = None,
    padding: int = 15,
) -> Iterator[bool]:
    isopen = user.get_tree_state(treename, id_, isopen)
    onclick = foldable_container_onclick(treename, id_, fetch_url)
    img_id = foldable_container_img_id(treename, id_)
    container_id = foldable_container_id(treename, id_)

    html.open_div(class_=["foldable", "open" if isopen else "closed"])

    if isinstance(title, HTML):  # custom HTML code
        html.write_text(title)

    else:
        html.open_b(class_=["treeangle", "title"],
                    onclick=None if title_url else onclick)

        if title_url:
            html.a(title, href=title_url, target=title_target)
        else:
            html.write_text(title)
        html.close_b()

    if icon:
        html.img(
            id_=img_id,
            class_=[
                "treeangle",
                "title",
                # Although foldable_sidebar is given via the argument icon it should not be
                # displayed as big as an icon.
                "icon" if icon != "foldable_sidebar" else None,
                "open" if isopen else "closed",
            ],
            src=theme.detect_icon_path(icon, "icon_"),
            onclick=onclick,
        )
    else:
        html.img(
            id_=img_id,
            class_=["treeangle", "open" if isopen else "closed"],
            src=theme.url("images/tree_closed.svg"),
            onclick=onclick,
        )

    if indent != "form" or not isinstance(title, HTML):
        html.br()

    indent_style = "padding-left: %dpx; " % (padding if indent else 0)
    if indent == "form":
        html.close_td()
        html.close_tr()
        html.close_table()
        indent_style += "margin: 0; "
    html.open_ul(id_=container_id,
                 class_=["treeangle", "open" if isopen else "closed"],
                 style=indent_style)

    yield isopen

    html.close_ul()
    html.close_div()
示例#29
0
class UserLoginTwoFactor(Page):
    def page(self) -> None:
        assert user.id is not None

        html.set_render_headfoot(False)
        html.add_body_css_class("login")
        html.add_body_css_class("two_factor")
        html.header(_("Two-factor authentication"),
                    Breadcrumb(),
                    javascripts=[])

        html.open_div(id_="login")

        html.open_div(id_="login_window")

        html.open_a(href="https://checkmk.com")
        html.img(
            src=theme.detect_icon_path(icon_name="logo", prefix="mk-"),
            id_="logo",
            class_="custom" if theme.has_custom_logo() else None,
        )
        html.close_a()

        if not is_two_factor_login_enabled(user.id):
            raise MKGeneralException(
                _("Two-factor authentication not enabled"))

        html.begin_form("two_factor_login",
                        method="POST",
                        add_transid=False,
                        action="user_login_two_factor.py")
        html.prevent_password_auto_completion()
        html.hidden_field(
            "_origtarget", origtarget :=
            request.get_url_input("_origtarget", "index.py"))

        if backup_code := request.get_ascii_input("_backup_code"):
            if is_two_factor_backup_code_valid(user.id, backup_code):
                set_two_factor_completed()
                raise HTTPRedirect(origtarget)

        html.label(
            _("Two-factor authentication"),
            for_="webauthn_message",
            id_="label_2fa",
            class_="legend",
        )
        html.div("", id_="webauthn_message")

        with foldable_container(
                treename="webauthn_backup_codes",
                id_="backup_container",
                isopen=False,
                title=_("Use backup code"),
                indent=False,
                save_state=False,
        ):
            html.label(
                "%s:" % _("Backup code"),
                id_="label_pass",
                class_=["legend"],
                for_="_backup_code",
            )
            html.br()
            html.password_input("_backup_code", id_="input_pass", size=None)

            html.open_div(id_="button_text")
            html.button("_use_backup_code",
                        _("Use backup code"),
                        cssclass="hot")
            html.close_div()
            html.close_div()

        if user_errors:
            html.open_div(id_="login_error")
            html.show_user_errors()
            html.close_div()

        html.javascript("cmk.webauthn.login()")

        html.hidden_fields()
        html.end_form()
        html.close_div()
        html.footer()
示例#30
0
def _rename_tags_after_confirmation(operation):
    # type: (ABCOperation) -> Union[bool, str]
    """Handle renaming and deletion of tags

    Find affected hosts, folders and rules. Remove or fix those rules according
    the users' wishes.
    """
    repair_mode = html.request.var("_repair")
    if repair_mode is not None:
        try:
            mode = TagCleanupMode(repair_mode)
        except ValueError:
            raise MKUserError("_repair", "Invalid mode")

        if mode == TagCleanupMode.ABORT:
            raise MKUserError("id_0", _("Aborting change."))

        # make attribute unknown to system, important for save() operations
        if isinstance(operation, OperationRemoveTagGroup):
            watolib.host_attributes.undeclare_host_tag_attribute(
                operation.tag_group_id)

        affected_folders, affected_hosts, affected_rulesets = \
        _change_host_tags_in_folders(operation, mode, watolib.Folder.root_folder())

        return _("Modified folders: %d, modified hosts: %d, modified rulesets: %d") % \
            (len(affected_folders), len(affected_hosts), len(affected_rulesets))

    message = u""
    affected_folders, affected_hosts, affected_rulesets = \
        _change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder())

    if affected_folders:
        message += _("Affected folders with an explicit reference to this tag "
                     "group and that are affected by the change") + ":"
        with html.plugged():
            _show_affected_folders(affected_folders)
            message += html.drain()

    if affected_hosts:
        message += _("Hosts where this tag group is explicitely set "
                     "and that are effected by the change") + ":"
        with html.plugged():
            _show_affected_hosts(affected_hosts)
            message += html.drain()

    if affected_rulesets:
        message += _(
            "Rulesets that contain rules with references to the changed tags"
        ) + ":"
        with html.plugged():
            _show_affected_rulesets(affected_rulesets)
            message += html.drain()

    if message:
        wato_html_head(operation.confirm_title())
        html.open_div(class_="really")
        html.h3(_("Your modifications affect some objects"))
        html.write_text(message)
        html.br()
        html.write_text(
            _("WATO can repair things for you. It can rename tags in folders, host and rules. "
              "Removed tag groups will be removed from hosts and folders, removed tags will be "
              "replaced with the default value for the tag group (for hosts and folders). What "
              "rules concern, you have to decide how to proceed."))
        html.begin_form("confirm", method="POST")

        if affected_rulesets and _is_removing_tags(operation):
            html.br()
            html.b(
                _("Some tags that are used in rules have been removed by you. What "
                  "shall we do with that rules?"))
            html.open_ul()
            html.radiobutton(
                "_repair", "remove", True,
                _("Just remove the affected tags from the rules."))
            html.br()
            html.radiobutton(
                "_repair", "delete", False,
                _("Delete rules containing tags that have been removed, if tag is used in a positive sense. Just remove that tag if it's used negated."
                  ))
        else:
            html.open_ul()
            html.radiobutton("_repair", "repair", True,
                             _("Fix affected folders, hosts and rules."))

        html.br()
        html.radiobutton("_repair", "abort", False,
                         _("Abort your modifications."))
        html.close_ul()

        html.button("_do_confirm", _("Proceed"), "")
        html.hidden_fields(add_action_vars=True)
        html.end_form()
        html.close_div()
        return False

    return True