Example #1
0
def test_context(register_builtin_html):
    table_id = 0
    rows = [(i, i**3) for i in range(10)]
    header = ["Number", "Cubical"]

    with html.plugged():
        with table_element(table_id="%d" % table_id,
                           searchable=False,
                           sortable=False) as table:
            for row in rows:
                table.row()
                for h, r in zip(header, row):
                    table.cell(_(h), r)

        written_text = "".join(html.drain())
    data = read_out_simple_table(written_text)
    assert data.pop(0) == header
    data = [tuple(map(int, row)) for row in data if row and row[0]]
    assert data == rows
Example #2
0
    def _render_bulk_move_form(self) -> str:
        with html.plugged():
            choices = self._folder.choices_for_moving_host()
            if not choices:
                return ""

            choices.insert(0, ("@", _("(select target folder)")))

            html.dropdown(
                "_bulk_moveto",
                choices,
                deflt="@",
                label=_("Move to folder:"),
                onchange="cmk.selection.update_bulk_moveto(this.value)",
                class_='bulk_moveto',
                form="form_hosts")
            html.button("_bulk_move", _("Move"), form="form_hosts")

            return html.drain()
Example #3
0
def test_plug(register_builtin_html):
    table_id = 0
    title = " TEST "

    with html.plugged():
        with table_element("%d" % table_id, title, searchable=False, sortable=False) as table:
            table.row()
            table.cell("A", "1")
            html.write("a")
            table.cell("B", "2")
            html.write("b")
            table.row()
            table.cell("A", "1")
            html.write("a")
            table.cell("C", "4")
            html.write("c")

        written_text = "".join(html.drain())
    assert read_out_simple_table(written_text) == [[u'A', u'B'], [u'1a', u'2b'], [u'1a', u'4c']]
Example #4
0
    def _render_tooltip(cls, title: str, parts: List[Part], total_part: Part) -> str:
        with html.plugged():
            html.h3(title)
            html.open_table()
            for part in parts:
                html.open_tr()
                html.td("", class_="color", style="background-color:%s" % part.color)
                html.td(str(part.count), class_="count")
                html.td(part.title, class_="title")
                html.close_tr()

            html.open_tr()
            html.td("", class_="color")
            html.td(str(total_part.count), class_="count")
            html.td(total_part.title, class_="title")
            html.close_tr()

            html.close_table()
            return html.drain()
Example #5
0
 def render(self, query: str) -> str:
     results = self._generate_results(query)
     with html.plugged():
         for topic, search_results in results.items():
             html.open_div(id_=topic, class_="topic")
             self._render_topic(topic)
             html.open_ul()
             for result in list(
                     search_results)[:self._max_num_displayed_results]:
                 self._render_result(result)
             # TODO: Remove this as soon as the index search does limit its search results
             if len(list(
                     search_results)) >= self._max_num_displayed_results:
                 html.div(content=_(
                     f"Showing only first {self._max_num_displayed_results} results."
                 ))
             html.close_ul()
             html.close_div()
         html.div(None, class_=["topic", "sentinel"])
         html_text = html.drain()
     return html_text
Example #6
0
    def _get_tooltip(cls, host_name: HostName, service_description: str,
                     alert_stats: AlertStats) -> str:
        with html.plugged():
            if service_description:
                html.h3(f"{host_name} - {service_description}")
            else:
                html.h3(host_name)

            html.open_table()
            for title, count in [
                (_("Problems in total"), alert_stats.num_problems),
                (_("Critical"), alert_stats.num_crit),
                (_("Unknown"), alert_stats.num_unknown),
                (_("Warning"), alert_stats.num_warn),
            ]:
                html.open_tr()
                html.td(str(count), class_="count")
                html.td(title, class_="title")
                html.close_tr()

            html.close_table()
            return html.drain()
