def _show_custom_user_attributes(self, topic): for name, attr in userdb.get_user_attributes(): if topic is not None and topic != attr.topic(): continue # skip attrs of other topics vs = attr.valuespec() forms.section(_u(vs.title())) if not self._is_locked(name): vs.render_input("ua_" + name, self._user.get(name, vs.default_value())) else: html.write(vs.value_to_text(self._user.get(name, vs.default_value()))) # Render hidden to have the values kept after saving html.open_div(style="display:none") vs.render_input("ua_" + name, self._user.get(name, vs.default_value())) html.close_div() html.help(_u(vs.help()))
def page(self): html.help( _("The renaming of hosts is a complex operation since a host's name is being " "used as a unique key in various places. It also involves stopping and starting " "of the monitoring core. You cannot rename a host while you have pending changes.")) html.begin_form("rename_host", method="POST") forms.header(_("Rename host %s") % self._host.name()) forms.section(_("Current name")) html.write_text(self._host.name()) forms.section(_("New name")) html.text_input("newname", "") forms.end() html.set_focus("newname") html.hidden_fields() html.end_form()
def _activation_form(self): if not config.user.may("wato.activate"): html.show_warning(_("You are not permitted to activate configuration changes.")) return if not self._changes: return if not config.user.may("wato.activateforeign") \ and self._has_foreign_changes_on_any_site(): html.show_warning(_("Sorry, you are not allowed to activate changes of other users.")) return valuespec = _vs_activation(self.title(), self.has_foreign_changes()) html.begin_form("activate", method="POST", action="") html.hidden_field("activate_until", self._get_last_change_id(), id_="activate_until") if valuespec: title = valuespec.title() assert title is not None forms.header(title) valuespec.render_input("activate", self._value) valuespec.set_focus("activate") html.help(valuespec.help()) if self.has_foreign_changes(): if config.user.may("wato.activateforeign"): html.show_warning( _("There are some changes made by your colleagues that you will " "activate if you proceed. You need to enable the checkbox above " "to confirm the activation of these changes.")) else: html.show_warning( _("There are some changes made by your colleagues that you can not " "activate because you are not permitted to. You can only activate " "the changes on the sites that are not affected by these changes. " "<br>" "If you need to activate your changes on all sites, please contact " "a permitted user to do it for you.")) forms.end() html.hidden_field("selection_id", weblib.selection_id()) html.hidden_fields() html.end_form() init_rowselect(self.name())
def _show_form(self) -> None: assert config.user.id is not None users = userdb.load_users() user = users.get(config.user.id) if user 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(_("Name"), simple=True) html.write_text(user.get("alias", config.user.id)) select_language(user) # Let the user configure how he wants to be notified rulebased_notifications = rulebased_notifications_enabled() if (not rulebased_notifications and config.user.may('general.edit_notifications') and user.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.")) watolib.get_vs_flexible_notifications().render_input( "notification_method", user.get("notification_method")) if config.user.may('general.edit_user_attributes'): custom_user_attr_topics = get_user_attributes_by_topic() _show_custom_user_attr(user, custom_user_attr_topics.get("personal", [])) forms.header(_("User interface settings")) _show_custom_user_attr( user, custom_user_attr_topics.get("interface", [])) forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def render_input(self, varprefix, value): value = convert_cgroups_from_tuple(value) # If we're just editing a host, then some of the checkboxes will be missing. # This condition is not very clean, but there is no other way to savely determine # the context. is_host = bool(html.request.var("host")) or html.request.var("mode") == "newhost" is_search = varprefix == "host_search" # Only show contact groups I'm currently in and contact # groups already listed here. self.load_data() self._vs_contactgroups().render_input(varprefix + self.name(), value['groups']) html.hr() if is_host: html.checkbox(varprefix + self.name() + "_use", value["use"], label=_("Add these contact groups to the host")) elif not is_search: html.checkbox(varprefix + self.name() + "_recurse_perms", value["recurse_perms"], label=_("Give these groups also <b>permission on all subfolders</b>")) html.hr() html.checkbox( varprefix + self.name() + "_use", value["use"], label=_("Add these groups as <b>contacts</b> to all hosts in this folder")) html.br() html.checkbox(varprefix + self.name() + "_recurse_use", value["recurse_use"], label=_("Add these groups as <b>contacts in all subfolders</b>")) html.hr() html.help( _("With this option contact groups that are added to hosts are always " "being added to services, as well. This only makes a difference if you have " "assigned other contact groups to services via rules in <i>Host & Service Parameters</i>. " "As long as you do not have any such rule a service always inherits all contact groups " "from its host.")) html.checkbox(varprefix + self.name() + "_use_for_services", value.get("use_for_services", False), label=_("Always add host contact groups also to its services"))
def page(self): new = self._folder.name() is None watolib.Folder.current().show_breadcrump() watolib.Folder.current().need_permission("read") if new and watolib.Folder.current().locked(): watolib.Folder.current().show_locking_information() html.begin_form("edit_host", method="POST") # title forms.header(_("Title")) forms.section(_("Title")) TextUnicode().render_input("title", self._folder.title()) html.set_focus("title") # folder name (omit this for root folder) if new or not watolib.Folder.current().is_root(): if not config.wato_hide_filenames: forms.section(_("Internal directory name")) if new: html.text_input("name") else: html.write_text(self._folder.name()) html.help( _("This is the name of subdirectory where the files and " "other folders will be created. You cannot change this later." )) # Attributes inherited to hosts if new: parent = watolib.Folder.current() myself = None else: parent = watolib.Folder.current().parent() myself = watolib.Folder.current() configure_attributes(new, {"folder": myself}, "folder", parent, myself) forms.end() if new or not watolib.Folder.current().locked(): html.button("save", _("Save & Finish"), "submit") html.hidden_fields() html.end_form()
def _show_try_form(self): html.begin_form('try') forms.header(_('Try Pattern Match')) forms.section(_('Hostname')) self._vs_host().render_input("host", self._hostname) forms.section(_('Logfile')) html.text_input('file') forms.section(_('Text to match')) html.help( _('You can insert some text (e.g. a line of the logfile) to test the patterns defined ' 'for this logfile. All patterns for this logfile are listed below. Matching patterns ' 'will be highlighted after clicking the "Try out" button.')) html.text_input('match', cssclass='match', size=100) forms.end() html.button('_try', _('Try out')) html.request.del_var('folder') # Never hand over the folder here html.hidden_fields() html.end_form()
def select_language(user): languages: Choices = [ l for l in get_languages() if not config.hide_language(l[0]) ] if not languages: return current_language = user.get("language") if current_language is None: current_language = "_default_" languages.insert(0, ("_default_", _("Use the default language (%s)") % get_language_alias(config.default_language))) forms.section(_("Language")) html.dropdown("language", languages, deflt=current_language) html.help( _('Configure the language to be used by the user in the user interface here.' ))
def _show_try_form(self): html.begin_form("try") forms.header(_("Try Pattern Match")) forms.section(_("Hostname")) self._vs_host().render_input("host", self._hostname) forms.section(_("Logfile")) html.help(_("Here you need to insert the original file or pathname")) html.text_input("file", size=80) forms.section(_("Text to match")) html.help( _("You can insert some text (e.g. a line of the logfile) to test the patterns defined " "for this logfile. All patterns for this logfile are listed below. Matching patterns " 'will be highlighted after clicking the "Try out" button.')) html.text_input("match", cssclass="match", size=100) forms.end() html.button("_try", _("Try out")) request.del_var("folder") # Never hand over the folder here html.hidden_fields() html.end_form()
def _select_attributes_for_bulk_cleanup(self, hosts): num_shown = 0 for attr in host_attribute_registry.get_sorted_host_attributes(): attrname = attr.name() if not attr.show_in_host_cleanup(): continue # only show attributes that at least on host have set num_haveit = 0 for host in hosts: if host.has_explicit_attribute(attrname): num_haveit += 1 if num_haveit == 0: continue # If the attribute is mandatory and no value is inherited # by file or folder, the attribute cannot be cleaned. container = self._folder is_inherited = False while container: if container.has_explicit_attribute(attrname): is_inherited = True break container = container.parent() num_shown += 1 # Legend and Help forms.section(attr.title()) if attr.is_mandatory() and not is_inherited: html.write_text( _("This attribute is mandatory and there is no value " "defined in the host list or any parent folder.")) else: label = "clean this attribute on <b>%s</b> hosts" % \ (num_haveit == len(hosts) and "all selected" or str(num_haveit)) html.checkbox("_clean_%s" % attrname, False, label=label) html.help(attr.help()) return num_shown > 0
def page(self): html.help( _("This catalog of check plugins gives you a complete listing of all plugins " "that are shipped with your Check_MK installation. It also allows you to " "access the rule sets for configuring the parameters of the checks and to " "manually create services in case you cannot or do not want to rely on the " "automatic service discovery.")) menu = MainMenu() for topic, _has_second_level, title, helptext in _man_page_catalog_topics(): menu.add_item( MenuItem(mode_or_url=makeuri( request, [("mode", "check_plugin_topic"), ("topic", topic)], ), title=title, icon="plugins_" + topic, permission=None, description=helptext)) menu.show()
def render(self, what): html.button("_acknowledge", _("Acknowledge")) html.button("_remove_ack", _("Remove Acknowledgement")) html.hr() html.checkbox("_ack_sticky", config.view_action_defaults["ack_sticky"], label=_("sticky")) html.checkbox("_ack_notify", config.view_action_defaults["ack_notify"], label=_("send notification")) html.checkbox("_ack_persistent", config.view_action_defaults["ack_persistent"], label=_('persistent comment')) html.hr() self._vs_expire().render_input("_ack_expire", config.view_action_defaults.get("ack_expire", 0)) html.help( _("Note: Expiration of acknowledgements only works when using the Checkmk Micro Core.")) html.hr() html.write_text(_("Comment") + ": ") html.text_input("_ack_comment", size=48, submit="_acknowledge")
def _select_attributes_for_bulk_cleanup(self, hosts): attributes = self._get_attributes_for_bulk_cleanup(hosts) for attr, is_inherited, num_haveit in attributes: # Legend and Help forms.section(attr.title()) if attr.is_mandatory() and not is_inherited: html.write_text( _("This attribute is mandatory and there is no value " "defined in the host list or any parent folder.")) else: label = "clean this attribute on <b>%s</b> hosts" % \ (num_haveit == len(hosts) and "all selected" or str(num_haveit)) html.checkbox("_clean_%s" % attr.name(), False, label=label) html.help(attr.help()) forms.end() if not attributes: html.write_text(_("The selected hosts have no explicit attributes"))
def page(self): role_list = sorted(userdb_utils.load_roles().items(), key=lambda a: (a[1]["alias"], a[0])) for section in permission_section_registry.get_sorted_sections(): with table_element( section.name, section.title, foldable=True, ) as table: permission_list = permission_registry.get_sorted_permissions( section) if not permission_list: table.row() table.cell(_("Permission"), _("No entries"), css="wide") continue for perm in permission_list: table.row() table.cell(_("Permission"), perm.title, css="wide") html.help(perm.description) for role_id, role in role_list: base_on_id = role.get("basedon", role_id) pvalue = role["permissions"].get(perm.name) if pvalue is None: if base_on_id in perm.defaults: icon_name: Optional[str] = "perm_yes_default" else: icon_name = None else: icon_name = "perm_%s" % (pvalue and "yes" or "no") table.cell(role_id, css="center") if icon_name: html.icon(icon_name) html.close_table()
def page(self): all_rulesets = watolib.AllRulesets() all_rulesets.load() for_host: bool = not self._service # Object type specific detail information if for_host: self._show_host_info() else: self._show_service_info(all_rulesets) last_maingroup = None for groupname in sorted( rulespec_group_registry.get_host_rulespec_group_names( for_host)): maingroup = groupname.split("/")[0] for rulespec in sorted(rulespec_registry.get_by_group(groupname), key=lambda x: x.title or ""): if (rulespec.item_type == "service") == (not self._service): continue # This rule is not for hosts/services # Open form for that group here, if we know that we have at least one rule if last_maingroup != maingroup: last_maingroup = maingroup rulegroup = watolib.get_rulegroup(maingroup) forms.header( rulegroup.title, isopen=maingroup == "monconf", narrow=True, css="rulesettings", ) html.help(rulegroup.help) self._output_analysed_ruleset(all_rulesets, rulespec, svc_desc_or_item=self._service, svc_desc=self._service) forms.end()
def select_language(user): languages = [ l for l in cmk.gui.i18n.get_languages() if not config.hide_language(l[0]) ] if languages: active = 'language' in user forms.section(_("Language"), checkbox=('_set_lang', active, 'language')) default_label = _('Default: %s') % cmk.gui.i18n.get_language_alias( config.default_language) html.div(default_label, class_="inherited", id_="attr_default_language", style="display: none" if active else "") html.open_div(id_="attr_entry_language", style="display: none" if not active else "") language = user.get('language') if user.get( 'language') is not None else '' # Transform 'en' configured language to empty string for compatibility reasons if language == "en": language = "" html.dropdown("language", languages, deflt=language) html.close_div() html.help( _('Configure the default language ' 'to be used by the user in the user interface here. If you do not check ' 'the checkbox, then the system default will be used.<br><br>' 'Note: currently Multisite is internationalized ' 'but comes without any actual localisations (translations). If you want to ' 'create you own translation, you find <a href="%(url)s">documentation online</a>.' ) % { "url": "https://mathias-kettner.com/checkmk_multisite_cmk.gui.i18n.html" })
def page(self) -> None: html.begin_form("group") forms.header(_("Properties")) forms.section(_("Name"), simple=not self._new, is_required=True) html.help( _("The name of the group is used as an internal key. It cannot be " "changed later. It is also visible in the status GUI.")) if self._new: html.text_input("name") html.set_focus("name") else: html.write_text(self._name) html.set_focus("alias") forms.section(_("Alias"), is_required=True) html.help(_("An alias or description of this group.")) html.text_input("alias", self.group["alias"]) self._show_extra_page_elements() forms.end() html.hidden_fields() html.end_form()
def page(self): role_list = sorted(userdb_utils.load_roles().items(), key=lambda a: (a[1]["alias"], a[0])) for section in permission_section_registry.get_sorted_sections(): html.begin_foldable_container("perm_matrix", section.name, section.name == "general", section.title, indent=True) with table_element(section.name) as table: for perm in permission_registry.get_sorted_permissions( section): table.row() table.cell(_("Permission"), perm.title, css="wide") html.help(perm.description) for role_id, role in role_list: base_on_id = role.get('basedon', role_id) pvalue = role["permissions"].get(perm.name) if pvalue is None: if base_on_id in perm.defaults: icon_name: Optional[str] = "perm_yes_default" else: icon_name = None else: icon_name = "perm_%s" % (pvalue and "yes" or "no") table.cell(role_id, css="center") if icon_name: html.icon(icon_name) html.end_foldable_container() html.close_table()
def page(self): # Let exceptions from loading notification scripts happen now watolib.load_notification_scripts() html.begin_form("user", method="POST") html.prevent_password_auto_completion() forms.header(_("Identity")) # ID forms.section(_("Username"), simple=not self._is_new_user) if self._is_new_user: vs_user_id = UserID(allow_empty=False) else: vs_user_id = FixedValue(self._user_id) vs_user_id.render_input("user_id", self._user_id) def lockable_input(name, dflt): if not self._is_locked(name): html.text_input(name, self._user.get(name, dflt), size=50) else: html.write_text(self._user.get(name, dflt)) html.hidden_field(name, self._user.get(name, dflt)) # Full name forms.section(_("Full name")) lockable_input('alias', self._user_id) html.help(_("Full name or alias of the user")) # Email address forms.section(_("Email address")) email = self._user.get("email", "") if not self._is_locked("email"): EmailAddressUnicode().render_input("email", email) else: html.write_text(email) html.hidden_field("email", email) html.help( _("The email address is optional and is needed " "if the user is a monitoring contact and receives notifications " "via Email.")) forms.section(_("Pager address")) lockable_input('pager', '') html.help(_("The pager address is optional ")) if cmk.is_managed_edition(): forms.section(self._vs_customer.title()) self._vs_customer.render_input("customer", managed.get_customer_id(self._user)) html.help(self._vs_customer.help()) vs_sites = self._vs_sites() forms.section(vs_sites.title()) authorized_sites = self._user.get("authorized_sites", vs_sites.default_value()) if not self._is_locked("authorized_sites"): vs_sites.render_input("authorized_sites", authorized_sites) else: html.write_html(vs_sites.value_to_text(authorized_sites)) html.help(vs_sites.help()) self._show_custom_user_attributes('ident') forms.header(_("Security")) forms.section(_("Authentication")) is_automation = self._user.get("automation_secret", None) is not None html.radiobutton("authmethod", "password", not is_automation, _("Normal user login with password")) html.open_ul() html.open_table() html.open_tr() html.td(_("password:"******"_password_" + self._pw_suffix(), autocomplete="new-password") html.close_td() html.close_tr() html.open_tr() html.td(_("repeat:")) html.open_td() html.password_input("_password2_" + self._pw_suffix(), autocomplete="new-password") html.write_text(" (%s)" % _("optional")) html.close_td() html.close_tr() html.open_tr() html.td("%s:" % _("Enforce change")) html.open_td() # Only make password enforcement selection possible when user is allowed to change the PW if self._is_new_user or config.user_may(self._user_id, 'general.edit_profile') and config.user_may( self._user_id, 'general.change_password'): html.checkbox("enforce_pw_change", self._user.get("enforce_pw_change", False), label=_("Change password at next login or access")) else: html.write_text( _("Not permitted to change the password. Change can not be enforced.")) else: html.i(_('The password can not be changed (It is locked by the user connector).')) html.hidden_field('_password', '') html.hidden_field('_password2', '') html.close_td() html.close_tr() html.close_table() html.close_ul() html.radiobutton("authmethod", "secret", is_automation, _("Automation secret for machine accounts")) html.open_ul() html.text_input("_auth_secret", self._user.get("automation_secret", ""), size=30, id_="automation_secret") html.write_text(" ") html.open_b(style=["position: relative", "top: 4px;"]) html.write(" ") html.icon_button("javascript:cmk.wato.randomize_secret('automation_secret', 20);", _("Create random secret"), "random") html.close_b() html.close_ul() html.help( _("If you want the user to be able to login " "then specify a password here. Users without a login make sense " "if they are monitoring contacts that are just used for " "notifications. The repetition of the password is optional. " "<br>For accounts used by automation processes (such as fetching " "data from views for further procession), set the method to " "<u>secret</u>. The secret will be stored in a local file. Processes " "with read access to that file will be able to use Multisite as " "a webservice without any further configuration.")) # Locking forms.section(_("Disable password"), simple=True) if not self._is_locked('locked'): html.checkbox("locked", self._user.get("locked", False), label=_("disable the login to this account")) else: html.write_text( _('Login disabled') if self._user.get("locked", False) else _('Login possible')) html.hidden_field('locked', '1' if self._user.get("locked", False) else '') html.help( _("Disabling the password will prevent a user from logging in while " "retaining the original password. Notifications are not affected " "by this setting.")) forms.section(_("Idle timeout")) idle_timeout = self._user.get("idle_timeout") if not self._is_locked("idle_timeout"): watolib.get_vs_user_idle_timeout().render_input("idle_timeout", idle_timeout) else: html.write_text(idle_timeout) html.hidden_field("idle_timeout", idle_timeout) # Roles forms.section(_("Roles")) entries = self._roles.items() entries.sort(key=lambda x: (x[1]["alias"], x[0])) is_member_of_at_least_one = False for role_id, role in entries: if not self._is_locked("roles"): html.checkbox("role_" + role_id, role_id in self._user.get("roles", [])) url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)]) html.a(role["alias"], href=url) html.br() else: is_member = role_id in self._user.get("roles", []) if is_member: is_member_of_at_least_one = True url = watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role_id)]) html.a(role["alias"], href=url) html.br() html.hidden_field("role_" + role_id, '1' if is_member else '') if self._is_locked('roles') and not is_member_of_at_least_one: html.i(_('No roles assigned.')) self._show_custom_user_attributes('security') # Contact groups forms.header(_("Contact Groups"), isopen=False) forms.section() groups_page_url = watolib.folder_preserving_link([("mode", "contact_groups")]) group_assign_url = watolib.folder_preserving_link([("mode", "rulesets"), ("group", "grouping")]) if not self._contact_groups: html.write( _("Please first create some <a href='%s'>contact groups</a>") % groups_page_url) else: entries = sorted([(group['alias'] or c, c) for c, group in self._contact_groups.items() ]) is_member_of_at_least_one = False for alias, gid in entries: is_member = gid in self._user.get("contactgroups", []) if not self._is_locked('contactgroups'): html.checkbox("cg_" + gid, gid in self._user.get("contactgroups", [])) else: if is_member: is_member_of_at_least_one = True html.hidden_field("cg_" + gid, '1' if is_member else '') if not self._is_locked('contactgroups') or is_member: url = watolib.folder_preserving_link([("mode", "edit_contact_group"), ("edit", gid)]) html.a(alias, href=url) html.br() if self._is_locked('contactgroups') and not is_member_of_at_least_one: html.i(_('No contact groups assigned.')) html.help( _("Contact groups are used to assign monitoring " "objects to users. If you haven't defined any contact groups yet, " "then first <a href='%s'>do so</a>. Hosts and services can be " "assigned to contact groups using <a href='%s'>rules</a>.<br><br>" "If you do not put the user into any contact group " "then no monitoring contact will be created for the user.") % (groups_page_url, group_assign_url)) forms.header(_("Notifications"), isopen=False) if not self._rbn_enabled(): forms.section(_("Enabling"), simple=True) html.checkbox("notifications_enabled", self._user.get("notifications_enabled", False), label=_("enable notifications")) html.help( _("Notifications are sent out " "when the status of a host or service changes.")) # Notification period forms.section(_("Notification time period")) choices = [(id_, "%s" % (tp["alias"])) for (id_, tp) in self._timeperiods.items()] html.dropdown("notification_period", choices, deflt=self._user.get("notification_period"), ordered=True) html.help( _("Only during this time period the " "user will get notifications about host or service alerts.")) # Notification options notification_option_names = { # defined here: _() must be executed always! "host": { "d": _("Host goes down"), "u": _("Host gets unreachble"), "r": _("Host goes up again"), }, "service": { "w": _("Service goes into warning state"), "u": _("Service goes into unknown state"), "c": _("Service goes into critical state"), "r": _("Service recovers to OK"), }, "both": { "f": _("Start or end of flapping state"), "s": _("Start or end of a scheduled downtime"), } } forms.section(_("Notification Options")) for title, what, opts in [(_("Host events"), "host", "durfs"), (_("Service events"), "service", "wucrfs")]: html.write_text("%s:" % title) html.open_ul() user_opts = self._user.get(what + "_notification_options", opts) for opt in opts: opt_name = notification_option_names[what].get( opt, notification_option_names["both"].get(opt)) html.checkbox(what + "_" + opt, opt in user_opts, label=opt_name) html.br() html.close_ul() html.help( _("Here you specify which types of alerts " "will be notified to this contact. Note: these settings will only be saved " "and used if the user is member of a contact group.")) forms.section(_("Notification Method")) watolib.get_vs_flexible_notifications().render_input( "notification_method", self._user.get("notification_method")) else: forms.section(_("Fallback notifications"), simple=True) html.checkbox("fallback_contact", self._user.get("fallback_contact", False), label=_("Receive fallback notifications")) html.help( _("In case none of your notification rules handles a certain event a notification " "will be sent to this contact. This makes sure that in that case at least <i>someone</i> " "gets notified. Furthermore this contact will be used for notifications to any host or service " "that is not known to the monitoring. This can happen when you forward notifications " "from the Event Console.<br><br>Notification fallback can also configured in the global " "setting <a href=\"wato.py?mode=edit_configvar&varname=notification_fallback_email\">" "Fallback email address for notifications</a>.")) self._show_custom_user_attributes('notify') forms.header(_("Personal Settings"), isopen=False) select_language(self._user) self._show_custom_user_attributes('personal') # Later we could add custom macros here, which then could be used # for notifications. On the other hand, if we implement some check_mk # --notify, we could directly access the data in the account with the need # to store values in the monitoring core. We'll see what future brings. forms.end() html.button("save", _("Save")) if self._is_new_user: html.set_focus("user_id") else: html.set_focus("alias") html.hidden_fields() html.end_form()
def _end(self) -> None: if not self.rows and self.options["omit_if_empty"]: return if self.options["output_format"] == "csv": self._write_csv(csv_separator=html.request.get_str_input_mandatory( "csv_separator", ";")) return if self.title: if self.options["foldable"]: html.begin_foldable_container( treename="table", id_=self.id, isopen=True, indent=False, title=html.render_h3(self.title, class_=["treeangle", "title"])) else: html.open_h3() html.write(self.title) html.close_h3() if self.help: html.help(self.help) if not self.rows: html.div(self.empty_text, class_="info") return # Controls whether or not actions are available for a table rows, actions_visible, search_term = self._evaluate_user_opts() # Apply limit after search / sorting etc. num_rows_unlimited = len(rows) limit = self.limit if limit is not None: # only use rows up to the limit plus the fixed rows limited_rows = [] for index in range(num_rows_unlimited): row = rows[index] if index < limit or isinstance(row, GroupHeader) or row.fixed: limited_rows.append(row) # Display corrected number of rows num_rows_unlimited -= len([ r for r in limited_rows if isinstance(row, GroupHeader) or r.fixed ]) rows = limited_rows # Render header if self.limit_hint is not None: num_rows_unlimited = self.limit_hint self._write_table(rows, num_rows_unlimited, self._show_action_row(), actions_visible, search_term) if self.title and self.options["foldable"]: html.end_foldable_container() if limit is not None and num_rows_unlimited > limit: html.show_message( _('This table is limited to show only %d of %d rows. ' 'Click <a href="%s">here</a> to disable the limitation.') % (limit, num_rows_unlimited, html.makeuri([('limit', 'none')]))) return
def page(self): search = get_search_expression() html.begin_form("role", method="POST") # ID forms.header(_("Basic properties"), css="wide") forms.section(_("Internal ID"), simple="builtin" in self._role, is_required=True) if self._role.get("builtin"): html.write_text("%s (%s)" % (self._role_id, _("builtin role"))) html.hidden_field("id", self._role_id) else: html.text_input("id", self._role_id) html.set_focus("id") # Alias forms.section(_("Alias")) html.help(_("An alias or description of the role")) html.text_input("alias", self._role.get("alias", ""), size=50) # Based on if not self._role.get("builtin"): forms.section(_("Based on role")) html.help( _("Each user defined role is based on one of the builtin roles. " "When created it will start with all permissions of that role. When due to a software " "update or installation of an addons new permissions appear, the user role will get or " "not get those new permissions based on the default settings of the builtin role it's " "based on.")) role_choices: Choices = [(i, r["alias"]) for i, r in self._roles.items() if r.get("builtin")] html.dropdown("basedon", role_choices, deflt=self._role.get("basedon", "user"), ordered=True) forms.end() html.h2(_("Permissions")) # Permissions base_role_id = self._role.get("basedon", self._role_id) html.help( _("When you leave the permissions at "default" then they get their " "settings from the factory defaults (for builtin roles) or from the " "factory default of their base role (for user define roles). Factory defaults " "may change due to software updates. When choosing another base role, all " "permissions that are on default will reflect the new base role." )) for section in permission_section_registry.get_sorted_sections(): # Now filter by the optional search term filtered_perms = [] for perm in permission_registry.get_sorted_permissions(section): if search and (search not in perm.title.lower() and search not in perm.name.lower()): continue filtered_perms.append(perm) if not filtered_perms: continue forms.header(section.title, isopen=search is not None, css="wide") for perm in filtered_perms: forms.section(perm.title) pvalue = self._role["permissions"].get(perm.name) def_value = base_role_id in perm.defaults choices: Choices = [ ("yes", _("yes")), ("no", _("no")), ("default", _("default (%s)") % (def_value and _("yes") or _("no"))), ] deflt = {True: "yes", False: "no"}.get(pvalue, "default") html.dropdown("perm_" + perm.name, choices, deflt=deflt, style="width: 130px;") html.help(perm.description) forms.end() html.hidden_fields() html.end_form()
def _end(self) -> None: if not self.rows and self.options["omit_if_empty"]: return if self.options["output_format"] == "csv": self._write_csv(csv_separator=request.get_str_input_mandatory( "csv_separator", ";")) return container: ContextManager[bool] = nullcontext(False) if self.title: if self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.open_div(class_="foldable_wrapper") container = foldable_container( treename="table", id_=self.id, isopen=True, indent=False, title=html.render_h3(self.title, class_=["treeangle", "title"]), save_state=self.options["foldable"] == Foldable.FOLDABLE_SAVE_STATE, ) else: html.h3(self.title, class_="table") with container: if self.help: html.help(self.help) if not self.rows: html.div(self.empty_text, class_="info") return # Controls whether or not actions are available for a table rows, actions_visible, search_term = self._evaluate_user_opts() # Apply limit after search / sorting etc. num_rows_unlimited = len(rows) limit = self.limit if limit: # only use rows up to the limit plus the fixed rows limited_rows = [] for index in range(num_rows_unlimited): row = rows[index] if index < limit or isinstance(row, GroupHeader) or row.fixed: limited_rows.append(row) # Display corrected number of rows num_rows_unlimited -= len([ r for r in limited_rows if isinstance(row, GroupHeader) or r.fixed ]) rows = limited_rows # Render header if self.limit_hint is not None: num_rows_unlimited = self.limit_hint if limit and num_rows_unlimited > limit: html.show_message( _("This table is limited to show only %d of %d rows. " 'Click <a href="%s">here</a> to disable the limitation.') % (limit, num_rows_unlimited, makeuri(request, [("limit", "none")]))) self._write_table(rows, num_rows_unlimited, self._show_action_row(), actions_visible, search_term) if self.title and self.options["foldable"] in [ Foldable.FOLDABLE_SAVE_STATE, Foldable.FOLDABLE_STATELESS, ]: html.close_div() return
def page(self): # Show outcome of host validation. Do not validate new hosts errors = None if self._mode != "edit": watolib.Folder.current().show_breadcrump() else: errors = watolib.validate_all_hosts([self._host.name()]).get( self._host.name(), []) + self._host.validation_errors() if errors: html.open_div(class_="info") html.open_table(class_="validationerror", boder=0, cellspacing=0, cellpadding=0) html.open_tr() html.open_td(class_="img") html.icon(title=None, icon="validation_error") html.close_td() html.open_td() html.open_p() html.h3(_("Warning: This host has an invalid configuration!")) html.open_ul() for error in errors: html.li(error) html.close_ul() html.close_p() if html.form_submitted(): html.br() html.b(_("Your changes have been saved nevertheless.")) html.close_td() html.close_tr() html.close_table() html.close_div() lock_message = "" if watolib.Folder.current().locked_hosts(): if watolib.Folder.current().locked_hosts() is True: lock_message = _( "Host attributes locked (You cannot edit this host)") else: lock_message = watolib.Folder.current().locked_hosts() if len(lock_message) > 0: html.div(lock_message, class_="info") html.begin_form("edit_host", method="POST") html.prevent_password_auto_completion() forms.header(_("General Properties")) self._show_host_name() # Cluster: nodes if self._is_cluster(): forms.section(_("Nodes")) self._vs_cluster_nodes().render_input( "nodes", self._host.cluster_nodes() if self._host else []) html.help( _('Enter the host names of the cluster nodes. These ' 'hosts must be present in WATO. ')) configure_attributes( new=self._mode != "edit", hosts={self._host.name(): self._host} if self._mode != "new" else {}, for_what="host" if not self._is_cluster() else "cluster", parent=watolib.Folder.current()) forms.end() if not watolib.Folder.current().locked_hosts(): html.button("services", _("Save & go to Services"), "submit") html.button("save", _("Save & Finish"), "submit") if not self._is_cluster(): html.button("diag_host", _("Save & Test"), "submit") html.hidden_fields() html.end_form()
def page(self): # TODO: remove subclass specific things specifict things (everything with _type == 'user') html.begin_form("attr") forms.header(_("Properties")) forms.section(_("Name"), simple=not self._new, is_required=True) html.help( _("The name of the attribute is used as an internal key. It cannot be " "changed later.")) if self._new: html.text_input("name", self._attr.get('name', '')) html.set_focus("name") else: html.write_text(self._name) html.set_focus("title") forms.section(_("Title") + "<sup>*</sup>", is_required=True) html.help(_("The title is used to label this attribute.")) html.text_input("title", self._attr.get('title', '')) forms.section(_('Topic')) html.help( _('The attribute is added to this section in the edit dialog.')) html.dropdown('topic', self._topics, deflt=self._attr.get('topic', self._default_topic)) forms.section(_('Help Text') + "<sup>*</sup>") html.help( _('You might want to add some helpful description for the attribute.' )) html.text_area('help', self._attr.get('help', '')) forms.section(_('Data type')) html.help(_('The type of information to be stored in this attribute.')) if self._new: html.dropdown('type', custom_attr_types(), deflt=self._attr.get('type', '')) else: html.write(dict(custom_attr_types())[self._attr.get('type')]) self._add_extra_form_sections() self._show_in_table_option() forms.section(_('Add to monitoring configuration')) html.help(self._macro_help) html.checkbox('add_custom_macro', self._attr.get('add_custom_macro', False), label=self._macro_label) forms.end() html.show_localization_hint() html.hidden_fields() html.end_form()
def edit_dictionaries(dictionaries, value, focus=None, hover_help=True, validate=None, buttontext=None, title=None, buttons=None, method="GET", preview=False, varprefix="", formname="form", consume_transid=True): # Convert list of entries/dictionaries sections = [] for keyname, d in dictionaries: if isinstance(d, list): sections.append((keyname, title or _("Properties"), d)) else: sections.append((keyname, None, d)) # valuespec Dictionary, title used from dict if html.request.var("filled_in") == formname and html.transaction_valid(): if not preview and consume_transid: html.check_transaction() messages = [] new_value = {} for keyname, _section_title, entries in sections: if isinstance(entries, list): new_value[keyname] = value.get(keyname, {}).copy() for name, vs in entries: if len(sections) == 1: vp = varprefix else: vp = keyname + "_" + varprefix try: v = vs.from_html_vars(vp + name) vs.validate_value(v, vp + name) new_value[keyname][name] = v except MKUserError as e: messages.append("%s: %s" % (vs.title(), e)) html.add_user_error(e.varname, e) else: new_value[keyname] = {} try: edited_value = entries.from_html_vars(keyname) entries.validate_value(edited_value, keyname) new_value[keyname].update(edited_value) except MKUserError as e: messages.append("%s: %s" % (entries.title() or _("Properties"), e)) html.add_user_error(e.varname, e) except Exception as e: messages.append("%s: %s" % (entries.title() or _("Properties"), e)) html.add_user_error(None, e) if validate and not html.has_user_errors(): try: validate(new_value[keyname]) except MKUserError as e: messages.append(e) html.add_user_error(e.varname, e) if messages: messages_joined = "".join(["%s<br>\n" % m for m in messages]) if not preview: html.show_error(messages_joined) else: raise MKUserError(None, messages_joined) else: return new_value html.begin_form(formname, method=method) for keyname, title1, entries in sections: subvalue = value.get(keyname, {}) if isinstance(entries, list): header(title1) first = True for name, vs in entries: section(vs.title()) html.help(vs.help()) if name in subvalue: v = subvalue[name] else: v = vs.default_value() if len(sections) == 1: vp = varprefix else: vp = keyname + "_" + varprefix vs.render_input(vp + name, v) if (not focus and first) or (name == focus): vs.set_focus(vp + name) first = False else: entries.render_input_as_form(keyname, subvalue) end() if buttons: for name, button_title, _icon in buttons: html.button(name, button_title) else: if buttontext is None: buttontext = _("Save") html.button("save", buttontext) # Should be ignored be hidden_fields, but I do not dare to change it there html.request.del_var("filled_in") html.hidden_fields() html.end_form()
def _preview(self): # type: () -> None html.begin_form("preview", method="POST") self._preview_form() attributes = self._attribute_choices() # first line could be missing in situation of import error csv_reader = self._open_csv_file() if not csv_reader: return # don't try to show preview when CSV could not be read html.h2(_("Preview")) attribute_list = "<ul>%s</ul>" % "".join( ["<li>%s (%s)</li>" % a for a in attributes if a[0] is not None]) html.help( _("This list shows you the first 10 rows from your CSV file in the way the import is " "currently parsing it. If the lines are not splitted correctly or the title line is " "not shown as title of the table, you may change the import settings above and try " "again.") + "<br><br>" + _("The first row below the titles contains fields to specify which column of the " "CSV file should be imported to which attribute of the created hosts. The import " "progress is trying to match the columns to attributes automatically by using the " "titles found in the title row (if you have some). " "If you use the correct titles, the attributes can be mapped automatically. The " "currently available attributes are:") + attribute_list + _("You can change these assignments according to your needs and then start the " "import by clicking on the <i>Import</i> button above.")) # Wenn bei einem Host ein Fehler passiert, dann wird die Fehlermeldung zu dem Host angezeigt, so dass man sehen kann, was man anpassen muss. # Die problematischen Zeilen sollen angezeigt werden, so dass man diese als Block in ein neues CSV-File eintragen kann und dann diese Datei # erneut importieren kann. if self._has_title_line: try: headers = list(next(csv_reader)) except StopIteration: headers = [] # nope, there is no header else: headers = [] rows = list(csv_reader) # Determine how many columns should be rendered by using the longest column num_columns = max([len(r) for r in [headers] + rows]) with table_element(sortable=False, searchable=False, omit_headers=not self._has_title_line) as table: # Render attribute selection fields table.row() for col_num in range(num_columns): header = headers[col_num] if len(headers) > col_num else None table.cell(html.render_text(header)) attribute_varname = "attribute_%d" % col_num if html.request.var(attribute_varname): attribute_method = html.request.get_ascii_input_mandatory( "attribute_varname") else: attribute_method = self._try_detect_default_attribute( attributes, header) html.request.del_var(attribute_varname) html.dropdown("attribute_%d" % col_num, attributes, deflt=attribute_method, autocomplete="off") # Render sample rows for row in rows: table.row() for cell in row: table.cell(None, html.render_text(cell)) html.end_form()
def _end(self): if not self.rows and self.options["omit_if_empty"]: return if self.options["output_format"] == "csv": self._write_csv( csv_separator=html.request.var("csv_separator", ";")) return if self.title: if self.options["foldable"]: html.begin_foldable_container( treename="table", id_=self.id, isopen=True, indent=False, title=html.render_h3(self.title, class_=["treeangle", "title"])) else: html.open_h3() html.write(self.title) html.close_h3() if self.help: html.help(self.help) if not self.rows: html.div(self.empty_text, class_="info") return # Controls whether or not actions are available for a table rows, actions_enabled, actions_visible, search_term, user_opts = self._evaluate_user_opts( ) # Apply limit after search / sorting etc. num_rows_unlimited = len(rows) limit = self.limit if limit is not None: # only use rows up to the limit plus the fixed rows rows = [ rows[i] for i in range(num_rows_unlimited) if i < limit or rows[i][3] ] # Display corrected number of rows num_rows_unlimited -= len([r for r in rows if r[3]]) # Render header self._write_table(rows, actions_enabled, actions_visible, search_term) if self.title and self.options["foldable"]: html.end_foldable_container() if limit is not None and num_rows_unlimited > limit: html.message( _('This table is limited to show only %d of %d rows. ' 'Click <a href="%s">here</a> to disable the limitation.') % (limit, num_rows_unlimited, html.makeuri([('limit', 'none')]))) if actions_enabled: config.user.save_file("tableoptions", user_opts) return
def page_list(cls): cls.load() # custom_columns = [] # render_custom_buttons = None # render_custom_columns = None # render_custom_context_buttons = None # check_deletable_handler = None cls.need_overriding_permission("edit") html.header(cls.phrase("title_plural")) html.begin_context_buttons() html.context_button(cls.phrase("new"), cls.create_url(), "new_" + cls.type_name()) # TODO: Remove this legacy code as soon as views, dashboards and reports have been # moved to pagetypes.py html.context_button(_("Views"), "edit_views.py", "view") html.context_button(_("Dashboards"), "edit_dashboards.py", "dashboard") def has_reporting(): try: # The suppression below is OK, we just want to check if the module is there. import cmk.gui.cee.reporting # noqa: F401 # pylint: disable=unused-variable,redefined-outer-name return True except ImportError: return False if has_reporting(): html.context_button(_("Reports"), "edit_reports.py", "report") # ## if render_custom_context_buttons: # ## render_custom_context_buttons() for other_type_name, other_pagetype in page_types.items(): if cls.type_name() != other_type_name: html.context_button( other_pagetype.phrase("title_plural").title(), '%ss.py' % other_type_name, other_type_name) html.end_context_buttons() # Deletion delname = html.request.var("_delete") if delname and html.transaction_valid(): owner = UserId(html.request.get_unicode_input_mandatory('_owner', config.user.id)) try: instance = cls.instance((owner, delname)) except KeyError: raise MKUserError( "_delete", _("The %s you are trying to delete " "does not exist.") % cls.phrase("title")) if not instance.may_delete(): raise MKUserError("_delete", _("You are not permitted to perform this action.")) try: if owner != config.user.id: owned_by = _(" (owned by %s)") % owner else: owned_by = "" c = html.confirm( _("Please confirm the deletion of \"%s\"%s.") % (instance.title(), owned_by)) if c: cls.remove_instance((owner, delname)) cls.save_user_instances(owner) html.reload_sidebar() elif c is False: html.footer() return except MKUserError as e: html.user_error(e) # Bulk delete if html.request.var("_bulk_delete_my") and html.transaction_valid(): if cls._bulk_delete_after_confirm("my") is False: html.footer() return elif html.request.var("_bulk_delete_foreign") and html.transaction_valid(): if cls._bulk_delete_after_confirm("foreign") is False: html.footer() return my_instances, foreign_instances, builtin_instances = cls.get_instances() for what, title, instances in [ ("my", _('Customized'), my_instances), ("foreign", _('Owned by other users'), foreign_instances), ("builtin", _('Builtin'), builtin_instances), ]: if not instances: continue html.open_h3() html.write(title) html.close_h3() if what != "builtin": html.begin_form("bulk_delete_%s" % what, method="POST") with table_element(limit=None) as table: for instance in instances: table.row() if what != "builtin" and instance.may_delete(): table.cell(html.render_input( "_toggle_group", type_="button", class_="checkgroup", onclick="cmk.selection.toggle_all_rows(this.form);", value='X'), sortable=False, css="checkbox") html.checkbox("_c_%s+%s+%s" % (what, instance.owner(), instance.name())) # Actions table.cell(_('Actions'), css='buttons visuals') # View if isinstance(instance, PageRenderer): html.icon_button(instance.page_url(), _("View"), "new_" + cls.type_name()) # Clone / Customize html.icon_button(instance.clone_url(), _("Create a customized copy of this"), "clone") # Delete if instance.may_delete(): html.icon_button(instance.delete_url(), _("Delete!"), "delete") # Edit if instance.may_edit(): html.icon_button(instance.edit_url(), _("Edit"), "edit") cls.custom_list_buttons(instance) # Internal ID of instance (we call that 'name') table.cell(_('ID'), instance.name(), css="narrow") # Title table.cell(_('Title')) html.write_text(instance.render_title()) html.help(_u(instance.description())) # Custom columns specific to that page type instance.render_extra_columns(table) # ## for title, renderer in custom_columns: # ## table.cell(title, renderer(visual)) # Owner if instance.is_builtin(): ownertxt = html.render_i(_("builtin")) else: ownertxt = instance.owner() table.cell(_('Owner'), ownertxt) table.cell(_('Public'), _("yes") if instance.is_public() else _("no")) table.cell(_('Hidden'), _("yes") if instance.is_hidden() else _("no")) # FIXME: WTF?!? # TODO: Haeeh? Another custom columns # ## if render_custom_columns: # ## render_custom_columns(visual_name, visual) if what != "builtin": html.button("_bulk_delete_%s" % what, _("Bulk delete"), "submit", style="margin-top:10px") html.hidden_fields() html.end_form() html.footer() return
def _show_page_user_profile(change_pw): start_async_replication = False if not config.user.id: raise MKUserError(None, _('Not logged in.')) if not config.user.may('general.edit_profile') and not config.user.may( 'general.change_password'): raise MKAuthException( _("You are not allowed to edit your user profile.")) if not config.wato_enabled: raise MKAuthException( _('User profiles can not be edited (WATO is disabled).')) success = None if html.request.has_var('_save') and html.check_transaction(): users = userdb.load_users(lock=True) try: # Profile edit (user options like language etc.) if config.user.may('general.edit_profile'): if not change_pw: set_lang = html.get_checkbox('_set_lang') language = html.request.var('language') # Set the users language if requested if set_lang: if language == '': language = None # Set custom language users[config.user.id]['language'] = language config.user.language = language html.set_language_cookie(language) else: # Remove the customized language if 'language' in users[config.user.id]: del users[config.user.id]['language'] config.user.reset_language() # load the new language cmk.gui.i18n.localize(config.user.language) user = users.get(config.user.id) if config.user.may('general.edit_notifications' ) and user.get("notifications_enabled"): value = forms.get_input( watolib.get_vs_flexible_notifications(), "notification_method") users[config.user.id]["notification_method"] = value # Custom attributes if config.user.may('general.edit_user_attributes'): for name, attr in userdb.get_user_attributes(): if attr.user_editable(): if not attr.permission() or config.user.may( attr.permission()): vs = attr.valuespec() value = vs.from_html_vars('ua_' + name) vs.validate_value(value, "ua_" + name) users[config.user.id][name] = value # Change the password if requested password_changed = False if config.user.may('general.change_password'): cur_password = html.request.var('cur_password') password = html.request.var('password') password2 = html.request.var('password2', '') if change_pw: # Force change pw mode if not cur_password: raise MKUserError( "cur_password", _("You need to provide your current password.")) if not password: raise MKUserError( "password", _("You need to change your password.")) if cur_password == password: raise MKUserError( "password", _("The new password must differ from your current one." )) if cur_password and password: if userdb.hook_login(config.user.id, cur_password) is False: raise MKUserError("cur_password", _("Your old password is wrong.")) if password2 and password != password2: raise MKUserError( "password2", _("The both new passwords do not match.")) watolib.verify_password_policy(password) users[config.user.id]['password'] = hash_password(password) users[config.user.id]['last_pw_change'] = int(time.time()) if change_pw: # Has been changed, remove enforcement flag del users[config.user.id]['enforce_pw_change'] # Increase serial to invalidate old cookies if 'serial' not in users[config.user.id]: users[config.user.id]['serial'] = 1 else: users[config.user.id]['serial'] += 1 password_changed = True # Now, if in distributed environment where users can login to remote sites, # set the trigger for pushing the new auth information to the slave sites # asynchronous if config.user.authorized_login_sites(): start_async_replication = True userdb.save_users(users) if password_changed: # Set the new cookie to prevent logout for the current user login.set_auth_cookie(config.user.id) success = True except MKUserError as e: html.add_user_error(e.varname, e) else: users = userdb.load_users() watolib.init_wato_datastructures(with_wato_lock=True) # When in distributed setup, display the replication dialog instead of the normal # profile edit dialog after changing the password. if start_async_replication: user_profile_async_replication_page() return if change_pw: title = _("Change Password") else: title = _("Edit User Profile") html.header(title) # Rule based notifications: The user currently cannot simply call the according # WATO module due to WATO permission issues. So we cannot show this button # right now. if not change_pw: rulebased_notifications = watolib.load_configuration_settings().get( "enable_rulebased_notifications") if rulebased_notifications and config.user.may( 'general.edit_notifications'): html.begin_context_buttons() url = "wato.py?mode=user_notifications_p" html.context_button(_("Notifications"), url, "notifications") html.end_context_buttons() else: reason = html.request.var('reason') if reason == 'expired': html.p( _('Your password is too old, you need to choose a new password.' )) else: html.p( _('You are required to change your password before proceeding.' )) if success: html.reload_sidebar() if change_pw: html.show_message(_("Your password has been changed.")) raise HTTPRedirect(html.request.var('_origtarget', 'index.py')) else: html.show_message(_("Successfully updated user profile.")) # Ensure theme changes are applied without additional user interaction html.immediate_browser_redirect(0.5, html.makeuri([])) if html.has_user_errors(): html.show_user_errors() user = users.get(config.user.id) if user is None: html.show_warning(_("Sorry, your user account does not exist.")) html.footer() return # Returns true if an attribute is locked and should be read only. Is only # checked when modifying an existing user locked_attributes = userdb.locked_attributes(user.get('connector')) def is_locked(attr): return attr in locked_attributes html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(_("Personal Settings")) if not change_pw: forms.section(_("Name"), simple=True) html.write_text(user.get("alias", config.user.id)) if config.user.may( 'general.change_password') and not is_locked('password'): forms.section(_("Current Password")) html.password_input('cur_password', autocomplete="new-password") forms.section(_("New Password")) html.password_input('password', autocomplete="new-password") forms.section(_("New Password Confirmation")) html.password_input('password2', autocomplete="new-password") if not change_pw and config.user.may('general.edit_profile'): select_language(user) # Let the user configure how he wants to be notified if not rulebased_notifications \ and config.user.may('general.edit_notifications') \ and user.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.")) watolib.get_vs_flexible_notifications().render_input( "notification_method", user.get("notification_method")) if config.user.may('general.edit_user_attributes'): for name, attr in userdb.get_user_attributes(): if attr.user_editable(): vs = attr.valuespec() forms.section(_u(vs.title())) value = user.get(name, vs.default_value()) if not attr.permission() or config.user.may( attr.permission()): vs.render_input("ua_" + name, value) html.help(_u(vs.help())) else: html.write(vs.value_to_text(value)) # Save button forms.end() html.button("_save", _("Save")) html.close_div() html.hidden_fields() html.end_form() html.footer()
def _show_start_form(self): html.begin_form("parentscan", method="POST") html.hidden_fields() # Mode of action html.open_p() if not self._complete_folder: num_selected = len(get_hosts_from_checkboxes()) html.write_text( _("You have selected <b>%d</b> hosts for parent scan. ") % num_selected) html.p( _("The parent scan will try to detect the last gateway " "on layer 3 (IP) before a host. This will be done by " "calling <tt>traceroute</tt>. If a gateway is found by " "that way and its IP address belongs to one of your " "monitored hosts, that host will be used as the hosts " "parent. If no such host exists, an artifical ping-only " "gateway host will be created if you have not disabled " "this feature.")) forms.header(_("Settings for Parent Scan")) self._settings = config.user.load_file( "parentscan", { "where": "subfolder", "alias": _("Created by parent scan"), "recurse": True, "select": "noexplicit", "timeout": 8, "probes": 2, "ping_probes": 5, "max_ttl": 10, "force_explicit": False, }) # Selection forms.section(_("Selection")) if self._complete_folder: html.checkbox("recurse", self._settings["recurse"], label=_("Include all subfolders")) html.br() html.radiobutton( "select", "noexplicit", self._settings["select"] == "noexplicit", _("Skip hosts with explicit parent definitions (even if empty)") + "<br>") html.radiobutton( "select", "no", self._settings["select"] == "no", _("Skip hosts hosts with non-empty parents (also if inherited)") + "<br>") html.radiobutton("select", "ignore", self._settings["select"] == "ignore", _("Scan all hosts") + "<br>") # Performance forms.section(_("Performance")) html.open_table() html.open_tr() html.open_td() html.write_text(_("Timeout for responses") + ":") html.close_td() html.open_td() html.number_input("timeout", self._settings["timeout"], size=2) html.write_text(_("sec")) html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Number of probes per hop") + ":") html.close_td() html.open_td() html.number_input("probes", self._settings["probes"], size=2) html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Maximum distance (TTL) to gateway") + ":") html.close_td() html.open_td() html.number_input("max_ttl", self._settings["max_ttl"], size=2) html.close_td() html.close_tr() html.open_tr() html.open_td() html.write_text(_("Number of PING probes") + ":") html.help( _("After a gateway has been found, Check_MK checks if it is reachable " "via PING. If not, it is skipped and the next gateway nearer to the " "monitoring core is being tried. You can disable this check by setting " "the number of PING probes to 0.")) html.close_td() html.open_td() html.number_input("ping_probes", self._settings.get("ping_probes", 5), size=2) html.close_td() html.close_tr() html.close_table() # Configuring parent forms.section(_("Configuration")) html.checkbox( "force_explicit", self._settings["force_explicit"], label= _("Force explicit setting for parents even if setting matches that of the folder" )) # Gateway creation forms.section(_("Creation of gateway hosts")) html.write_text(_("Create gateway hosts in")) html.open_ul() html.radiobutton( "where", "subfolder", self._settings["where"] == "subfolder", _("in the subfolder <b>%s/Parents</b>") % watolib.Folder.current_disk_folder().title()) html.br() html.radiobutton( "where", "here", self._settings["where"] == "here", _("directly in the folder <b>%s</b>") % watolib.Folder.current_disk_folder().title()) html.br() html.radiobutton("where", "there", self._settings["where"] == "there", _("in the same folder as the host")) html.br() html.radiobutton("where", "nowhere", self._settings["where"] == "nowhere", _("do not create gateway hosts")) html.close_ul() html.write_text(_("Alias for created gateway hosts") + ": ") html.text_input("alias", self._settings["alias"]) forms.end() # Start button html.button("_start", _("Start")) html.hidden_fields() html.end_form()