Esempio n. 1
0
    def _show_failed_notifications(self):
        if not self.parameters()["show_failed_notifications"]:
            return

        failed_notifications = notifications.number_of_failed_notifications(
            after=notifications.acknowledged_time()
        )
        if not failed_notifications:
            return

        html.open_div(class_="spacertop")
        html.open_div(class_="tacticalalert")

        confirm_url = makeuri_contextless(request, [], filename="clear_failed_notifications.py")
        html.icon_button(confirm_url, _("Confirm failed notifications"), "delete", target="main")

        view_url = makeuri_contextless(
            request,
            [("view_name", "failed_notifications")],
            filename="view.py",
        )

        html.a(_("%d failed notifications") % failed_notifications, target="main", href=view_url)
        html.close_div()
        html.close_div()
Esempio n. 2
0
def write_snapin_exception(e: Exception) -> None:
    html.open_div(class_=["snapinexception"])
    html.h2(_("Error"))
    html.p(str(e))
    html.div(traceback.format_exc().replace("\n", "<br>"),
             style="display:none;")
    html.close_div()
Esempio n. 3
0
    def _show_form(self) -> None:
        assert user.id is not None
        credentials = load_two_factor_credentials(user.id)

        credential_id = request.get_ascii_input_mandatory("_edit")
        credential = credentials["webauthn_credentials"].get(credential_id)
        if credential is None:
            raise MKUserError("_edit", _("The credential does not exist"))

        html.begin_form("profile", method="POST")
        html.prevent_password_auto_completion()
        html.open_div(class_="wato")

        self._valuespec(credential).render_input(
            "profile",
            {
                "registered_at": credential["registered_at"],
                "alias": credential["alias"],
            },
        )

        forms.end()
        html.close_div()
        html.hidden_field("_edit", credential_id)
        html.hidden_fields()
        html.end_form()
        html.footer()
Esempio n. 4
0
    def show(self):
        html.open_div(class_="speedometer")
        html.img(theme.url("images/speedometer.svg"), id_="speedometerbg")
        html.canvas("", width=str(snapin_width), height="146", id_="speedometer")
        html.close_div()

        html.javascript("cmk.sidebar.speedometer_show_speed(0, 0, 0);")
Esempio n. 5
0
def jqm_page_navfooter(items: NavigationBar, current: str, page_id: str) -> None:
    html.close_div()  # close content
    html.open_div(
        **{
            "data-role": "footer",
            "data-position": "fixed",
            "data-tap-toggle": "false",
            "data-hide-during-focus": "",
        }
    )
    html.open_div(**{"data-role": "navbar"})
    html.open_ul()

    for href, title, icon, custom_css in items:
        href = makeuri(request, [("page", href), ("search", "Search")])
        if current == href:
            custom_css += " ui-state-persist ui-btn-active"
        else:
            html.open_li()
            html.a(
                title,
                href=href,
                class_=custom_css,
                **{
                    "data-transition": "slide",
                    "data-icon": icon,
                    "data-iconpos": "bottom",
                },
            )
            html.close_li()
    html.close_ul()
    html.close_div()
    html.close_div()
    html.close_div()  # close page-div
Esempio n. 6
0
def _show_command_form(datasource: ABCDataSource, rows: Rows) -> None:
    what = datasource.infos[0]
    html.javascript(
        """
    $(document).ready(function() {
      $('.command_group').has('x').trigger('expand');
      $('x').children().css('background-color', '#f84');
    });
    """
    )

    one_shown = False
    html.open_div(**{"data-role": "collapsible-set"})
    for command_class in command_registry.values():
        command = command_class()
        if what in command.tables and user.may(command.permission.name):
            html.open_div(class_=["command_group"], **{"data-role": "collapsible"})
            html.h3(command.title)
            html.open_p()

            html.begin_form("actions")
            html.hidden_field("_do_actions", "yes")
            html.hidden_field("actions", "yes")
            command.render(what)
            html.hidden_fields()
            html.end_form()

            html.close_p()
            html.close_div()
            one_shown = True
    html.close_div()
    if not one_shown:
        html.write_text(_("No commands are possible in this view"))
