magpie.ui.management.views ========================== .. py:module:: magpie.ui.management.views Attributes ---------- .. autoapisummary:: magpie.ui.management.views.OUT_OF_SYNC magpie.ui.management.views.SYNC_SERVICES_TYPES magpie.ui.management.views.REMOTE_RESOURCE_TREE_SERVICE magpie.ui.management.views.RESOURCE_TYPE_DICT magpie.ui.management.views.SERVICE_TYPE_DICT magpie.ui.management.views.CONTENT_TYPE_JSON magpie.ui.management.views.LOGGER Classes ------- .. autoapisummary:: magpie.ui.management.views.UserGroupStatus magpie.ui.management.views.UserStatuses magpie.ui.management.views.Permission magpie.ui.management.views.PermissionSet magpie.ui.management.views.AdminRequests magpie.ui.management.views.BaseViews magpie.ui.management.views.ManagementViews Functions --------- .. autoapisummary:: magpie.ui.management.views.fetch_single_service magpie.ui.management.views.get_last_sync magpie.ui.management.views.merge_local_and_remote_resources magpie.ui.management.views.get_constant magpie.ui.management.views.check_response magpie.ui.management.views.handle_errors magpie.ui.management.views.request_api magpie.ui.management.views.get_json magpie.ui.management.views.get_logger magpie.ui.management.views.is_json_body Module Contents --------------- .. py:data:: OUT_OF_SYNC .. py:function:: fetch_single_service(service: Union[magpie.models.Service, int], session: sqlalchemy.orm.session.Session) -> None Get remote resources for a single service. :param service: Specific service for which to synchronize remote resources. :param session: Database connexion to apply synchronization changes. .. py:function:: get_last_sync(service_id: int, session: sqlalchemy.orm.session.Session) -> Optional[datetime.datetime] Obtain the date-time of the last known sync event for a service. .. py:function:: merge_local_and_remote_resources(resources_local: magpie.typedefs.RemoteResourceTree, service_sync_type: magpie.typedefs.Str, service_id: int, session: sqlalchemy.orm.session.Session) -> magpie.typedefs.RemoteResourceTree Main function to sync resources with remote server. .. py:data:: SYNC_SERVICES_TYPES :type: Dict[magpie.typedefs.Str, Type[SyncServiceInterface]] .. py:function:: get_constant(constant_name: magpie.typedefs.Str, settings_container: Optional[magpie.typedefs.AnySettingsContainer] = None, settings_name: Optional[magpie.typedefs.Str] = None, default_value: Optional[magpie.typedefs.SettingValue] = None, raise_not_set: bool = True, raise_missing: bool = True, print_missing: bool = False, empty_missing: bool = False) -> magpie.typedefs.SettingValue Search in order for matched value of :paramref:`constant_name`: 1. search in :py:data:`MAGPIE_CONSTANTS` 2. search in settings if specified 3. search alternative setting names (see below) 4. search in :mod:`magpie.constants` definitions 5. search in environment variables Parameter :paramref:`constant_name` is expected to have the format ``MAGPIE_[VARIABLE_NAME]`` although any value can be passed to retrieve generic settings from all above-mentioned search locations. If :paramref:`settings_name` is provided as alternative name, it is used as is to search for results if :paramref:`constant_name` was not found. Otherwise, ``magpie.[variable_name]`` is used for additional search when the format ``MAGPIE_[VARIABLE_NAME]`` was used for :paramref:`constant_name` (i.e.: ``MAGPIE_ADMIN_USER`` will also search for ``magpie.admin_user`` and so on for corresponding constants). :param constant_name: key to search for a value :param settings_container: WSGI application settings container (if not provided, uses found one in current thread) :param settings_name: alternative name for `settings` if specified :param default_value: default value to be returned if not found anywhere, and exception raises are disabled. :param raise_not_set: raise an exception if the found key is ``None``, search until last case if others are ``None`` :param raise_missing: raise exception if key is not found anywhere :param print_missing: print message if key is not found anywhere, return ``None`` :param empty_missing: consider an empty value for an existing key as if it was missing (i.e.: as if not set). :returns: found value or `default_value` :raises ValueError: if resulting value is invalid based on options (by default raise missing/empty/``None`` value) :raises LookupError: if no appropriate value could be found from all search locations (according to options) .. py:data:: REMOTE_RESOURCE_TREE_SERVICE .. py:data:: RESOURCE_TYPE_DICT :type: Dict[magpie.typedefs.Str, Type[Resource]] .. py:class:: UserGroupStatus Bases: :py:obj:`magpie.utils.FlexibleNameEnum` Supported statuses of user-group relationships. .. py:attribute:: ALL :value: 'all' .. py:attribute:: ACTIVE :value: 'active' .. py:attribute:: PENDING :value: 'pending' .. py:method:: allowed() -> List[magpie.typedefs.Str] :classmethod: Returns all supported representation values that can be mapped to a valid status. .. py:class:: UserStatuses Bases: :py:obj:`enum.IntFlag`, :py:obj:`magpie.utils.FlexibleNameEnum` Values applicable to :term:`User` statues. Provides allowed values for the ``status`` search query of :class:`User` and :class:`UserPending` entries. Also, defines the possible values of :attr:`User.status` field, omitting :attr:`UserStatuses.Pending` reserved for objects defined by :class:`UserPending`. Initialize self. See help(type(self)) for accurate signature. .. py:attribute:: OK :value: 1 .. py:attribute:: WebhookError :value: 2 .. py:attribute:: Pending :value: 4 .. py:method:: _get_one(status: AnyUserStatus) -> Optional[UserStatuses] :classmethod: .. py:method:: get(status: Union[None, int, magpie.typedefs.Str, UserStatuses, Iterable[None, int, magpie.typedefs.Str, UserStatuses]], default: Optional[UserStatuses] = None) -> Optional[UserStatuses] :classmethod: Obtains the combined flag :class:`UserStatuses` .. py:method:: allowed() -> List[Union[None, int, magpie.typedefs.Str]] :classmethod: Returns all supported representation values that can be mapped to a valid status for :class:`UserSearchService`. .. py:method:: all() -> UserStatuses :classmethod: Representation of all flags combined. .. py:method:: __or__(other: Union[UserStatuses, int]) -> UserStatuses Return self|value. .. py:method:: __and__(other: Union[UserStatuses, int]) -> UserStatuses Return self&value. .. py:method:: __xor__(other: Union[UserStatuses, int]) -> UserStatuses Return self^value. .. py:method:: __iter__() -> Iterable[UserStatuses] .. py:method:: __len__() .. py:class:: Permission Bases: :py:obj:`magpie.utils.ExtendedEnum` Applicable :term:`Permission` values (names) under certain :term:`Service` and :term:`Resource`. .. py:attribute:: READ :value: 'read' .. py:attribute:: WRITE :value: 'write' .. py:attribute:: ACCESS :value: 'access' .. py:attribute:: BROWSE :value: 'browse' .. py:attribute:: GET_CAPABILITIES :value: 'getcapabilities' .. py:attribute:: GET_MAP :value: 'getmap' .. py:attribute:: GET_FEATURE_INFO :value: 'getfeatureinfo' .. py:attribute:: GET_LEGEND_GRAPHIC :value: 'getlegendgraphic' .. py:attribute:: GET_METADATA :value: 'getmetadata' .. py:attribute:: GET_PROPERTY_VALUE :value: 'getpropertyvalue' .. py:attribute:: GET_FEATURE :value: 'getfeature' .. py:attribute:: GET_FEATURE_WITH_LOCK :value: 'getfeaturewithlock' .. py:attribute:: GET_GML_OBJECT :value: 'getgmlobject' .. py:attribute:: DESCRIBE_FEATURE_TYPE :value: 'describefeaturetype' .. py:attribute:: DESCRIBE_LAYER :value: 'describelayer' .. py:attribute:: DESCRIBE_PROCESS :value: 'describeprocess' .. py:attribute:: EXECUTE :value: 'execute' .. py:attribute:: LOCK_FEATURE :value: 'lockfeature' .. py:attribute:: TRANSACTION :value: 'transaction' .. py:attribute:: CREATE_STORED_QUERY :value: 'createstoredquery' .. py:attribute:: DROP_STORED_QUERY :value: 'dropstoredquery' .. py:attribute:: LIST_STORED_QUERIES :value: 'liststoredqueries' .. py:attribute:: DESCRIBE_STORED_QUERIES :value: 'describestoredqueries' .. py:class:: PermissionSet(permission: magpie.typedefs.AnyPermissionType, access: Optional[Union[Access, magpie.typedefs.Str]] = None, scope: Optional[Union[Scope, magpie.typedefs.Str]] = None, typ: Optional[PermissionType] = None, reason: Optional[magpie.typedefs.Str] = None) Bases: :py:obj:`object` Explicit definition of a :class:`Permission` with applicable :class:`Access` and :class:`Scope` to resolve it. The :class:`Permission` is the *name* of the applicable permission on the :class:`magpie.models.Resource`. The :class:`Scope` defines how the :class:`Permission` should impact the resolution of the perceived :term:`Effective Permissions ` over a :class:`magpie.models.Resource` tree hierarchy. The :class:`Access` defines how the :class:`Permission` access should be interpreted (granted or denied). Optionally, a :class:`PermissionType` can be provided to specifically indicate which kind of permission this set represents. This type is only for informative purposes, and is not saved to database nor displayed by the explicit string representation. It is returned within JSON representation and can be employed by :term:`Effective Permissions ` resolution to be more verbose about returned results. On missing :class:`Access` or :class:`Scope` specifications, they default to :attr:`Access.ALLOW` and :attr:`Scope.RECURSIVE` to handle backward compatible naming convention of plain ``permission_name``. Initializes the permission definition, possibly using required conversion from other implementations. :param permission: Name of the permission, or any other implementation from which the name can be inferred. :param access: Effective behaviour of the permissions. Generally, grant or deny the specified permission. :param scope: Scope for which the permission affects hierarchical resources. Important for effective resolution. :param typ: Type of permission being represented. Informative only, does not impact behavior if omitted. :param reason: Slightly more indicative information on why the current permission-type has this value. Value should be either explicitly provided or will be inferred if converted from input PermissionTuple. .. seealso:: :meth:`PermissionSet._convert` .. py:attribute:: __slots__ :value: ['_name', '_access', '_scope', '_tuple', '_type', '_reason'] .. py:method:: __eq__(other: Any) -> bool Return self==value. .. py:method:: __ne__(other: Any) -> bool Return self!=value. .. py:method:: __lt__(other: Any) -> bool Ascending sort of permission according to their name, access and scope modifiers. First sort by permission name alphabetically, followed by increasing *restrictive access* and increasing *range of scoped resources*. Using this sorting methodology, similar permissions by name are grouped together first, and permissions of same name with modifiers are then ordered, the first having less priority when selecting a single item to display with conflicting possibilities. Respecting :attr:`Access.DENY` is more important than :attr:`Access.ALLOW` (to protect the :term:`Resource`), and :attr:`Scope.MATCH` is *closer* to the actual :term:`Resource` than :attr:`Scope.RECURSIVE` permission received from a *farther* parent in the hierarchy. Sorted explicit string representation becomes:: [name1]-[allow]-[match] [name1]-[allow]-[recursive] [name1]-[deny]-[match] [name1]-[deny]-[recursive] [name2]-[allow]-[match] [name2]-[allow]-[recursive] [name2]-[deny]-[match] [name2]-[deny]-[recursive] ... We then obtain two **crucial** ordering results: 1. We can easily pick the last sorted item with highest resolution priority to find the final result of corresponding permissions. (note: final result for same user or group, their direct/inherited resolution is not considered here). 2. Picking the first element with lowest priority also displays the permission that impacts the widest range of resources. For instance in Magpie UI, indicating that a permission as :attr:`Scope.RECURSIVE` is more verbose as it tell other resources under it are also receive the specified :class:`Access` modifier rather than only the punctual resource. .. warning:: Alphabetically sorting permissions by string representation (implicit/explicit) is not equivalent to sorting them according to :term:`Permission` priority according to how modifiers are resolved. To obtain the prioritized sorting as strings, a list of :class:`PermissionSet` (with the strings as input) should be used to convert and correctly interpreted the raw strings, and then be converted back after sorting. .. code-block:: python # valid priority-sorted strings [str(perm) for perm in sorted(PermissionSet(p) for p in permission_strings)] # not equivalent to raw sorting list(sorted(permission_strings)) .. py:method:: __hash__() -> int Return hash(self). .. py:method:: __str__() -> magpie.typedefs.Str Obtains the compound literal representation of the :class:`PermissionSet`. Employed for database storage supporting ``ziggurat`` format. .. py:method:: __repr__() -> magpie.typedefs.Str Obtains the visual representation of the :class:`PermissionSet`. .. py:method:: like(other: Any) -> bool Evaluates if one permission is *similar* to another permission definition regardless of *modifiers*. This is different than ``==`` operator which will evaluate *exactly* equal permission definitions. .. py:method:: json() -> magpie.typedefs.PermissionDict Obtains the JSON representation of this :class:`PermissionSet`. .. py:method:: webhook_params() -> magpie.typedefs.JSON Obtain JSON representation employed for :term:`Webhook` reference. .. py:method:: ace(user_or_group: Optional[Union[magpie.models.User, magpie.models.Group]]) -> magpie.typedefs.AccessControlEntryType Converts the :class:`PermissionSet` into an :term:`ACE` that :mod:`pyramid` can understand. .. py:property:: reason :type: Optional[magpie.typedefs.Str] Indicative reason of the returned value defined by :meth:`type` or inferred by the :class:`PermissionTuple`. .. seealso:: :meth:`combine` :returns: Single string that describes the reason (source) of the permission, or multiple strings if updated by combination of multiple permissions. .. py:method:: resolve(permission1: magpie.typedefs.ResolvablePermissionType, permission2: magpie.typedefs.ResolvablePermissionType, context: PermissionType = PermissionType.INHERITED, multiple_choice: Optional[magpie.typedefs.Str] = None) -> magpie.typedefs.ResolvablePermissionType :classmethod: Resolves provided permissions into a single one considering various modifiers and groups for a resource. Permissions **MUST** have the same :term:`Permission` name. The associated :term:`Resource` on which the two compared permissions are applied on should also be the same This method **SHOULD NOT** be used by itself to obtain for :term:`Effective Permission` since it does not handle multi-level :term:`Resource` resolution. Resolution is accomplished in this case only for a given level in the tree hierarchy. The comparison considers both the :class:`Access` and :class:`Scope` of every :term:`Inherited Permission` of the :term:`User`, as well as its :term:`Group` memberships sorted by their priority. .. seealso:: - :meth:`magpie.services.ServiceInterface.effective_permissions` - :func:`magpie.api.management.user.user_utils.combine_user_group_permissions` - :meth:`PermissionSet.__lt__` :param permission1: Permission to compare. :param permission2: Permission to compare. :param context: Control the resolution context (local/effective) of the permissions (safeguard against invalid definitions). :param multiple_choice: Alternate explanation to default :data:`PERMISSION_REASON_MULTIPLE` applied if multiple :term:`Permission` refer to distinct :term:`Group` of equal priority and equivalent access definitions, meaning they are interchangeable without impacting resolution to access the same target :term:`Resource`. :returns: Permission with highest priority to resolve access a resource without considering scope. .. py:property:: group_priority :type: Optional[magpie.typedefs.GroupPriority] Priority accessor in case of group inherited permission resolved by :class:`PermissionTuple`. .. py:property:: perm_tuple :type: Optional[ziggurat_foundations.permissions.PermissionTuple] Get the original :class:`PermissionTuple` if available (:class:`PermissionSet` must have been created by one). .. py:property:: implicit_permission :type: Optional[magpie.typedefs.Str] Obtain the implicit string representation of the :class:`PermissionSet` as plain :class:`Permission` name. This representation is backward compatible with prior versions of `Magpie` where explicit representation of permission names in the database did not exist. If the contained modifiers of the :class:`PermissionSet` (notably the :attr:`Access.DENY`) result in a string representation that is *not possible* according to non existing permissions for older `Magpie` instances, the returned value will be ``None``. .. seealso:: - :meth:`explicit_permission` for the new representation. .. py:property:: explicit_permission :type: magpie.typedefs.Str Obtain the explicit string representation of the :class:`PermissionSet`. This format is always guaranteed to be completely defined contrary to :meth:`implicit_permission`. .. seealso:: - :meth:`__str__` (default string value). - :meth:`implicit_permission` for the old representation. .. py:property:: name :type: Permission .. py:attribute:: permission .. py:property:: access :type: Access .. py:property:: scope :type: Scope .. py:property:: type :type: Optional[PermissionType] .. py:method:: _convert(permission: magpie.typedefs.AnyPermissionType) -> Optional[PermissionSet] :classmethod: Converts any permission representation to the :class:`PermissionSet` with applicable enum members. Supports older :class:`Permission` representation such that implicit conversion of permission name without :attr:`access` and :attr:`scope` values are padded with defaults. Also, pre-defined partial or full definition from literal string representation are parsed to generate the :class:`PermissionSet` instance. :param permission: implicit or explicit permission name string, or any other known permission implementation :raises ValueError: when the permission name cannot be identified or parsed .. py:data:: SERVICE_TYPE_DICT .. py:class:: AdminRequests(request) Bases: :py:obj:`BaseViews` Regroups multiple administration-level operations to be dispatched to the API requests. .. py:method:: create_user_default_template_data(data) Generates all the default values for the various fields employed for display purposes of the user creation form. :param data: any template data that should override the defaults. :return: updated template data with defaults and overridden values. .. seealso: :meth:`create_user` .. py:method:: get_admin_session() -> magpie.typedefs.CookiesType Temporarily login as default administrator to execute an elevated operation that the current user cannot make. .. warning:: Cookies *MUST NOT* be preserved or memorized, to avoid user gaining restricted access. This is intended only for basic operations such as validating information. Care must be taken such information retrieved this way do not provide a way of non-administrator to indirectly infer some otherwise protected information. User sparingly. :returns: Cookies of the administrator login. .. py:method:: get_all_groups(first_default_group=None) .. py:method:: get_group_info(group_name: magpie.typedefs.Str) -> magpie.typedefs.JSON .. py:method:: get_group_users(group_name: magpie.typedefs.Str, user_group_status: magpie.models.UserGroupStatus = UserGroupStatus.ACTIVE) -> List[magpie.typedefs.Str] .. py:method:: update_group_info(group_name: magpie.typedefs.Str, group_info: magpie.typedefs.JSON) -> magpie.typedefs.JSON .. py:method:: delete_group(group_name: magpie.typedefs.Str) -> magpie.typedefs.JSON .. py:method:: get_user_groups(user_name: magpie.typedefs.Str, user_group_status: magpie.models.UserGroupStatus = UserGroupStatus.ACTIVE) -> List[magpie.typedefs.Str] .. py:method:: get_user_names() Obtains all user names. .. py:method:: get_user_statuses(status: Union[magpie.typedefs.Str, int] = 0) -> List[magpie.typedefs.Str] Obtains all user names that have the corresponding status value. .. py:method:: get_user_emails() .. py:method:: get_user_details(status: Optional[Union[str, int]] = None, cookies: Optional[magpie.typedefs.CookiesType] = None) -> List[magpie.typedefs.JSON] Obtains all user details, optionally filtered to by corresponding status value. Employ this method to avoid multiple requests fetching individual information. .. seealso:: - :meth:`get_user_emails` - :meth:`get_user_names` - :meth:`get_user_statuses` .. py:method:: get_resource_types() :return: dictionary of all resources as {id: 'resource_type'} :rtype: dict .. py:method:: flatten_tree_resource(resource_node, resource_dict) :staticmethod: :param resource_node: any-level dictionary composing the resources tree :param resource_dict: reference of flattened dictionary across levels :return: flattened dictionary `resource_dict` of all {id: 'resource_type'} :rtype: dict .. py:method:: get_services(cur_svc_type) .. py:method:: get_service_data(service_name) .. py:method:: get_service_types() .. py:method:: update_service_name(old_service_name, new_service_name, service_push) .. py:method:: update_service_url(service_name, new_service_url, service_push) .. py:method:: create_user(data) Processes the user creation form with fields input data. All the fields are pre- and post-validated according to expected behaviour by the API. Pre-validations attempt *soft* checks to detect as many potential errors such that they can all be simultaneously displayed on the form, to avoid back-and-forth erroneous submissions by the user. Post-validations are the *hard* checks imposed by the API, which include some of the pre-checks. Whenever some failure occurs, returned data will contain ``is_error`` with ``True`` or ``False`` accordingly. Following successful request without error, the :term:`User` will be created. It is up to the calling function to redirect the response and further process the returned data as needed. :param data: initial templated data overrides according to who is initiation the user creation. :return: updated template data with any relevant error messages and statuses if applicable. :raises HTTPException: any unhandled or unknown HTTP error received from the API. .. seealso: :meth:`create_user_default_template_data` .. py:class:: BaseViews(request) Bases: :py:obj:`object` Base methods for Magpie UI pages. .. py:attribute:: MAGPIE_FIXED_GROUP_MEMBERSHIPS :value: [] Special :term:`Group` memberships that cannot be edited. .. py:attribute:: MAGPIE_FIXED_GROUP_EDITS :value: [] Special :term:`Group` details that cannot be edited. .. py:attribute:: MAGPIE_FIXED_USERS :value: [] Special :term:`User` details that cannot be edited. .. py:attribute:: MAGPIE_FIXED_USERS_REFS :value: [] Special :term:`User` that cannot have any relationship edited. This includes both :term:`Group` memberships and :term:`Permission` references. .. py:attribute:: MAGPIE_USER_PWD_LOCKED :value: [] Special :term:`User` that *could* self-edit themselves, but is disabled since conflicting with other policies. .. py:attribute:: MAGPIE_USER_PWD_DISABLED :value: [] Special :term:`User` where password cannot be edited (managed by `Magpie` configuration settings). .. py:attribute:: MAGPIE_ANONYMOUS_GROUP :value: None Reference to :py:data:`magpie.constants.MAGPIE_ANONYMOUS_GROUP` for convenience in UI pages. .. py:method:: add_template_data(data: Optional[Dict[magpie.typedefs.Str, Any]] = None) -> Dict[magpie.typedefs.Str, Any] Adds required template data for the 'heading' mako template applied to every UI page. .. py:method:: render(template: magpie.typedefs.Str, data: Optional[Dict[magpie.typedefs.Str, Any]] = None) -> pyramid.response.Response Render the response with an explicit Mako template reference. Views that are decorated by :func:`pyramid.view.view_config` or registered by :meth:`pyramid.config.Configurator.add_view` with a ``renderer`` parameter do not require to call this function as it is auto-resolved with the submitted :paramref:`data`. .. py:function:: check_response(response: magpie.typedefs.AnyResponseType) -> magpie.typedefs.AnyResponseType :returns: response if the HTTP status code is successful. :raises HTTPError: (of appropriate type) if the response corresponds to an HTTP error code .. py:function:: handle_errors(func: Callable) -> Callable Decorator that encapsulates the operation in a try/except block, and redirects the response to the UI error page with API error contents. In worst case scenario where the operation cannot figure out what to do with the exception response, raise the most basic :class:`HTTPInternalServerError` that can be formulated from available details. .. seealso:: :func:`redirect_error` .. py:function:: request_api(request: pyramid.request.Request, path: magpie.typedefs.Str, method: magpie.typedefs.Str = 'GET', data: Optional[Union[magpie.typedefs.JSON, magpie.typedefs.Str]] = None, headers: Optional[magpie.typedefs.HeadersType] = None, cookies: Optional[magpie.typedefs.CookiesType] = None) -> magpie.typedefs.AnyResponseType Use a pyramid sub-request to request Magpie API routes via the UI. This avoids max retries and closed connections when using 1 worker (eg: during tests). Some information is retrieved from :paramref:`request` to pass down to the sub-request (eg: cookies). If they are passed as argument, corresponding values will override the ones found in :paramref:`request`. All sub-requests to the API are assumed to be :py:data:`magpie.common.CONTENT_TYPE_JSON` unless explicitly overridden with :paramref:`headers`. Headers are also looked for additional ``Set-Cookie`` header in case they need to be passed down to :paramref:`cookies`. :param request: incoming Magpie UI request that requires sub-request to Magpie API, to retrieve required details. :param path: local Magpie API path (relative to root without URL). :param method: HTTP method to send the API sub-request. :param data: JSON dictionary or literal string content of the request body. :param headers: override headers to employ for the API sub-request. Defaults to JSON Accept & Content-Type headers. :param cookies: Override cookies to employ for the API sub-request. Defaults to current logged user. For empty cookies (no user), explicitly provide an empty dictionary. .. py:data:: CONTENT_TYPE_JSON :value: 'application/json' .. py:function:: get_json(request_or_response: Union[magpie.typedefs.AnyRequestType, magpie.typedefs.AnyResponseType]) -> magpie.typedefs.JSON Retrieves the 'JSON' body of a response using the property/callable according to the response's implementation. .. py:function:: get_logger(name: magpie.typedefs.Str, level: Optional[int] = None, force_stdout: bool = None, message_format: Optional[magpie.typedefs.Str] = None, datetime_format: Optional[magpie.typedefs.Str] = None) -> logging.Logger Immediately sets the logger level to avoid duplicate log outputs from the `root logger` and `this logger` when `level` is ``logging.NOTSET``. .. py:function:: is_json_body(body: Any, return_body: bool = False) -> bool .. py:data:: LOGGER .. py:class:: ManagementViews(request) Bases: :py:obj:`magpie.ui.utils.AdminRequests`, :py:obj:`magpie.ui.utils.BaseViews` Regroups multiple administration-level operations to be dispatched to the API requests. .. py:method:: goto_service(resource_id) .. py:method:: view_users() .. py:method:: add_user() User creation by a logged administrator. .. note:: The template employed for this form is reused for user self-registration as the fields and validation of inputs are essentially the same. Their actual processing is different though, as the administrator user is already logged in this case, and nobody is logged in the other. .. seealso:: :meth:`magpie.ui.login.views.LoginViews.register_user` .. py:method:: edit_user() Edit the fields of any referenced user profile by an administrator. .. seealso:: - :meth:`magpie.ui.user.views.UserViews.edit_current_user` for corresponding operation by user self-update .. py:method:: view_pending_user() Displays a pending user registration profile details. .. note:: View configuration is added dynamically because this page it should be available only when the corresponding feature is activated with configuration settings. .. py:method:: view_groups() .. py:method:: add_group() .. py:method:: resource_tree_parser(raw_resources_tree, permission) .. py:method:: perm_tree_parser(raw_perm_tree) .. py:method:: edit_group_users(group_name) .. py:method:: edit_user_or_group_resource_permissions(user_or_group_name, is_user=False) .. py:method:: get_user_or_group_resources_permissions_dict(user_or_group_name, services, service_type, is_user=False, is_inherit_groups_permissions=False) Get the user or group applied permissions as well as applicable permissions for corresponding services. Result is a :class:`tuple` of: - combined :term:`Allowed Permissions ` (*names only*) for services and their children :term:`Resources `. - dictionary of key-service-name, each with recursive map value of children resource details including the :term:`Applied Permissions ` or :term:`Inherited Resources` for the corresponding :term:`User` or :term:`Group` accordingly to specified arguments. .. py:method:: edit_group() .. py:method:: make_sync_error_message(service_names) :staticmethod: .. py:method:: sync_services(services: Dict[magpie.typedefs.Str, magpie.typedefs.JSON]) -> Tuple[List[magpie.typedefs.Str], Optional[magpie.typedefs.Str]] Syncs specified services. :returns: names of services that produced a sync error and corresponding sync message (if any). .. py:method:: get_remote_resources_info(res_perms, services, session) .. py:method:: merge_remote_resources(res_perms, services, session) :staticmethod: .. py:method:: get_last_sync_datetimes(service_ids: List[int], session: sqlalchemy.orm.session.Session) -> List[Optional[datetime.datetime]] :staticmethod: .. py:method:: delete_resource(res_id) .. py:method:: get_ids_to_clean(resources) .. py:method:: add_remote_resource(service_type, services_names, user_or_group, remote_id, is_user=False) .. py:method:: get_service_resources(service_name) .. py:method:: view_services() .. py:method:: add_service() .. py:method:: edit_service() .. py:method:: add_resource()