def _show_subfolder_infos(self, subfolder): html.open_div(class_="infos") html.open_div(class_="infos_content") groups = load_contact_group_information() permitted_groups, _folder_contact_groups, _use_for_services = subfolder.groups( ) for num, pg in enumerate(permitted_groups): cgalias = groups.get(pg, {'alias': pg})['alias'] html.icon(_("Contactgroups that have permission on this folder"), "contactgroups") html.write_text(' %s' % cgalias) html.br() if num > 1 and len(permitted_groups) > 4: html.write_text( _('<i>%d more contact groups</i><br>') % (len(permitted_groups) - num - 1)) break num_hosts = subfolder.num_hosts_recursively() if num_hosts == 1: html.write_text(_("1 Host")) elif num_hosts > 0: html.write_text("%d %s" % (num_hosts, _("Hosts"))) else: html.i(_("(no hosts)")) html.close_div() html.close_div()
def _render_aux_tag_list(self): with table_element( "auxtags", _("Auxiliary tags"), help=_("Auxiliary tags can be attached to other tags. That way " "you can for example have all hosts with the tag <tt>cmk-agent</tt> " "get also the tag <tt>tcp</tt>. This makes the configuration of " "your hosts easier."), empty_text=_("You haven't defined any auxiliary tags."), searchable=False) as table: for aux_tag in self._effective_config.aux_tag_list.get_tags(): table.row() table.cell(_("Actions"), css="buttons") if aux_tag.id in self._builtin_config.aux_tag_list.get_tag_ids(): html.i("(%s)" % _("builtin")) else: edit_url = watolib.folder_preserving_link([("mode", "edit_auxtag"), ("edit", aux_tag.id)]) delete_url = make_action_link([("mode", "tags"), ("_del_aux", aux_tag.id)]) html.icon_button(edit_url, _("Edit this auxiliary tag"), "edit") html.icon_button(delete_url, _("Delete this auxiliary tag"), "delete") table.text_cell(_("ID"), aux_tag.id) table.text_cell(_("Title"), _u(aux_tag.title)) table.text_cell(_("Topic"), _u(aux_tag.topic) or _("Tags")) table.text_cell( _("Tags using this auxiliary tag"), ", ".join( self._get_tags_using_aux_tag(aux_tag)))
def _show_aux_tag_icons(self, aux_tag: cmk.utils.tags.AuxTag) -> None: if aux_tag.id in self._builtin_config.aux_tag_list.get_tag_ids(): html.i("(%s)" % _("builtin")) return edit_url = watolib.folder_preserving_link([("mode", "edit_auxtag"), ("edit", aux_tag.id)]) html.icon_button(edit_url, _("Edit this auxiliary tag"), "edit")
def _show_tag_icons(self, tag_group, nr): # Tag groups were made builtin with ~1.4. Previously users could modify # these groups. These users now have the modified tag groups in their # user configuration and should be able to cleanup this using the GUI # for the moment. Make the buttons available to the users. if self._builtin_config.tag_group_exists( tag_group.id) and not self._tag_config.tag_group_exists( tag_group.id): html.i("(%s)" % _("builtin")) return edit_url = watolib.folder_preserving_link([("mode", "edit_tag"), ("edit", tag_group.id)]) html.icon_button(edit_url, _("Edit this tag group"), "edit") html.element_dragger_url("tr", base_url=make_action_link([("mode", "tags"), ("_move", nr)])) delete_url = make_confirm_link( url=make_action_link([("mode", "tags"), ("_delete", tag_group.id)]), message=_("Do you really want to delete the tag group '%s'?") % tag_group.id) html.icon_button(delete_url, _("Delete this tag group"), "delete")
def _show_aux_tag_icons(self, aux_tag): # type: (cmk.utils.tags.AuxTag) -> None if aux_tag.id in self._builtin_config.aux_tag_list.get_tag_ids(): html.i("(%s)" % _("builtin")) return edit_url = watolib.folder_preserving_link([("mode", "edit_auxtag"), ("edit", aux_tag.id)]) delete_url = make_action_link([("mode", "tags"), ("_del_aux", aux_tag.id)]) html.icon_button(edit_url, _("Edit this auxiliary tag"), "edit") html.icon_button(delete_url, _("Delete this auxiliary tag"), "delete")
def _show_backup_codes(self, backup_codes: Sequence[str]) -> None: forms.header(_("Backup codes")) forms.section(_("Backup codes"), simple=True) if backup_codes: html.p(_("You have %d unused backup codes left.") % len(backup_codes)) html.i(_("If you regenerate backup codes, you automatically invalidate old codes.")) else: html.i(_("No backup codes created yet.")) forms.end()
def _show_aux_tag_icons(self, aux_tag: cmk.utils.tags.AuxTag) -> None: if aux_tag.id in self._builtin_config.aux_tag_list.get_tag_ids(): html.i("(%s)" % _("builtin")) return edit_url = watolib.folder_preserving_link([("mode", "edit_auxtag"), ("edit", aux_tag.id)]) delete_url = make_confirm_link( url=make_action_link([("mode", "tags"), ("_del_aux", aux_tag.id)]), message=_("Do you really want to delete the auxiliary tag '%s'?") % aux_tag.id) html.icon_button(edit_url, _("Edit this auxiliary tag"), "edit") html.icon_button(delete_url, _("Delete this auxiliary tag"), "delete")
def _show_tag_group_icons(self, tag_group: cmk.utils.tags.TagGroup) -> None: # Tag groups were made builtin with ~1.4. Previously users could modify # these groups. These users now have the modified tag groups in their # user configuration and should be able to cleanup this using the GUI # for the moment. Make the buttons available to the users. if self._builtin_config.tag_group_exists( tag_group.id) and not self._tag_config.tag_group_exists(tag_group.id): html.i("(%s)" % _("builtin")) return edit_url = watolib.folder_preserving_link([("mode", "edit_tag"), ("edit", tag_group.id)]) html.icon_button(edit_url, _("Edit this tag group"), "edit")
def _show_webauthn_credentials( self, webauthn_credentials: dict[str, WebAuthnCredential]) -> None: html.div("", id_="webauthn_message") forms.header(_("WebAuthn credentials")) forms.section(_("Registered credentials"), simple=True) if webauthn_credentials: self._show_credentials(webauthn_credentials) else: html.i(_("No credentials registered")) forms.end()
def _show_tag_icons(self, tag_group, nr): if self._builtin_config.tag_group_exists(tag_group.id): html.i("(%s)" % _("builtin")) return edit_url = watolib.folder_preserving_link([("mode", "edit_tag"), ("edit", tag_group.id)]) html.icon_button(edit_url, _("Edit this tag group"), "edit") html.element_dragger_url("tr", base_url=make_action_link([("mode", "tags"), ("_move", nr)])) delete_url = make_action_link([("mode", "tags"), ("_delete", tag_group.id)]) html.icon_button(delete_url, _("Delete this tag group"), "delete")
def page(self): with table_element("timeperiods", empty_text=_("There are no timeperiods defined yet.")) as table: for name, timeperiod in sorted(self._timeperiods.items()): table.row() table.cell(_("Actions"), css="buttons") if name in watolib.timeperiods.builtin_timeperiods(): html.i(_("(builtin)")) else: self._action_buttons(name) table.text_cell(_("Name"), name) table.text_cell(_("Alias"), timeperiod_spec_alias(timeperiod))
def _show_labels(self, labels, object_type, label_sources): forms.section(_("Effective labels")) html.open_table(class_="setting") html.open_tr() html.open_td(class_="reason") html.i(_("Explicit, ruleset, discovered")) html.close_td() html.open_td(class_=["settingvalue", "used"]) html.write( cmk.gui.view_utils.render_labels( labels, object_type, with_links=False, label_sources=label_sources)) html.close_td() html.close_tr() html.close_table()
def _show_form(self) -> None: assert user.id is not None credentials = load_two_factor_credentials(user.id) webauthn_credentials = credentials["webauthn_credentials"] backup_codes = credentials["backup_codes"] html.begin_form("two_factor", method="POST") html.div("", id_="webauthn_message") forms.header(_("Credentials")) forms.section(_("Registered credentials"), simple=True) if webauthn_credentials: self._show_credentials(webauthn_credentials) else: html.i(_("No credentials registered")) forms.section(_("Backup codes"), simple=True) if backup_codes: html.p( _("You have %d unused backup codes left. You can use them as one-time password " "if your key is not available.") % len(backup_codes)) html.i( _("If you regenerate backup codes, you automatically invalidate the existing codes." )) else: html.i(_("No backup codes created yet.")) forms.end() html.hidden_fields() html.end_form() html.footer()
def _output_analysed_ruleset(self, all_rulesets, rulespec, svc_desc_or_item, svc_desc, known_settings=None): if known_settings is None: known_settings = self._PARAMETERS_UNKNOWN def rule_url(rule): return watolib.folder_preserving_link([ ('mode', 'edit_rule'), ('varname', varname), ('rule_folder', rule.folder.path()), ('rulenr', rule.index()), ('host', self._hostname), ('item', watolib.mk_repr(svc_desc_or_item) if svc_desc_or_item else ''), ('service', watolib.mk_repr(svc_desc) if svc_desc else ''), ]) varname = rulespec.name valuespec = rulespec.valuespec url = watolib.folder_preserving_link([ ('mode', 'edit_ruleset'), ('varname', varname), ('host', self._hostname), ('item', watolib.mk_repr(svc_desc_or_item)), ('service', watolib.mk_repr(svc_desc)), ]) forms.section(html.render_a(rulespec.title, url)) ruleset = all_rulesets.get(varname) setting, rules = ruleset.analyse_ruleset(self._hostname, svc_desc_or_item, svc_desc) html.open_table(class_="setting") html.open_tr() html.open_td(class_="reason") # Show reason for the determined value if len(rules) == 1: rule_folder, rule_index, rule = rules[0] url = rule_url(rule) html.a(_("Rule %d in %s") % (rule_index + 1, rule_folder.title()), href=rule_url(rule)) elif len(rules) > 1: html.a("%d %s" % (len(rules), _("Rules")), href=url) else: html.i(_("Default Value")) html.close_td() # Show the resulting value or factory setting html.open_td( class_=["settingvalue", "used" if len(rules) > 0 else "unused"]) if isinstance(known_settings, dict) and "tp_computed_params" in known_settings: computed_at = known_settings["tp_computed_params"]["computed_at"] html.write_text( _("Timespecific parameters computed at %s") % cmk.utils.render.date_and_time(computed_at)) html.br() known_settings = known_settings["tp_computed_params"]["params"] # In some cases we now the settings from a check_mk automation if known_settings is self._PARAMETERS_OMIT: return # Special handling for logwatch: The check parameter is always None. The actual # patterns are configured in logwatch_rules. We do not have access to the actual # patterns here but just to the useless "None". In order not to complicate things # we simply display nothing here. if varname == "logwatch_rules": pass elif known_settings is not self._PARAMETERS_UNKNOWN: try: html.write(valuespec.value_to_text(known_settings)) except Exception as e: if config.debug: raise html.write_text( _("Invalid parameter %r: %s") % (known_settings, e)) else: # For match type "dict" it can be the case the rule define some of the keys # while other keys are taken from the factory defaults. We need to show the # complete outcoming value here. if rules and ruleset.match_type() == "dict": if rulespec.factory_default is not watolib.Rulespec.NO_FACTORY_DEFAULT \ and rulespec.factory_default is not watolib.Rulespec.FACTORY_DEFAULT_UNUSED: fd = rulespec.factory_default.copy() fd.update(setting) setting = fd if valuespec and not rules: # show the default value if rulespec.factory_default is watolib.Rulespec.FACTORY_DEFAULT_UNUSED: # Some rulesets are ineffective if they are empty html.write_text(_("(unused)")) elif rulespec.factory_default is not watolib.Rulespec.NO_FACTORY_DEFAULT: # If there is a factory default then show that one setting = rulespec.factory_default html.write(valuespec.value_to_text(setting)) elif ruleset.match_type() in ("all", "list"): # Rulesets that build lists are empty if no rule matches html.write_text(_("(no entry)")) else: # Else we use the default value of the valuespec html.write( valuespec.value_to_text(valuespec.default_value())) # We have a setting elif valuespec: if ruleset.match_type() == "all": html.write(", ".join( [valuespec.value_to_text(e) for e in setting])) else: html.write(valuespec.value_to_text(setting)) # Binary rule, no valuespec, outcome is True or False else: icon_name = "rule_%s%s" % ("yes" if setting else "no", "_off" if not rules else '') html.icon(title=_("yes") if setting else _("no"), icon=icon_name) html.close_td() html.close_tr() html.close_table()
def _show_user_list(self): visible_custom_attrs = [ (name, attr) for name, attr in userdb.get_user_attributes() if attr.show_in_table() ] users = userdb.load_users() entries = users.items() html.begin_form("bulk_delete_form", method="POST") roles = userdb.load_roles() timeperiods = watolib.timeperiods.load_timeperiods() contact_groups = load_contact_group_information() with table_element("users", None, empty_text=_("No users are defined yet.")) as table: online_threshold = time.time() - config.user_online_maxage for uid, user in sorted(entries, key=lambda x: x[1].get("alias", x[0]).lower()): table.row() # Checkboxes table.cell(html.render_input("_toggle_group", type_="button", class_="checkgroup", onclick="cmk.selection.toggle_all_rows();", value='X'), sortable=False, css="checkbox") if uid != config.user.id: html.checkbox("_c_user_%s" % base64.b64encode(uid.encode("utf-8"))) user_connection_id = userdb.cleanup_connection_id(user.get('connector')) connection = userdb.get_connection(user_connection_id) # Buttons table.cell(_("Actions"), css="buttons") if connection: # only show edit buttons when the connector is available and enabled edit_url = watolib.folder_preserving_link([("mode", "edit_user"), ("edit", uid)]) html.icon_button(edit_url, _("Properties"), "edit") clone_url = watolib.folder_preserving_link([("mode", "edit_user"), ("clone", uid)]) html.icon_button(clone_url, _("Create a copy of this user"), "clone") delete_url = make_action_link([("mode", "users"), ("_delete", uid)]) html.icon_button(delete_url, _("Delete"), "delete") notifications_url = watolib.folder_preserving_link([("mode", "user_notifications"), ("user", uid)]) if watolib.load_configuration_settings().get("enable_rulebased_notifications"): html.icon_button(notifications_url, _("Custom notification table of this user"), "notifications") # ID table.cell(_("ID"), uid) # Online/Offline if config.save_user_access_times: last_seen = user.get('last_seen', 0) if last_seen >= online_threshold: title = _('Online') img_txt = 'online' elif last_seen != 0: title = _('Offline') img_txt = 'offline' elif last_seen == 0: title = _('Never logged in') img_txt = 'inactive' title += ' (%s %s)' % (render.date(last_seen), render.time_of_day(last_seen)) table.cell(_("Act.")) html.icon(title, img_txt) table.cell(_("Last seen")) if last_seen != 0: html.write_text("%s %s" % (render.date(last_seen), render.time_of_day(last_seen))) else: html.write_text(_("Never logged in")) if cmk.is_managed_edition(): table.cell(_("Customer"), managed.get_customer_name(user)) # Connection if connection: table.cell(_("Connection"), '%s (%s)' % (connection.short_title(), user_connection_id)) locked_attributes = userdb.locked_attributes(user_connection_id) else: table.cell(_("Connection"), "%s (%s) (%s)" % (_("UNKNOWN"), user_connection_id, _("disabled")), css="error") locked_attributes = [] # Authentication if "automation_secret" in user: auth_method = _("Automation") elif user.get("password") or 'password' in locked_attributes: auth_method = _("Password") else: auth_method = "<i>%s</i>" % _("none") table.cell(_("Authentication"), auth_method) table.cell(_("State")) if user.get("locked", False): html.icon(_('The login is currently locked'), 'user_locked') if "disable_notifications" in user and isinstance(user["disable_notifications"], bool): disable_notifications_opts = {"disable": user["disable_notifications"]} else: disable_notifications_opts = user.get("disable_notifications", {}) if disable_notifications_opts.get("disable", False): html.icon(_('Notifications are disabled'), 'notif_disabled') # Full name / Alias table.text_cell(_("Alias"), user.get("alias", "")) # Email table.text_cell(_("Email"), user.get("email", "")) # Roles table.cell(_("Roles")) if user.get("roles", []): role_links = [(watolib.folder_preserving_link([("mode", "edit_role"), ("edit", role)]), roles[role].get("alias")) for role in user["roles"]] html.write_html( HTML(", ").join( html.render_a(alias, href=link) for (link, alias) in role_links)) # contact groups table.cell(_("Contact groups")) cgs = user.get("contactgroups", []) if cgs: cg_aliases = [ contact_groups[c]['alias'] if c in contact_groups else c for c in cgs ] cg_urls = [ watolib.folder_preserving_link([("mode", "edit_contact_group"), ("edit", c)]) for c in cgs ] html.write_html( HTML(", ").join( html.render_a(content, href=url) for (content, url) in zip(cg_aliases, cg_urls))) else: html.i(_("none")) #table.cell(_("Sites")) #html.write(vs_authorized_sites().value_to_text(user.get("authorized_sites", # vs_authorized_sites().default_value()))) # notifications if not watolib.load_configuration_settings().get("enable_rulebased_notifications"): table.cell(_("Notifications")) if not cgs: html.i(_("not a contact")) elif not user.get("notifications_enabled", True): html.write_text(_("disabled")) elif user.get("host_notification_options", "") == "" and \ user.get("service_notification_options", "") == "": html.write_text(_("all events disabled")) else: tp = user.get("notification_period", "24X7") if tp not in timeperiods: tp = tp + _(" (invalid)") elif tp not in watolib.timeperiods.builtin_timeperiods(): url = watolib.folder_preserving_link([("mode", "edit_timeperiod"), ("edit", tp)]) tp = html.render_a(timeperiods[tp].get("alias", tp), href=url) else: tp = timeperiods[tp].get("alias", tp) html.write(tp) # the visible custom attributes for name, attr in visible_custom_attrs: vs = attr.valuespec() table.cell(html.attrencode(_u(vs.title()))) html.write(vs.value_to_text(user.get(name, vs.default_value()))) html.button("_bulk_delete_users", _("Bulk Delete"), "submit", style="margin-top:10px") html.hidden_fields() html.end_form() if not load_contact_group_information(): url = "wato.py?mode=contact_groups" html.open_div(class_="info") html.write( _("Note: you haven't defined any contact groups yet. If you <a href='%s'>" "create some contact groups</a> you can assign users to them und thus " "make them monitoring contacts. Only monitoring contacts can receive " "notifications.") % url) html.write(" you can assign users to them und thus " "make them monitoring contacts. Only monitoring contacts can receive " "notifications.") html.close_div()
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 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 # 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 = html.request.var('_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.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