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
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()
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']]
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()
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
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()
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
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 </div>malicious_code<div>=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)
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()
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
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(" ") 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()
def get_availability_options_from_url(what): # type: (AVObjectType) -> AVOptions with html.plugged(): avoptions = render_availability_options(what) html.drain() return avoptions
def _render_filter_form(self) -> str: with html.plugged(): self._display_audit_log_options() return html.drain()
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()
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>")
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
def render(self): with html.plugged(): self._show_tree() return html.drain()
def _gen_leaf(self, tree, height, show_host): with html.plugged(): self._show_leaf(tree, show_host) content = HTML(html.drain()) return [(content, height, [])]
def _render_dropdown_area(self, dropdown: PageMenuDropdown) -> str: with html.plugged(): self._show_dropdown_area(dropdown) return html.drain()
def get_availability_options_from_url(what): with html.plugged(): avoptions = render_availability_options(what) html.drain() return avoptions
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 <script>alert(1)</script> <br> <b></div>"