Example #7
0
    def render(self, row, cell):
        single_url = "view.py?" + html.urlencode_vars([("view_name", "aggr_single"),
                                                       ("aggr_name", row["aggr_name"])])
        avail_url = single_url + "&mode=availability"

        with html.plugged():
            html.icon_button(single_url, _("Show only this aggregation"), "showbi")
            html.icon_button(avail_url, _("Analyse availability of this aggregation"),
                             "availability")
            if row["aggr_effective_state"]["in_downtime"] != 0:
                html.icon(
                    _("A service or host in this aggregation is in downtime."), "derived_downtime")
            if row["aggr_effective_state"]["acknowledged"]:
                html.icon(
                    _("The critical problems that make this aggregation non-OK have been acknowledged."
                     ), "ack")
            if not row["aggr_effective_state"]["in_service_period"]:
                html.icon(
                    _("This aggregation is currently out of its service period."),
                    "outof_serviceperiod")
            code = html.drain()
        return "buttons", code
Example #8
0
def test_ABCHTMLGenerator(register_builtin_html):
    with html.plugged():

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

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

        with html.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(
                html.drain(), "<table><tr><td>1</td><td>2</td></tr></table>")

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

        a = u"\u2665"
        with html.plugged():
            assert html.render_a("test", href="www.test.case")
            html.render_a(u"test", href="www.test.case")
            html.render_a("test", href=u"www.test.case")
            html.render_a(u"test", href=u"www.test.case")
            try:
                assert html.render_a(u"test",
                                     href=six.text_type("www.test.case"),
                                     id_=six.text_type("something"),
                                     class_=six.text_type("test_%s") % a)
            except Exception as e:
                traceback.print_exc()
                print(e)
Example #9
0
def table_element(
    table_id: Optional[str] = None,
    title: 'HTMLContent' = None,
    searchable: bool = True,
    sortable: bool = True,
    foldable: bool = False,
    limit: Union[None, int, Literal[False]] = None,
    output_format: str = "html",
    omit_if_empty: bool = False,
    omit_empty_columns: bool = False,
    omit_headers: bool = False,
    omit_update_header: bool = False,
    empty_text: Optional[str] = None,
    help: Optional[str] = None,  # pylint: disable=redefined-builtin
    css: Optional[str] = None,
) -> Iterator['Table']:
    with html.plugged():
        table = Table(table_id=table_id,
                      title=title,
                      searchable=searchable,
                      sortable=sortable,
                      foldable=foldable,
                      limit=limit,
                      output_format=output_format,
                      omit_if_empty=omit_if_empty,
                      omit_empty_columns=omit_empty_columns,
                      omit_headers=omit_headers,
                      omit_update_header=omit_update_header,
                      empty_text=empty_text,
                      help=help,
                      css=css)
        try:
            yield table
        finally:
            table._finish_previous()
            table._end()
Example #10
0
 def _render_results(self, results: SearchResultsByTopic) -> str:
     with html.plugged():
         for topic, search_results in results:
             html.open_div(id_=topic, class_="topic")
             self._render_topic(topic)
             html.open_ul()
             for count, result in enumerate(list(search_results)):
                 self._render_result(
                     result,
                     hidden=count >= self._max_num_displayed_results)
             # TODO: Remove this as soon as the index search does limit its search results
             if len(list(
                     search_results)) >= self._max_num_displayed_results:
                 html.input(
                     name="show_all_results",
                     value=_("Show all results"),
                     type_="button",
                     onclick=
                     f"cmk.search.on_click_show_all_results('{topic}');")
             html.close_ul()
             html.close_div()
         html.div(None, class_=["topic", "sentinel"])
         html_text = html.drain()
     return html_text