Esempio n. 7
0
def render_user_message_table(what: str) -> None:
    html.open_div()
    with table_element(
        "user_messages", sortable=False, searchable=False, omit_if_empty=True
    ) as table:

        for entry in sorted(message.get_gui_messages(), key=lambda e: e["time"], reverse=True):
            if what not in entry["methods"]:
                continue

            table.row()

            msg_id = entry["id"]
            datetime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(entry["time"]))
            msg = entry["text"].replace("\n", " ")

            table.cell(_("Actions"), css=["buttons"], sortable=False)
            onclick = (
                "cmk.utils.delete_user_message('%s', this);cmk.utils.reload_whole_page();" % msg_id
                if what == "gui_hint"
                else "cmk.utils.delete_user_message('%s', this);" % msg_id
            )
            html.icon_button(
                "",
                _("Delete"),
                "delete",
                onclick=onclick,
            )

            table.cell(_("Message"), msg)
            table.cell(_("Date"), datetime)

    html.close_div()
Esempio n. 8
0
    def _create_status_box(
        self,
        site_ids: Collection[livestatus.SiteId],
        css_class: str,
        site_status: str,
    ):
        html.open_div(class_="spacertop")
        html.open_div(class_=css_class)
        message_template = ungettext("%d site is %s.", "%d sites are %s.", len(site_ids))
        message = message_template % (len(site_ids), site_status)
        tooltip_template = ungettext(
            "Associated hosts, services and events are not included "
            "in the Tactical Overview. The %s site is %s.",
            "Associated hosts, services and events are not included "
            "in the Tactical Overview. The %s sites are %s.",
            len(site_ids),
        )
        tooltip = tooltip_template % (site_status, ", ".join(site_ids))

        if user.may("wato.sites"):
            url = makeuri_contextless(request, [("mode", "sites")], filename="wato.py")
            html.icon_button(url, tooltip, "sites", target="main")
            html.a(message, target="main", href=url)
        else:
            html.icon("sites", tooltip)
            html.write_text(message)
        html.close_div()
        html.close_div()
Esempio n. 9
0
    def _show_sidebar(self) -> None:
        if not user.may("general.see_sidebar"):
            html.div("", id_="check_mk_navigation")
            return

        user_config = UserSidebarConfig(user, active_config.sidebar)

        html.open_div(
            id_="check_mk_navigation",
            class_="min"
            if user.get_attribute("nav_hide_icons_title") else None,
        )
        self._show_sidebar_head()
        html.close_div()

        assert user.id is not None
        sidebar_position = cmk.gui.userdb.load_custom_attr(
            user_id=user.id,
            key="ui_sidebar_position",
            parser=lambda x: None if x == "None" else "left",
        )
        html.open_div(
            id_="check_mk_sidebar",
            class_=[] if sidebar_position is None else [sidebar_position])

        self._show_snapin_bar(user_config)

        html.close_div()

        if user_config.folded:
            html.final_javascript("cmk.sidebar.fold_sidebar();")
Esempio n. 10
0
    def show(self):
        failed_notifications = notifications.number_of_failed_notifications(
            after=notifications.acknowledged_time())
        if not failed_notifications:
            return

        html.open_div(class_="has_failed_notifications")
        html.open_div(class_="failed_notifications_inner")

        confirm_url = makeuri_contextless(
            request, [], filename="clear_failed_notifications.py")
        html.icon_button(confirm_url,
                         _("Clear failed notifications"),
                         "closetimewarp",
                         target="main")

        view_url = makeuri_contextless(
            request,
            [("view_name", "failed_notifications")],
            filename="view.py",
        )
        html.a(_("%d failed notifications") % failed_notifications,
               href=view_url)

        html.close_div()
        html.close_div()
Esempio n. 11
0
    def _show_tree(self):
        tree_spec = self._trees[self._current_tree_id]["tree_spec"]

        tree = self._compute_tag_tree(tree_spec)
        html.open_div(class_="tag_tree")
        self._render_tag_tree_level(tree_spec, [], self._current_tree_path,
                                    _("Virtual Host Tree"), tree)
        html.close_div()
Esempio n. 12
0
 def _show_add_snapin_button(self) -> None:
     html.open_div(id_="add_snapin")
     html.open_a(href=makeuri_contextless(request, [],
                                          filename="sidebar_add_snapin.py"),
                 target="main")
     html.icon("add", title=_("Add elements to your sidebar"))
     html.close_a()
     html.close_div()
