def _render_aux_tag_list(self): # type: () -> None 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") self._show_aux_tag_icons(aux_tag) 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( sorted(tag.id for tag in self._get_tags_using_aux_tag(aux_tag) if tag.id is not None)))
def _show_tag_row(self, table, tag_group, tag): # type: (Table, cmk.utils.tags.TagGroup, cmk.utils.tags.GroupedTag) -> None table.row() table.cell(_("Actions"), css="buttons") self._show_tag_group_icons(tag_group) table.text_cell(_("Tag group"), _u(tag_group.choice_title)) # TODO: This check shouldn't be necessary if we get our types right. if tag.title is None or tag.id is None or tag_group.id is None: raise Exception("uninitialized tag/tag group") table.text_cell(_("Tag"), _u(tag.title)) operation = OperationReplaceGroupedTags(tag_group.id, remove_tag_ids=[tag.id], replace_tag_ids={}) affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder()) table.cell(_("Explicitly set on folders")) if affected_folders: _show_affected_folders(affected_folders) table.cell(_("Explicitly set on hosts")) if affected_hosts: _show_affected_hosts(affected_hosts) table.cell(_("Used in rulesets")) if affected_rulesets: _show_affected_rulesets(affected_rulesets)
def visuals_by_topic(permitted_visuals, default_order=None): if default_order is None: default_order = [ _("Overview"), _("Hosts"), _("Host Groups"), _("Services"), _("Service Groups"), _("Metrics"), _("Business Intelligence"), _("Problems"), ] s = sorted([(_u(visual.get("topic") or _("Other")), _u(visual.get("title")), name, 'painters' in visual) for name, visual in permitted_visuals if not visual["hidden"] and not visual.get("mobile")]) result = [] for topic in default_order: result.append((topic, s)) rest = sorted({t for (t, _t, _v, _i) in s if t not in default_order}) for topic in rest: if topic: result.append((topic, s)) return result
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_form(self, profile_changed: bool) -> None: assert config.user.id is not None users = userdb.load_users() if profile_changed: html.reload_sidebar() html.show_message(_("Successfully updated user profile.")) # Ensure theme changes are applied without additional user interaction html.immediate_browser_redirect(0.5, makeuri(global_request, [])) 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 html.begin_form("profile", method="POST") html.prevent_password_auto_completion() html.open_div(class_="wato") forms.header(self._page_title()) 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'): 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)) forms.end() html.close_div() html.hidden_fields() html.end_form() html.footer()
def _show_tag_row(self, table, tag_group, tag): # type: (Table, cmk.utils.tags.TagGroup, cmk.utils.tags.GroupedTag) -> None table.row() table.cell(_("Actions"), css="buttons") self._show_tag_group_icons(tag_group) table.text_cell(_("Tag group"), _u(tag_group.choice_title)) table.text_cell(_("Tag"), _u(tag.title)) operation = OperationReplaceGroupedTags(tag_group.id, remove_tag_ids=[tag.id], replace_tag_ids={}) affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder()) table.cell(_("Explicitly set on folders")) if affected_folders: _show_affected_folders(affected_folders) table.cell(_("Explicitly set on hosts")) if affected_hosts: _show_affected_hosts(affected_hosts) table.cell(_("Used in rulesets")) if affected_rulesets: _show_affected_rulesets(affected_rulesets)
def _show_custom_user_attr(user, custom_attr): for name, attr in custom_attr: 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))
def _show_custom_user_attributes(self, custom_attr): for name, attr in custom_attr: 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 _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 _show_aux_tag_row(self, table, aux_tag): # type: (Table, cmk.utils.tags.AuxTag) -> None table.row() table.cell(_("Actions"), css="buttons") self._show_aux_tag_icons(aux_tag) table.text_cell(_("Tag"), _u(aux_tag.choice_title)) table.text_cell(_("Used by tags")) _show_aux_tag_used_by_tags(self._get_tags_using_aux_tag(aux_tag)) operation = OperationRemoveAuxTag(aux_tag.id) affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder()) table.cell(_("Explicitly set on folders")) if affected_folders: _show_affected_folders(affected_folders) table.cell(_("Explicitly set on hosts")) if affected_hosts: _show_affected_hosts(affected_hosts) table.cell(_("Used in rulesets")) if affected_rulesets: _show_affected_rulesets(affected_rulesets)
def load_plugins(force: bool) -> None: for name, attrs in watolib.load_notification_scripts().items(): if name[0] == ".": continue declare_permission("notification_plugin.%s" % name, _u(attrs["title"]), u"", ["admin", "user"])
def _show_aux_tag_row(self, table, aux_tag): # type: (Table, cmk.utils.tags.AuxTag) -> None table.row() table.cell(_("Actions"), css="buttons") self._show_aux_tag_icons(aux_tag) table.text_cell(_("Tag"), _u(aux_tag.choice_title)) table.text_cell(_("Used by tags")) _show_aux_tag_used_by_tags(self._get_tags_using_aux_tag(aux_tag)) # TODO: This check shouldn't be necessary if we get our types right. if aux_tag.id is None: raise Exception("uninitialized tag") operation = OperationRemoveAuxTag(aux_tag.id) affected_folders, affected_hosts, affected_rulesets = \ _change_host_tags_in_folders(operation, TagCleanupMode.CHECK, watolib.Folder.root_folder()) table.cell(_("Explicitly set on folders")) if affected_folders: _show_affected_folders(affected_folders) table.cell(_("Explicitly set on hosts")) if affected_hosts: _show_affected_hosts(affected_hosts) table.cell(_("Used in rulesets")) if affected_rulesets: _show_affected_rulesets(affected_rulesets)
def text_with_links_to_user_translated_html( elements: Iterable[Tuple[str, Optional[str]]], separator: str = "", ) -> HTML: return HTML(separator).join( html.render_a(user_translation, href=url) if url else user_translation for txt, url in elements for user_translation in [_u(txt)] if txt)
def declare_notification_plugin_permissions() -> None: for name, attrs in load_notification_scripts().items(): if name[0] == ".": continue declare_permission("notification_plugin.%s" % name, _u(attrs["title"]), "", ["admin", "user"])
def render(self, what): html.write_text(_('Downtime Comment') + ": ") html.text_input("_down_comment", "", size=60, submit="") html.hr() html.button("_down_from_now", _("From now for")) html.nbsp() html.number_input("_down_minutes", 60, size=4, submit="_down_from_now") html.write_text(" " + _("minutes")) html.hr() for time_range in config.user_downtime_timeranges: html.button("_downrange__%s" % time_range['end'], _u(time_range['title'])) if what != "aggr" and config.user.may("action.remove_all_downtimes"): html.write_text(" - ") html.button("_down_remove", _("Remove all")) html.hr() if config.adhoc_downtime and config.adhoc_downtime.get("duration"): adhoc_duration = config.adhoc_downtime.get("duration") adhoc_comment = config.adhoc_downtime.get("comment", "") html.button("_down_adhoc", _("Adhoc for %d minutes") % adhoc_duration) html.nbsp() html.write_text(_('with comment') + ": ") html.write(adhoc_comment) html.hr() html.button("_down_custom", _("Custom time range")) html.datetime_input("_down_from", time.time(), submit="_down_custom") html.write_text(" " + _('to') + " ") html.datetime_input("_down_to", time.time() + 7200, submit="_down_custom") html.hr() html.checkbox("_down_flexible", False, label="%s " % _('flexible with max. duration')) html.time_input("_down_duration", 2, 0) html.write_text(" " + _('(HH:MM)')) if what == "host": html.hr() html.checkbox("_include_childs", False, label=_('Also set downtime on child hosts')) html.write_text(" ") html.checkbox("_include_childs_recurse", False, label=_('Do this recursively')) elif what == "service": html.hr() html.checkbox("_on_hosts", False, label=_('Schedule downtimes on the affected ' '<b>hosts</b> instead of on the individual ' 'services')) if self._has_recurring_downtimes(): html.hr() html.checkbox("_down_do_recur", False, label=_("Repeat this downtime on a regular basis every")) html.write_text(" ") from cmk.gui.cee.plugins.wato.cmc import recurring_downtimes_types # pylint: disable=no-name-in-module recurring_selections = [ (str(k), v) for (k, v) in sorted(recurring_downtimes_types().items()) ] html.dropdown("_down_recurring", recurring_selections, deflt="3") html.write_text(_("(This only works when using CMC)"))
def valuespec(self): choice = self._tag_group.get_tag_choices()[0] return Checkbox( title=self._tag_group.title, label=_u(choice[1]), true_label=self._tag_group.title, false_label="%s %s" % (_("Not"), self._tag_group.title), onclick="cmk.wato.fix_visibility();", )
def text_with_links_to_user_translated_html( elements: Iterable[Tuple[str, Optional[str]]], separator: str = "", ) -> HTML: return HTML(separator).join( html.render_a(user_translation, href=url, title=user_translation ) if url else escape_to_html_permissive( user_translation, escape_links=False) for txt, url in elements for user_translation in [_u(txt)] if txt)
def _show_aux_tag_used_by_tags(tags: Set[cmk.utils.tags.GroupedTag]) -> None: if not tags: return html.open_ul() html.open_li() builtin_config = cmk.utils.tags.BuiltinTagConfig() for index, tag in enumerate(sorted(tags, key=lambda t: t.choice_title)): if index > 0: html.write_text(", ") # Builtin tag groups can not be edited if builtin_config.tag_group_exists(tag.group.id): html.write_text(_u(tag.choice_title)) else: edit_url = watolib.folder_preserving_link([("mode", "edit_tag"), ("edit", tag.group.id)]) html.a(_u(tag.choice_title), href=edit_url) html.close_li() html.close_ul()
def _title_help_text_for_macros(dashlet_type: Type[Dashlet]) -> str: available_macros = chain( ["$DEFAULT_TITLE$ " + _u("(default title of the element)")], _get_title_macros_from_single_infos(dashlet_type.single_infos()), dashlet_type.get_additional_title_macros(), ) macros_as_list = f"<ul>{''.join(f'<li><tt>{macro}</tt></li>' for macro in available_macros)}</ul>" return _("You can use the following macros to fill in the corresponding information:%s%s") % ( macros_as_list, _("These macros can be combined with arbitrary text elements, e.g. \"some text " "<tt>$MACRO1$</tt> -- <tt>$MACRO2$</tt>\"."), )
def render_title_with_macros_string( context: VisualContext, single_infos: SingleInfos, title: str, default_title: str, **additional_macros: str, ): return replace_macros_in_str( _u(title), macro_mapping_from_context( context, single_infos, title, default_title, **additional_macros, ), )
def user_script_choices(what): scripts = load_user_scripts(what) choices = [(name, info["title"]) for (name, info) in scripts.items()] choices = [(k, _u(v)) for k, v in sorted(choices, key=lambda x: x[1])] return choices
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 render_title_with_macros_string( title: str, macro_mapping: MacroMapping, ): return replace_macros_in_str(_u(title), macro_mapping)
def render_title(self) -> str: return _u(self.title())
def user_script_choices(what): scripts = load_user_scripts(what) choices = [(name, info["title"]) for (name, info) in scripts.items()] choices.sort(cmp=lambda a, b: cmp(a[1], b[1])) choices = [(k, _u(v)) for k, v in choices] return choices
def render_title_elements_plain(elements: Iterable[str]) -> str: return " / ".join(_u(txt) for txt in elements if txt)
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 render(self, what): html.open_div(class_="group") html.text_input("_down_comment", id_="down_comment", size=60, label=_("Comment"), required=True) html.close_div() html.open_div(class_="group") html.button("_down_from_now", _("From now for"), cssclass="hot") html.nbsp() html.text_input("_down_minutes", default_value="60", size=4, submit="_down_from_now", cssclass="number") html.write_text(" " + _("minutes")) html.close_div() html.open_div(class_="group") for time_range in config.user_downtime_timeranges: html.button("_downrange__%s" % time_range['end'], _u(time_range['title'])) if what != "aggr" and config.user.may("action.remove_all_downtimes"): html.write_text(" - ") html.button("_down_remove", _("Remove all")) html.close_div() if config.adhoc_downtime and config.adhoc_downtime.get("duration"): adhoc_duration = config.adhoc_downtime.get("duration") adhoc_comment = config.adhoc_downtime.get("comment", "") html.open_div(class_="group") html.button("_down_adhoc", _("Adhoc for %d minutes") % adhoc_duration) html.nbsp() html.write_text(_('with comment') + ": ") html.write(adhoc_comment) html.close_div() html.open_div(class_="group") html.button("_down_custom", _("Custom time range")) self._vs_down_from().render_input("_down_from", time.time()) html.write_text(" " + _('to') + " ") self._vs_down_to().render_input("_down_to", time.time() + 7200) html.close_div() html.open_div(class_="group") html.checkbox("_down_flexible", False, label="%s " % _('flexible with max. duration')) self._vs_duration().render_input("_down_duration", 7200) html.close_div() if what == "host": html.open_div(class_="group") html.checkbox("_include_childs", False, label=_('Also set downtime on child hosts')) html.write_text(" ") html.checkbox("_include_childs_recurse", False, label=_('Do this recursively')) html.close_div() elif what == "service": html.open_div(class_="group") html.checkbox("_on_hosts", False, label=_('Schedule downtimes on the affected ' '<b>hosts</b> instead of on the individual ' 'services')) html.close_div() if self._has_recurring_downtimes(): html.open_div(class_="group") html.checkbox("_down_do_recur", False, label=_("Repeat this downtime on a regular basis every")) from cmk.gui.cee.plugins.wato.cmc import recurring_downtimes_types # pylint: disable=no-name-in-module,import-outside-toplevel recurring_selections: Choices = [ (str(k), v) for (k, v) in sorted(recurring_downtimes_types().items()) ] html.dropdown("_down_recurring", recurring_selections, deflt="3") html.write_text(" " + _("(only works with the microcore)")) html.close_div()
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 render_title(self): # type: () -> Text return _u(self.title())