Example #11
0
def render_bi_availability(title, aggr_rows):
    # type: (Text, Rows) -> None
    config.user.need_permission("general.see_availability")

    av_mode = html.request.get_ascii_input_mandatory("av_mode", "availability")
    avoptions = get_availability_options_from_url("bi")
    if av_mode == "timeline":
        title = _("Timeline of") + " " + title
    else:
        title = _("Availability of") + " " + title

    if html.output_format != "csv_export":
        html.body_start(title)
        html.top_heading(title)
        html.begin_context_buttons()
        html.toggle_button("avoptions", False, "painteroptions",
                           _("Configure details of the report"))
        html.context_button(_("Status View"),
                            html.makeuri([("mode", "status")]), "status")
        if config.reporting_available() and config.user.may(
                "general.reporting"):
            html.context_button(_("Export as PDF"),
                                html.makeuri([], filename="report_instant.py"),
                                "report")
        if config.user.may("general.csv_export"):
            html.context_button(
                _("Export as CSV"),
                html.makeuri([("output_format", "csv_export")]),
                "download_csv")

        if av_mode == "timeline":
            html.context_button(_("Availability"),
                                html.makeuri([("av_mode", "availability")]),
                                "availability")

        elif len(aggr_rows) == 1:
            aggr_name = aggr_rows[0]["aggr_name"]
            aggr_group = aggr_rows[0]["aggr_group"]
            timeline_url = html.makeuri([("av_mode", "timeline"),
                                         ("av_aggr_name", aggr_name),
                                         ("av_aggr_group", aggr_group)])
            html.context_button(_("Timeline"), timeline_url, "timeline")
        html.end_context_buttons()

        avoptions = render_availability_options("bi")

    if not html.has_user_errors():
        logrow_limit = avoptions["logrow_limit"]
        if logrow_limit == 0:
            livestatus_limit = None
        else:
            livestatus_limit = (len(aggr_rows) * logrow_limit)

        spans = []  # type: List[AVSpan]

        # iterate all aggregation rows
        timewarpcode = HTML()
        timewarp = html.request.get_integer_input("timewarp")

        has_reached_logrow_limit = False
        timeline_containers, fetched_rows = availability.get_timeline_containers(
            aggr_rows, avoptions, timewarp,
            livestatus_limit + 1 if livestatus_limit is not None else None)
        if livestatus_limit and fetched_rows > livestatus_limit:
            has_reached_logrow_limit = True

        for timeline_container in timeline_containers:
            tree = timeline_container.aggr_tree
            these_spans = timeline_container.timeline
            timewarp_tree_state = timeline_container.timewarp_state

            spans += these_spans

            # render selected time warp for the corresponding aggregation row (should be matched by only one)
            if timewarp and timewarp_tree_state:
                state, assumed_state, node, _subtrees = timewarp_tree_state
                eff_state = state
                if assumed_state is not None:
                    eff_state = assumed_state
                row = {
                    "aggr_tree": tree,
                    "aggr_treestate": timewarp_tree_state,
                    "aggr_state": state,  # state disregarding assumptions
                    "aggr_assumed_state":
                    assumed_state,  # is None, if there are no assumptions
                    "aggr_effective_state":
                    eff_state,  # is assumed_state, if there are assumptions, else real state
                    "aggr_name": node["title"],
                    "aggr_output": eff_state["output"],
                    "aggr_hosts": node["reqhosts"],
                    "aggr_function": node["func"],
                    "aggr_group": html.request.var("aggr_group"),
                }

                renderer = bi.FoldableTreeRendererTree(
                    row,
                    omit_root=False,
                    expansion_level=config.user.bi_expansion_level,
                    only_problems=False,
                    lazy=False)
                tdclass, htmlcode = renderer.css_class(), renderer.render()

                with html.plugged():
                    # TODO: SOMETHING IS WRONG IN HERE (used to be the same situation in original code!)
                    # FIXME: WHAT is wrong in here??

                    html.open_h3()
                    # render icons for back and forth
                    button_back_shown = False
                    button_forth_shown = False
                    if int(these_spans[0]["from"]) == timewarp:
                        html.disabled_icon_button("back_off")
                        button_back_shown = True

                    previous_span = None
                    for span in these_spans:
                        if not button_back_shown and int(
                                span["from"]
                        ) == timewarp and previous_span is not None:
                            html.icon_button(
                                html.makeuri([("timewarp",
                                               str(int(previous_span["from"])))
                                              ]), _("Jump one phase back"),
                                "back")
                            button_back_shown = True
                        # Multiple followup spans can have the same "from" time
                        # We only show one forth-arrow with an actual time difference
                        elif not button_forth_shown and previous_span and int(
                                previous_span["from"]) == timewarp and int(
                                    span["from"]) != timewarp:
                            html.icon_button(
                                html.makeuri([("timewarp",
                                               str(int(span["from"])))]),
                                _("Jump one phase forth"), "forth")
                            button_forth_shown = True
                        previous_span = span
                    if not button_forth_shown:
                        html.disabled_icon_button("forth_off")

                    html.write_text(" &nbsp; ")
                    html.icon_button(html.makeuri([("timewarp", "")]),
                                     _("Close Timewarp"), "closetimewarp")
                    html.write_text("%s %s" %
                                    (_("Timewarp to "),
                                     time.strftime("%Y-%m-%d %H:%M:%S",
                                                   time.localtime(timewarp))))
                    html.close_h3()

                    html.open_table(class_=["data", "table", "timewarp"])
                    html.open_tr(class_=["data", "odd0"])
                    html.open_td(class_=tdclass)
                    html.write_html(htmlcode)
                    html.close_td()
                    html.close_tr()
                    html.close_table()

                    timewarpcode += html.drain()

        # Note: 'spans_by_object' returns two arguments which are used by
        # all availability views but not by BI. There we have to take
        # only complete aggregations
        av_rawdata = availability.spans_by_object(spans, None)[0]
        av_data = availability.compute_availability("bi", av_rawdata,
                                                    avoptions)

        # If we abolish the limit we have to fetch the data again
        # with changed logrow_limit = 0, which means no limit
        if has_reached_logrow_limit:
            text = _(
                "Your query matched more than %d log entries. "
                "<b>Note:</b> The shown data does not necessarily reflect the "
                "matched entries and the result might be incomplete. "
            ) % avoptions["logrow_limit"]
            text += html.render_a(_('Repeat query without limit.'),
                                  html.makeuri([("_unset_logrow_limit", "1")]))
            html.show_warning(text)

        if html.output_format == "csv_export" and config.user.may(
                "general.csv_export"):
            _output_csv("bi", av_mode, av_data, avoptions)
            return

        html.write(timewarpcode)
        do_render_availability("bi", av_rawdata, av_data, av_mode, None,
                               avoptions)

    html.bottom_footer()
    html.body_end()