Esempio n. 13
0
    def _show_audit_log_options_controls(self):
        html.open_div(class_="side_popup_controls")

        html.open_div(class_="update_buttons")
        html.button("apply", _("Apply"), "submit")
        html.buttonlink(makeuri(request, [], remove_prefix="options_"), _("Reset"))
        html.close_div()

        html.close_div()
Esempio n. 14
0
 def show(self, page_state: PageState) -> None:
     html.open_div(class_=self._get_css_classes(page_state), title=page_state.tooltip_text)
     if page_state.url:
         html.open_a(page_state.url)
         self._show_content(page_state)
         html.close_a()
     else:
         self._show_content(page_state)
     html.close_div()
Esempio n. 15
0
def _show_output_box(title: str, content: bytes) -> None:
    html.h3(title, class_="table")
    html.open_div(class_="log_output")
    html.write_html(
        HTML(
            escaping.escape_attribute(
                content.decode(errors="surrogateescape")).replace(
                    "\n", "<br>").replace(" ", "&nbsp;")))
    html.close_div()
Esempio n. 16
0
    def show(self, breadcrumb: Breadcrumb) -> None:
        html.open_div(class_="breadcrumb")

        for item in breadcrumb:
            if item.url:
                html.a(escape_to_html(str(item.title)), href=item.url)
            else:
                html.span(escape_to_html(str(item.title)))

        html.close_div()
Esempio n. 17
0
    def action(self) -> ActionResult:
        if request.var("_action") != "discard":
            return None

        if not transactions.check_transaction():
            return None

        if not self._may_discard_changes():
            return None

        if not self.has_changes():
            return None

        # Now remove all currently pending changes by simply restoring the last automatically
        # taken snapshot. Then activate the configuration. This should revert all pending changes.
        file_to_restore = self._get_last_wato_snapshot_file()

        if not file_to_restore:
            raise MKUserError(None,
                              _("There is no WATO snapshot to be restored."))

        msg = _("Discarded pending changes (Restored %s)") % file_to_restore

        # All sites and domains can be affected by a restore: Better restart everything.
        _changes.add_change(
            "changes-discarded",
            msg,
            domains=ABCConfigDomain.enabled_domains(),
            need_restart=True,
        )

        self._extract_snapshot(file_to_restore)
        activate_changes.execute_activate_changes([
            d.get_domain_request([])
            for d in ABCConfigDomain.enabled_domains()
        ])

        for site_id in activation_sites():
            self.confirm_site_changes(site_id)

        build_index_background()

        make_header(
            html,
            self.title(),
            breadcrumb=self.breadcrumb(),
            show_body_start=display_options.enabled(display_options.H),
            show_top_heading=display_options.enabled(display_options.T),
        )
        html.open_div(class_="wato")

        html.show_message(_("Successfully discarded all pending changes."))
        html.javascript("hide_changes_buttons();")
        html.footer()
        return FinalizeRequest(code=200)
Esempio n. 18
0
    def _show_entry(self, entry: PageMenuEntry) -> None:
        classes = ["entry"]
        classes += self._get_entry_css_classes(entry)

        html.open_div(
            class_=classes,
            id_="menu_entry_%s" % entry.name if entry.name else None,
            title=entry.disabled_tooltip if not entry.is_enabled else None,
        )
        DropdownEntryRenderer().show(entry)
        html.close_div()
Esempio n. 19
0
    def page(self):
        html.open_div(class_="diag_host")
        html.open_table()
        html.open_tr()
        html.open_td()

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

        forms.header(_("Host Properties"))

        forms.section(legend=False)

        # The diagnose page shows both snmp variants at the same time
        # We need to analyse the preconfigured community and set either the
        # snmp_community or the snmp_v3_credentials
        vs_dict = {}
        for key, value in self._host.attributes().items():
            if key == "snmp_community" and isinstance(value, tuple):
                vs_dict["snmp_v3_credentials"] = value
                continue
            vs_dict[key] = value

        vs_host = self._vs_host()
        vs_host.render_input("vs_host", vs_dict)
        html.help(vs_host.help())

        forms.end()

        html.open_div(style="margin-bottom:10px")
        html.close_div()

        forms.header(_("Options"))

        value = {}
        forms.section(legend=False)
        vs_rules = self._vs_rules()
        vs_rules.render_input("vs_rules", value)
        html.help(vs_rules.help())
        forms.end()

        # When clicking "Save & Test" on the "Edit host" page, this will be set
        # to immediately execute the tests using the just saved settings
        if request.has_var("_start_on_load"):
            html.final_javascript("cmk.page_menu.form_submit('diag_host', '_save');")

        html.hidden_fields()
        html.end_form()

        html.close_td()
        html.open_td(style="padding-left:10px;")

        self._show_diagnose_output()
