def test_text_input(request_context): with output_funnel.plugged(): html.text_input("tralala") written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="tralala" type="text" class="text" value=\'\' />' ) with output_funnel.plugged(): html.text_input("blabla", cssclass="blubb") written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="tralala" type="text" class="blubb" value=\'\' />' ) with output_funnel.plugged(): html.text_input("blabla", autocomplete="yep") written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="blabla" autocomplete="yep" type="text" class="text" value=\'\' />', ) with output_funnel.plugged(): html.text_input("blabla", placeholder="placido", data_world="welt", data_max_labels=42) written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="tralala" type="text" class="text" value=\'\' />' )
def test_text_input(register_builtin_html): with output_funnel.plugged(): html.text_input('tralala') written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="tralala" type="text" class="text" value=\'\' />' ) with output_funnel.plugged(): html.text_input('blabla', cssclass='blubb') written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="tralala" type="text" class="blubb" value=\'\' />' ) with output_funnel.plugged(): html.text_input('blabla', autocomplete='yep') written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="blabla" autocomplete="yep" type="text" class="text" value=\'\' />' ) with output_funnel.plugged(): html.text_input('blabla', placeholder='placido', data_world='welt', data_max_labels=42) written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '<input style="" name="tralala" type="text" class="text" value=\'\' />' )
def test_ABCHTMLGenerator(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 </div>malicious_code<div>=trends>test</div>", ) a = "\u2665" with output_funnel.plugged(): assert html.render_a("test", href="www.test.case") html.render_a("test", href="www.test.case") html.render_a("test", href="www.test.case") html.render_a("test", href="www.test.case") try: assert html.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)
def render(self, row: Row, cell: Cell) -> CellSpec: single_url = "view.py?" + urlencode_vars( [("view_name", "aggr_single"), ("aggr_name", row["aggr_name"])]) avail_url = single_url + "&mode=availability" bi_map_url = "bi_map.py?" + urlencode_vars([ ("aggr_name", row["aggr_name"]), ]) with output_funnel.plugged(): html.icon_button(bi_map_url, _("Visualize this aggregation"), "aggr") 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( "derived_downtime", _("A service or host in this aggregation is in downtime.")) if row["aggr_effective_state"]["acknowledged"]: html.icon( "ack", _("The critical problems that make this aggregation non-OK have been acknowledged." ), ) if not row["aggr_effective_state"]["in_service_period"]: html.icon( "outof_serviceperiod", _("This aggregation is currently out of its service period." ), ) code = HTML(output_funnel.drain()) return "buttons", code
def _add_cell( self, title: 'HTMLContent' = "", text: 'HTMLContent' = "", css: 'CSSSpec' = None, help_txt: Optional[str] = None, colspan: Optional[int] = None, sortable: bool = True, ): if isinstance(text, HTML): content = text else: content = escape_html_permissive(str(text) if not isinstance(text, str) else text) htmlcode: HTML = content + HTML(output_funnel.drain()) if isinstance(title, HTML): header_title = title else: if title is None: title = "" header_title = escape_html_permissive( str(title) if not isinstance(title, str) else title) if self.options["collect_headers"] is True: # small helper to make sorting introducion easier. Cells which contain # buttons are never sortable if css and 'buttons' in css and sortable: sortable = False self.headers.append( TableHeader(title=header_title, css=css, help_txt=help_txt, sortable=sortable)) current_row = self.rows[-1] assert isinstance(current_row, TableRow) current_row.cells.append(CellSpec(htmlcode, css, colspan))
def test_table_cubical(register_builtin_html, monkeypatch, sortable, searchable, limit, output_format): # TODO: Better mock the access to save_user in table.* def save_user_mock(name, data, user, unlock=False): pass import cmk.gui.config as config # pylint: disable=bad-option-value,import-outside-toplevel monkeypatch.setattr(config, "save_user_file", save_user_mock) # Test data rows = [(i, i**3) for i in range(10)] header = ["Number", "Cubical"] # Table options table_id = 0 title = " TEST " separator = ';' html.request.set_var('_%s_sort' % table_id, "1,0") html.request.set_var('_%s_actions' % table_id, '1') def _render_table(): with table_element(table_id="%d" % table_id, title=title, sortable=sortable, searchable=searchable, limit=limit, output_format=output_format) as table: for row in rows: table.row() for h, r in zip(header, row): table.cell(_(h), r) # Data assertions assert output_format in ['html', 'csv'], 'Fetch is not yet implemented' if output_format == 'html': with output_funnel.plugged(): _render_table() written_text = "".join(output_funnel.drain()) data = read_out_simple_table(written_text) assert data.pop(0) == header, 'Wrong header' elif output_format == 'csv': _render_table() data = read_out_csv(response.get_data(as_text=True), separator) limit = len(data) assert data.pop(0) == header, 'Wrong header' else: raise Exception('Not yet implemented') # Reconstruct table data data = [tuple(map(int, row)) for row in data if row and row[0]] if limit is None: limit = len(rows) # Assert data correctness assert len( data) <= limit, 'Wrong number of rows: Got %s, should be <= %s' % ( len(data), limit) assert data == rows[:limit], "Incorrect data: %s\n\nVS\n%s" % ( data, rows[:limit])
def page(self): if not user.may("general.configure_sidebar"): raise MKGeneralException( _("You are not allowed to change the sidebar.")) addname = request.var("name") if addname is None or addname not in snapin_registry: raise MKUserError(None, _("Invalid sidebar element %s") % addname) if addname in _used_snapins(): raise MKUserError(None, _("Element %s is already enabled") % addname) user_config = UserSidebarConfig(user, config.sidebar) snapin = UserSidebarSnapin.from_snapin_type_id(addname) user_config.add_snapin(snapin) user_config.save() with output_funnel.plugged(): try: url = SidebarRenderer().render_snapin(snapin) finally: snapin_code = output_funnel.drain() return { "name": addname, "url": url, "content": snapin_code, "refresh": snapin.snapin_type.refresh_regularly(), "restart": snapin.snapin_type.refresh_on_restart(), }
def test_nesting_context(register_builtin_html): table_id = 0 title = " TEST " with output_funnel.plugged(): with table_element(table_id="%d" % table_id, title=title, searchable=False, sortable=False) as table1: table1.row() table1.cell("A", "1") table1.cell("B", "") with table_element("%d" % (table_id + 1), title + "2", searchable=False, sortable=False) as table2: table2.row() table2.cell("_", "+") table2.cell("|", "-") written_text = "".join(output_funnel.drain()) assert compare_html( written_text, '''<h3 class="table"> TEST </h3> <script type="text/javascript">\ncmk.utils.update_row_info(\'1 row\');\n</script> <table class="data oddeven"> <tr> <th> A </th> <th> B </th> </tr> <tr class="data even0"> <td> 1 </td> <td> <h3 class="table"> TEST 2</h3> <script type="text/javascript">\ncmk.utils.update_row_info(\'1 row\');\n</script> <table class="data oddeven"> <tr><th>_</th><th>|</th></tr> <tr class="data even0"><td>+</td><td>-</td></tr> </table> </td> </tr> </table>'''), written_text
def test_table_cubical(request_context, monkeypatch, sortable, searchable, limit, output_format): monkeypatch.setattr(LoggedInNobody, "save_tableoptions", lambda s: None) # Test data rows = [(i, i**3) for i in range(10)] header = ["Number", "Cubical"] # Table options table_id = 0 title = " TEST " separator = ";" html.request.set_var("_%s_sort" % table_id, "1,0") html.request.set_var("_%s_actions" % table_id, "1") def _render_table(): with table_element( table_id="%d" % table_id, title=title, sortable=sortable, searchable=searchable, limit=limit, output_format=output_format, ) as table: for row in rows: table.row() for h, r in zip(header, row): table.cell(_(h), r) # Data assertions assert output_format in ["html", "csv"], "Fetch is not yet implemented" if output_format == "html": with output_funnel.plugged(): _render_table() written_text = "".join(output_funnel.drain()) data = read_out_simple_table(written_text) assert data.pop(0) == header, "Wrong header" elif output_format == "csv": _render_table() data = read_out_csv(response.get_data(as_text=True), separator) limit = len(data) assert data.pop(0) == header, "Wrong header" else: raise Exception("Not yet implemented") # Reconstruct table data data = [tuple(map(int, row)) for row in data if row and row[0]] if limit is None: limit = len(rows) # Assert data correctness assert len( data) <= limit, "Wrong number of rows: Got %s, should be <= %s" % ( len(data), limit) assert data == rows[:limit], "Incorrect data: %s\n\nVS\n%s" % ( data, rows[:limit])
def test_show_user_errors(register_builtin_html): assert not user_errors user_errors.add(MKUserError(None, "asd <script>alert(1)</script> <br> <b>")) assert user_errors with output_funnel.plugged(): html.show_user_errors() c = output_funnel.drain() assert c == "<div class=\"error\">asd <script>alert(1)</script> <br> <b></div>"
def test_show_user_errors(request_context): assert not user_errors user_errors.add(MKUserError(None, "asd <script>alert(1)</script> <br> <b>")) assert user_errors with output_funnel.plugged(): html.show_user_errors() c = output_funnel.drain() assert c == '<div class="error">asd <script>alert(1)</script> <br> <b></div>'
def page(self) -> AjaxPageResult: with output_funnel.plugged(): api_request = request.get_request() job_snapshot = self._show_details_page(api_request["job_id"]) content = output_funnel.drain() return { "status_container_content": content, "is_finished": job_snapshot and not job_snapshot.is_active(), }
def test_cell_title_escaping(request_context): with output_funnel.plugged(): with table_element("ding", "TITLE", searchable=False, sortable=False) as table: table.row() table.cell("<script>alert('A')</script>") table.cell(HTML("<script>alert('B')</script>")) table.cell("<b>C</b>") written_text = output_funnel.drain() assert "<script>alert('A')</script>" in written_text assert "<script>alert('B')</script>" in written_text assert "<b>C</b>" in written_text
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 config.user.get_attribute("nav_hide_icons_title") else None, ]) MegaMenuRenderer().show(menu) html.close_div() return output_funnel.drain()
def ajax_snapin(): """Renders and returns the contents of the requested sidebar snapin(s) in JSON format""" response.set_content_type("application/json") user_config = UserSidebarConfig(user, config.sidebar) snapin_id = request.var("name") snapin_ids = ([snapin_id] if snapin_id else request.get_str_input_mandatory("names", "").split(",")) snapin_code: List[str] = [] for snapin_id in snapin_ids: try: snapin_instance = user_config.get_snapin(snapin_id).snapin_type() except KeyError: continue # Skip not existing snapins if not snapin_instance.may_see(): continue # When restart snapins are about to be refreshed, only render # them, when the core has been restarted after their initial # rendering if not snapin_instance.refresh_regularly( ) and snapin_instance.refresh_on_restart(): since = request.get_float_input_mandatory("since", 0) newest = since for site in sites.states().values(): prog_start = site.get("program_start", 0) if prog_start > newest: newest = prog_start if newest <= since: # no restart snapin_code.append("") continue with output_funnel.plugged(): try: snapin_instance.show() except Exception as e: write_snapin_exception(e) e_message = ( _("Exception during element refresh (element '%s')") % snapin_instance.type_name()) logger.error("%s %s: %s", request.requested_url, e_message, traceback.format_exc()) finally: snapin_code.append(output_funnel.drain()) response.set_data(json.dumps(snapin_code))
def test_foldable_container(register_builtin_html) -> None: with output_funnel.plugged(): with foldable_container(treename="name", id_="id", isopen=False, title="Title") as is_open: assert is_open is False code = output_funnel.drain() assert compare_html( code, '''<div class="foldable closed"><b onclick="cmk.foldable_container.toggle("name", "id", "")" class="treeangle title">Title</b><img id="treeimg.name.id" onclick="cmk.foldable_container.toggle("name", "id", "")" src="themes/facelift/images/tree_closed.svg" class="treeangle closed" /><br/><ul id="tree.name.id" style="padding-left: 15px; " class="treeangle closed"></ul></div>''')
def _render_werk_options_form(werk_table_options: Dict[str, Any]) -> HTML: with output_funnel.plugged(): html.begin_form("werks") html.hidden_field("wo_set", "set") _show_werk_options_controls() html.open_div(class_="side_popup_content") for name, height, vs, _default_value in _werk_table_option_entries(): html.render_floating_option(name, height, "wo_", vs, werk_table_options[name]) html.close_div() html.hidden_fields() html.end_form() return HTML(output_funnel.drain())
def render_graph_html(graph_artwork, graph_data_range, graph_render_options) -> HTML: graph_render_options = artwork.add_default_render_options( graph_render_options) with output_funnel.plugged(): _show_graph_html_content(graph_artwork, graph_data_range, graph_render_options) html_code = HTML(output_funnel.drain()) return html.render_javascript( 'cmk.graphs.create_graph(%s, %s, %s, %s);' % (json.dumps(html_code), json.dumps(graph_artwork), json.dumps(graph_render_options), json.dumps( graph_ajax_context(graph_artwork, graph_data_range, graph_render_options))))
def render_werk_description(werk) -> HTML: with output_funnel.plugged(): html.open_p() in_list = False in_code = False for line in werk["body"]: if line.startswith("LI:"): if not in_list: html.open_ul() in_list = True html.li(line[3:]) else: if in_list: html.close_ul() in_list = False if line.startswith("H2:"): html.h3(line[3:]) elif line.startswith("C+:"): html.open_pre(class_="code") in_code = True elif line.startswith("F+:"): file_name = line[3:] if file_name: html.div(file_name, class_="filename") html.open_pre(class_="file") in_code = True elif line.startswith("C-:") or line.startswith("F-:"): html.close_pre() in_code = False elif line.startswith("OM:"): html.write_text("OMD[mysite]:~$ ") html.b(line[3:]) elif line.startswith("RP:"): html.write_text("root@myhost:~# ") html.b(line[3:]) elif not line.strip() and not in_code: html.p("") else: html.write_text(line + "\n") if in_list: html.close_ul() html.close_p() return HTML(output_funnel.drain())
def _gen_node(self, tree, height, show_host): leaves: List[Any] = [] for node in tree[3]: if not node[2].get("hidden"): leaves += self._gen_table(node, height - 1, show_host) with output_funnel.plugged(): html.open_div(class_="aggr_tree") with self._show_node(tree, show_host): html.write_text(tree[2]["title"]) html.close_div() content = HTML(output_funnel.drain()) if leaves: leaves[0][2].append((len(leaves), content)) return leaves
def test_context(request_context): table_id = 0 rows = [(i, i**3) for i in range(10)] header = ["Number", "Cubical"] with output_funnel.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(output_funnel.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 output_funnel.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 output_funnel.drain()
def test_basic(register_builtin_html): table_id = 0 title = " TEST " with output_funnel.plugged(): with table_element("%d" % table_id, title, searchable=False, sortable=False) as table: table.row() table.cell("A", "1") table.cell("B", "2") table.row() table.cell("A", "1") table.cell("C", "4") written_text = "".join(output_funnel.drain()) assert read_out_simple_table(written_text) == [[u'A', u'B'], [u'1', u'2'], [u'1', u'4']]
def test_basic(request_context): table_id = 0 title = " TEST " with output_funnel.plugged(): with table_element("%d" % table_id, title, searchable=False, sortable=False) as table: table.row() table.cell("A", "1") table.cell("B", "2") table.row() table.cell("A", "1") table.cell("C", "4") written_text = "".join(output_funnel.drain()) assert read_out_simple_table(written_text) == [["A", "B"], ["1", "2"], ["1", "4"]]
def _render_filter_form(self) -> HTML: with output_funnel.plugged(): self._display_audit_log_options() return HTML(output_funnel.drain())
def _rename_tags_after_confirmation(breadcrumb: Breadcrumb, operation: 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. Returns: True: Proceed, no "question" dialog shown False: "Question dialog" shown str: Action done after "question" dialog """ repair_mode = 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 = HTML() affected_folders, affected_hosts, affected_rulesets = \ change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder()) if affected_folders: with output_funnel.plugged(): html.write_text( _("Affected folders with an explicit reference to this tag " "group and that are affected by the change") + ":") _show_affected_folders(affected_folders) message += HTML(output_funnel.drain()) if affected_hosts: with output_funnel.plugged(): html.write_text( _("Hosts where this tag group is explicitely set " "and that are effected by the change") + ":") _show_affected_hosts(affected_hosts) message += HTML(output_funnel.drain()) if affected_rulesets: with output_funnel.plugged(): html.write_text( _("Rulesets that contain rules with references to the changed tags") + ":") _show_affected_rulesets(affected_rulesets) message += HTML(output_funnel.drain()) if message: wato_html_head(title=operation.confirm_title(), breadcrumb=breadcrumb) html.open_div(class_="really") html.h3(_("Your modifications affect some objects")) html.write_text(message) html.br() html.write_text( _("Setup 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_dropdown_area(self, dropdown: PageMenuDropdown) -> str: with output_funnel.plugged(): self._show_dropdown_area(dropdown) return output_funnel.drain()
def render_ajax_graph(context): graph_data_range = context["data_range"] graph_render_options = context["render_options"] graph_recipe = context["definition"] start_time_var = request.var("start_time") end_time_var = request.var("end_time") step_var = request.var("step") if start_time_var is not None and end_time_var is not None and step_var is not None: start_time = float(start_time_var) end_time = float(end_time_var) step = float(step_var) else: start_time, end_time = graph_data_range["time_range"] step = graph_data_range["step"] size = graph_render_options["size"] resize_x_var = request.var("resize_x") resize_y_var = request.var("resize_y") if resize_x_var is not None and resize_y_var is not None: render_opt_x, render_opt_y = context["render_options"]["size"] size_x = max(min_resize_width, float(resize_x_var) / html_size_per_ex + render_opt_x) size_y = max(min_resize_height, float(resize_y_var) / html_size_per_ex + render_opt_y) config.user.save_file("graph_size", (size_x, size_y)) size = (size_x, size_y) range_from_var = request.var("range_from") range_to_var = request.var("range_to") if range_from_var is not None and range_to_var is not None: vertical_range: Optional[Tuple[float, float]] = (float(range_from_var), float(range_to_var)) else: vertical_range = None if request.has_var("pin"): artwork.save_graph_pin() if request.has_var("consolidation_function"): graph_recipe["consolidation_function"] = request.var( "consolidation_function") graph_render_options["size"] = size graph_data_range["time_range"] = (start_time, end_time) graph_data_range["vertical_range"] = vertical_range graph_data_range["step"] = step # Persist the current data range for the graph editor if graph_render_options["editing"]: save_user_graph_data_range(graph_data_range) graph_artwork = artwork.compute_graph_artwork(graph_recipe, graph_data_range, graph_render_options) with output_funnel.plugged(): _show_graph_html_content(graph_artwork, graph_data_range, graph_render_options) html_code = HTML(output_funnel.drain()) return { "html": html_code, "graph": graph_artwork, "context": { "graph_id": context["graph_id"], "definition": graph_recipe, "data_range": graph_data_range, "render_options": graph_render_options, } }
def render(self) -> HTML: with output_funnel.plugged(): self._show_tree() return HTML(output_funnel.drain())
def _gen_leaf(self, tree, height, show_host): with output_funnel.plugged(): self._show_leaf(tree, show_host) content = HTML(output_funnel.drain()) return [(content, height, [])]