Example #12
0
def get_availability_options_from_url(what):
    # type: (AVObjectType) -> AVOptions
    with html.plugged():
        avoptions = render_availability_options(what)
        html.drain()
    return avoptions
Example #13
0
 def _render_filter_form(self) -> str:
     with html.plugged():
         self._display_audit_log_options()
         return html.drain()
Example #14
0
def render_availability_page(view, filterheaders):
    # type: (View, FilterHeaders) -> None
    config.user.need_permission("general.see_availability")

    if handle_edit_annotations():
        return

    # We make reports about hosts, services or BI aggregates
    if "service" in view.datasource.infos:
        what = "service"
    elif "aggr_name" in view.datasource.infos:
        what = "bi"
    else:
        what = "host"

    avoptions = get_availability_options_from_url(what)
    time_range, range_title = avoptions["range"]

    # We have two display modes:
    # - Show availability table (stats) "table"
    # - Show timeline                   "timeline"
    # --> controlled by URL variable "av_mode"
    av_mode = html.request.get_ascii_input_mandatory("av_mode", "table")

    if av_mode == "timeline":
        title = _("Availability Timeline")
    else:
        title = _("Availability")

    # This is combined with the object selection
    # - Show all objects
    # - Show one specific object
    # --> controlled by URL variables "av_site", "av_host" and "av_service"
    # --> controlled by "av_aggr" in case of BI aggregate
    title += " - "
    av_object = None  # type: AVObjectSpec
    if html.request.var("av_host"):
        av_object = (html.request.get_str_input_mandatory("av_site"),
                     html.request.get_str_input_mandatory("av_host"),
                     html.request.get_unicode_input_mandatory("av_service"))
        title += av_object[1]
        if av_object[2]:
            title += " - " + av_object[2]
    elif html.request.var("av_aggr"):
        av_object = (None, None,
                     html.request.get_unicode_input_mandatory("av_aggr"))
        title += av_object[2]
    else:
        title += view_title(view.spec)

    # Deletion must take place before computation, since it affects the outcome
    with html.plugged():
        handle_delete_annotations()
        confirmation_html_code = html.drain()

    # Now compute all data, we need this also for CSV export
    if not html.has_user_errors():
        include_long_output = av_mode == "timeline" \
                and "timeline_long_output" in avoptions["labelling"]
        av_rawdata, has_reached_logrow_limit = availability.get_availability_rawdata(
            what,
            view.context,
            filterheaders,
            view.only_sites,
            av_object=av_object,
            include_output=av_mode == "timeline",
            include_long_output=include_long_output,
            avoptions=avoptions)
        av_data = availability.compute_availability(what, av_rawdata,
                                                    avoptions)

    # Do CSV ouput
    if html.output_format == "csv_export" and config.user.may(
            "general.csv_export"):
        _output_csv(what, av_mode, av_data, avoptions)
        return

    title += " - " + range_title

    if display_options.enabled(display_options.H):
        html.body_start(title, force=True)

    if display_options.enabled(display_options.T):
        html.top_heading(title)

    html.write(confirmation_html_code)

    # Remove variables for editing annotations, otherwise they will make it into the uris
    html.request.del_vars("anno_")
    if html.request.var("filled_in") == "editanno":
        html.request.del_var("filled_in")

    if display_options.enabled(display_options.B):
        html.begin_context_buttons()
        html.toggle_button(
            "avoptions",
            html.has_user_errors(),
            "painteroptions",
            _("Configure details of the report"),
        )
        html.context_button(
            _("Status View"),
            html.makeuri([("mode", "status")]),
            "status",
        )
        if config.reporting_available() and config.user.may(
                "general.reporting"):
            html.context_button(
                _("Export as PDF"),
                html.makeuri([], filename="report_instant.py"),
                "report",
            )

        if config.user.may("general.csv_export"):
            html.context_button(
                _("Export as CSV"),
                html.makeuri([("output_format", "csv_export")]),
                "download_csv",
            )

        if av_mode == "timeline" or av_object:
            html.context_button(
                _("Availability"),
                html.makeuri([("av_mode", "availability"), ("av_host", ""),
                              ("av_aggr", "")]),
                "availability",
            )
        elif not av_object:
            html.context_button(
                _("Timeline"),
                html.makeuri([("av_mode", "timeline")]),
                "timeline",
            )
        elif av_mode == "timeline" and what != "bi":
            history_url = availability.history_url_of(av_object, time_range)
            html.context_button(
                _("History"),
                history_url,
                "history",
            )

        html.end_context_buttons()

    # Render the avoptions again to get the HTML code, because the HTML vars have changed
    # above (anno_ and editanno_ has been removed, which must not be part of the form
    avoptions = render_availability_options(what)

    if not html.has_user_errors():
        # If we abolish the limit we have to fetch the data again
        # with changed logrow_limit = 0, which means no limit
        if has_reached_logrow_limit:
            text = _(
                "Your query matched more than %d log entries. "
                "<b>Note:</b> The number of shown rows does not necessarily reflect the "
                "matched entries and the result might be incomplete. "
            ) % avoptions["logrow_limit"]
            text += html.render_a(
                _('Repeat query without limit.'),
                html.makeuri([("_unset_logrow_limit", "1"),
                              ("avo_logrow_limit", 0)]))
            html.show_warning(text)

        do_render_availability(what, av_rawdata, av_data, av_mode, av_object,
                               avoptions)

    if display_options.enabled(display_options.Z):
        html.bottom_footer()

    if display_options.enabled(display_options.H):
        html.body_end()
Example #15
0
def test_multiclass_call(register_builtin_html):
    with html.plugged():
        html.div('', class_="1", css="3", cssclass="4", **{"class": "2"})
        written_text = "".join(html.drain())
    assert compare_html(written_text, "<div class=\"1 3 4 2\"></div>")
Example #16
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
Example #17
0
 def render(self):
     with html.plugged():
         self._show_tree()
         return html.drain()
Example #18
0
 def _gen_leaf(self, tree, height, show_host):
     with html.plugged():
         self._show_leaf(tree, show_host)
         content = HTML(html.drain())
     return [(content, height, [])]
Example #19
0
 def _render_dropdown_area(self, dropdown: PageMenuDropdown) -> str:
     with html.plugged():
         self._show_dropdown_area(dropdown)
         return html.drain()
Example #20
0
def get_availability_options_from_url(what):
    with html.plugged():
        avoptions = render_availability_options(what)
        html.drain()
    return avoptions
Example #21
0
def test_user_error(register_builtin_html):
    with html.plugged():
        html.user_error(
            MKUserError(None, "asd <script>alert(1)</script> <br> <b>"))
        c = html.drain()
    assert c == "<div class=\"error\">asd &lt;script&gt;alert(1)&lt;/script&gt; <br> <b></div>"