Esempio n. 20
0
    def display(self, value: FilterHTTPVariables) -> None:
        html.open_div(class_="multigroup")
        DualListChoice(choices=self._options(self.info),
                       rows=4,
                       enlarge_active=True).render_input(
                           self.query_filter.request_vars[0],
                           self.query_filter.selection(value))

        if self.query_filter.negateable:
            checkbox_component(self.query_filter.request_vars[1], value,
                               _("negate"))
        html.close_div()
Esempio n. 21
0
 def _get_mega_menu_content(self, menu_item: MainMenuItem) -> str:
     with output_funnel.plugged():
         menu = mega_menu_registry[menu_item.name]
         html.open_div(
             id_="popup_menu_%s" % menu_item.name,
             class_=(["popup_menu", "main_menu_popup"] +
                     (["min"] if user.get_attribute("nav_hide_icons_title")
                      else [])),
         )
         MegaMenuRenderer().show(menu)
         html.close_div()
         return output_funnel.drain()
Esempio n. 22
0
    def page(self) -> None:
        html.open_div(class_="rulesets")

        packed = self._packed_agents()
        if packed:
            self._download_table(_("Packaged Agents"), packed)

        titles = {
            "": _("Agents"),
            "/plugins": _("Plugins"),
            "/cfg_examples": _("Example Configurations"),
            "/cfg_examples/systemd": _("Example configuration for systemd"),
            "/windows": _("Windows Agent"),
            "/windows/plugins": _("Plugins"),
            "/windows/mrpe": _("Scripts to integrate Nagios plugis"),
            "/windows/cfg_examples": _("Example Configurations"),
            "/windows/ohm": _("OpenHardwareMonitor (headless)"),
            "/z_os": _("z/OS"),
            "/sap": _("SAP R/3"),
        }

        banned_paths = self._exclude_paths()

        other_sections = []
        for root, _dirs, files in os.walk(self._walk_base_dir()):
            file_paths = []
            relpath = root.split("agents")[1]
            if relpath in banned_paths:
                continue

            title = titles.get(relpath, relpath)
            for filename in files:
                rel_file_path = relpath + "/" + filename
                if rel_file_path in banned_paths:
                    continue

                if self._exclude_by_pattern(rel_file_path):
                    continue

                path = root + "/" + filename
                if path not in packed and "deprecated" not in path:
                    file_paths.append(path)

            other_sections.append((title, file_paths))

        for title, file_paths in sorted(other_sections):
            useful_file_paths = [
                p for p in file_paths if not p.endswith("/CONTENTS")
            ]
            if useful_file_paths:
                self._download_table(title, sorted(useful_file_paths))
        html.close_div()
Esempio n. 23
0
    def _show_view_as_dashlet(self, view_spec: ViewSpec):
        html.add_body_css_class("view")
        html.open_div(id_="dashlet_content_wrapper")

        is_reload = request.has_var("_reload")

        view_display_options = "SIXLW"
        if not is_reload:
            view_display_options += "HR"

        request.set_var("display_options", view_display_options)
        request.set_var("_display_options", view_display_options)
        html.add_body_css_class("dashlet")

        # Need to be loaded before processing the painter_options below.
        # TODO: Make this dependency explicit
        display_options.load_from_html(request, html)

        painter_options = PainterOptions.get_instance()
        painter_options.load(self._dashlet_spec["name"])

        # Here the linked view default context has the highest priority
        # linkedview default>dashlet>url active filter> dashboard. However views
        # have the "show_filters" default to prefill the filtermenu with empty
        # valued filters(UX). Those need to be cleared out. Otherwise those
        # empty filters are the highest priority filters and the user can never
        # filter the view.

        view_context = {
            filtername: filtervalues
            for filtername, filtervalues in view_spec["context"].items() if {
                var: value
                for var, value in filtervalues.items()
                # These are the filters request variables. Keep set values
                # For the TriStateFilters unset == ignore == "-1"
                # all other cases unset is an empty string
                if (var.startswith("is_") and value != "-1"
                    )  # TriState filters except ignore
                or (not var.startswith("is_") and value
                    )  # Rest of filters with some value
            }
        }
        context = visuals.get_merged_context(self.context, view_context)

        view = views.View(self._dashlet_spec["name"], view_spec, context)
        view.row_limit = views.get_limit()
        view.only_sites = visuals.get_only_sites_from_context(context)
        view.user_sorters = views.get_user_sorters()

        views.process_view(views.GUIViewRenderer(view, show_buttons=False))

        html.close_div()
Esempio n. 24
0
    def show(self):
        html.open_div(class_="mainmenu")
        for item in self._items:
            if not item.may_see():
                continue

            html.open_a(href=item.get_url(),
                        onfocus="if (this.blur) this.blur();")
            html.icon(item.icon, item.title)
            html.div(item.title, class_="title")
            html.div(item.description, class_="subtitle")
            html.close_a()

        html.close_div()
Esempio n. 25
0
    def update(self):
        import cmk.gui.sidebar as sidebar  # pylint: disable=import-outside-toplevel

        dashlet = self._dashlet_spec
        snapin = sidebar.snapin_registry.get(self._dashlet_spec["snapin"])
        if not snapin:
            raise MKUserError(None,
                              _("The configured element does not exist."))
        snapin_instance = snapin()

        html.browser_reload = self.refresh_interval()
        html.html_head(_("Sidebar element"))
        html.open_body(class_="side", data_theme=theme.get())
        html.open_div(id_="check_mk_sidebar")
        html.open_div(id_="side_content")
        html.open_div(id_="snapin_container_%s" % dashlet["snapin"],
                      class_="snapin")
        html.open_div(id_="snapin_%s" % dashlet["snapin"], class_="content")
        styles = snapin_instance.styles()
        if styles:
            html.style(styles)
        snapin_instance.show()
        html.close_div()
        html.close_div()
        html.close_div()
        html.close_div()
        html.body_end()
Esempio n. 26
0
    def page(self) -> cmk.gui.pages.PageResult:
        breadcrumb = make_simple_page_breadcrumb(
            mega_menu_registry["help_links"], _("Info"))
        make_header(
            html,
            self._title(),
            breadcrumb=breadcrumb,
        )

        html.open_div(id_="info_title")
        html.h1(_("Your monitoring machine"))
        html.a(
            HTMLWriter.render_img(theme.url("images/tribe29.svg")),
            "https://tribe29.com",
            target="_blank",
        )
        html.close_div()

        html.div(None, id_="info_underline")

        html.open_div(id_="info_intro_text")
        html.span(_("Open. Effective. Awesome."))
        html.span(
            _("May we present? Monitoring as it's supposed to be: "
              "incredibly quick to install, infinetely scalable, highly customizable and "
              "designed for admins."))
        html.span(
            _("Visit our %s to learn more about Checkmk and about the %s.") % (
                HTMLWriter.render_a(
                    _("website"), "https://checkmk.com", target="_blank"),
                HTMLWriter.render_a(
                    _("latest version"),
                    "https://checkmk.com/product/latest-version",
                    target="_blank",
                ),
            ))
        html.close_div()

        version_major_minor = re.sub(r".\d+$", "",
                                     Version(__version__).version_base)
        if version_major_minor:
            current_version_link = "https://checkmk.com/product/checkmk-%s" % version_major_minor
        else:
            current_version_link = "https://checkmk.com/product/latest-version"

        html.open_div(id="info_image")
        html.open_a(href=current_version_link, target="_blank")
        html.img(theme.url("images/monitoring-machine.png"))
        html.close_a()
        html.close_div()

        html.close_div()

        html.open_div(id_="info_footer")
        html.span(
            _("© %s tribe29 GmbH. All Rights Reserved.") % time.strftime("%Y"))
        html.a(_("License agreement"),
               href="https://checkmk.com/legal.html",
               target="_blank")
        html.close_div()
Esempio n. 27
0
    def _show_diagnose_output(self):
        if not request.var("_save"):
            html.show_message(
                _(
                    "You can diagnose the connection to a specific host using this dialog. "
                    "You can either test whether your current configuration is still working "
                    "or investigate in which ways a host can be reached. Simply configure the "
                    "connection options you like to try on the right side of the screen and "
                    'press the "Test" button. The results will be displayed here.'
                )
            )
            return

        if user_errors:
            html.show_user_errors()
            return

        # TODO: Insert any vs_host valuespec validation
        #       These tests can be called with invalid valuespec settings...
        # TODO: Replace hard coded icon paths with dynamic ones to old or new theme
        for ident, title in ModeDiagHost.diag_host_tests():
            html.h3(title)
            html.open_table(class_=["data", "test"])
            html.open_tr(class_=["data", "odd0"])

            html.open_td(class_="icons")
            html.open_div()
            html.icon("reload", id_="%s_img" % ident)
            html.open_a(href="")
            html.icon(
                "reload", title=_("Retry this test"), cssclass="retry", id_="%s_retry" % ident
            )
            html.close_a()
            html.close_div()
            html.close_td()

            html.open_td()
            html.div("", class_="log", id="%s_log" % ident)
            html.close_td()

            html.close_tr()
            html.close_table()
            html.javascript(
                "cmk.host_diagnose.start_test(%s, %s, %s)"
                % (
                    json.dumps(ident),
                    json.dumps(self._hostname),
                    json.dumps(transactions.fresh_transid()),
                )
            )
Esempio n. 28
0
def test_HTMLWriter(request_context):
    with output_funnel.plugged():

        with output_funnel.plugged():
            html.open_div()
            text = output_funnel.drain()
            assert text.rstrip("\n").rstrip(" ") == "<div>"

        with output_funnel.plugged():
            # html.open_div().write("test").close_div()
            html.open_div()
            html.write_text("test")
            html.close_div()
            assert compare_html(output_funnel.drain(), "<div>test</div>")

        with output_funnel.plugged():
            # html.open_table().open_tr().td("1").td("2").close_tr().close_table()
            html.open_table()
            html.open_tr()
            html.td("1")
            html.td("2")
            html.close_tr()
            html.close_table()
            assert compare_html(
                output_funnel.drain(),
                "<table><tr><td>1</td><td>2</td></tr></table>")

        with output_funnel.plugged():
            html.div("test", **{"</div>malicious_code<div>": "trends"})
            assert compare_html(
                output_funnel.drain(),
                "<div &lt;/div&gt;malicious_code&lt;div&gt;=trends>test</div>",
            )

        a = "\u2665"
        with output_funnel.plugged():
            assert HTMLWriter.render_a("test", href="www.test.case")
            HTMLWriter.render_a("test", href="www.test.case")
            HTMLWriter.render_a("test", href="www.test.case")
            HTMLWriter.render_a("test", href="www.test.case")
            try:
                assert HTMLWriter.render_a(
                    "test",
                    href=str("www.test.case"),
                    id_=str("something"),
                    class_=str("test_%s") % a,
                )
            except Exception as e:
                traceback.print_exc()
                print(e)
Esempio n. 29
0
    def _show_form(self) -> None:
        assert user.id is not None

        users = userdb.load_users()

        user_spec: Optional[UserSpec] = users.get(user.id)
        if user_spec is None:
            html.show_warning(_("Sorry, your user account does not exist."))
            html.footer()
            return

        html.begin_form("profile", method="POST")
        html.prevent_password_auto_completion()
        html.open_div(class_="wato")
        forms.header(_("Personal settings"))

        forms.section(_("Username"), simple=True)
        html.write_text(user_spec.get("user_id", user.id))

        forms.section(_("Full name"), simple=True)
        html.write_text(user_spec.get("alias", ""))

        select_language(user_spec)

        # Let the user configure how he wants to be notified
        rulebased_notifications = rulebased_notifications_enabled()
        if (not rulebased_notifications
                and user.may("general.edit_notifications")
                and user_spec.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."))
            get_vs_flexible_notifications().render_input(
                "notification_method", user_spec.get("notification_method"))

        if user.may("general.edit_user_attributes"):
            custom_user_attr_topics = get_user_attributes_by_topic()
            _show_custom_user_attr(user_spec,
                                   custom_user_attr_topics.get("personal", []))
            forms.header(_("User interface settings"))
            _show_custom_user_attr(
                user_spec, custom_user_attr_topics.get("interface", []))

        forms.end()
        html.close_div()
        html.hidden_fields()
        html.end_form()
        html.footer()
Esempio n. 30
0
def render_unacknowleged_werks():
    werks = unacknowledged_incompatible_werks()
    if werks and not 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()