magpie.ui.management.views

Attributes

OUT_OF_SYNC

SYNC_SERVICES_TYPES

REMOTE_RESOURCE_TREE_SERVICE

RESOURCE_TYPE_DICT

SERVICE_TYPE_DICT

CONTENT_TYPE_JSON

LOGGER

Classes

UserGroupStatus

Supported statuses of user-group relationships.

UserStatuses

Values applicable to User statues.

Permission

Applicable Permission values (names) under certain Service and Resource.

PermissionSet

Explicit definition of a Permission with applicable Access and Scope to resolve it.

AdminRequests

Regroups multiple administration-level operations to be dispatched to the API requests.

BaseViews

Base methods for Magpie UI pages.

ManagementViews

Regroups multiple administration-level operations to be dispatched to the API requests.

Functions

fetch_single_service(→ None)

Get remote resources for a single service.

get_last_sync(→ Optional[datetime.datetime])

Obtain the date-time of the last known sync event for a service.

merge_local_and_remote_resources(...)

Main function to sync resources with remote server.

get_constant(→ magpie.typedefs.SettingValue)

Search in order for matched value of constant_name:

check_response(→ magpie.typedefs.AnyResponseType)

returns:

response if the HTTP status code is successful.

handle_errors(→ Callable)

Decorator that encapsulates the operation in a try/except block, and redirects the response to the UI error page

request_api(→ magpie.typedefs.AnyResponseType)

Use a pyramid sub-request to request Magpie API routes via the UI. This avoids max retries and closed connections

get_json(→ magpie.typedefs.JSON)

Retrieves the 'JSON' body of a response using the property/callable according to the response's implementation.

get_logger(→ logging.Logger)

Immediately sets the logger level to avoid duplicate log outputs from the root logger and this logger when

is_json_body(→ bool)

Module Contents

magpie.ui.management.views.OUT_OF_SYNC[source]
magpie.ui.management.views.fetch_single_service(service: magpie.models.Service | int, session: sqlalchemy.orm.session.Session) None[source]

Get remote resources for a single service.

Parameters:
  • service – Specific service for which to synchronize remote resources.

  • session – Database connexion to apply synchronization changes.

magpie.ui.management.views.get_last_sync(service_id: int, session: sqlalchemy.orm.session.Session) datetime.datetime | None[source]

Obtain the date-time of the last known sync event for a service.

magpie.ui.management.views.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[source]

Main function to sync resources with remote server.

magpie.ui.management.views.SYNC_SERVICES_TYPES: Dict[magpie.typedefs.Str, Type[SyncServiceInterface]][source]
magpie.ui.management.views.get_constant(constant_name: magpie.typedefs.Str, settings_container: magpie.typedefs.AnySettingsContainer | None = None, settings_name: magpie.typedefs.Str | None = None, default_value: magpie.typedefs.SettingValue | None = None, raise_not_set: bool = True, raise_missing: bool = True, print_missing: bool = False, empty_missing: bool = False) magpie.typedefs.SettingValue[source]
Search in order for matched value of constant_name:
  1. search in MAGPIE_CONSTANTS

  2. search in settings if specified

  3. search alternative setting names (see below)

  4. search in magpie.constants definitions

  5. search in environment variables

Parameter 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 settings_name is provided as alternative name, it is used as is to search for results if constant_name was not found. Otherwise, magpie.[variable_name] is used for additional search when the format MAGPIE_[VARIABLE_NAME] was used for constant_name (i.e.: MAGPIE_ADMIN_USER will also search for magpie.admin_user and so on for corresponding constants).

Parameters:
  • constant_name – key to search for a value

  • settings_container – WSGI application settings container (if not provided, uses found one in current thread)

  • settings_name – alternative name for settings if specified

  • default_value – default value to be returned if not found anywhere, and exception raises are disabled.

  • raise_not_set – raise an exception if the found key is None, search until last case if others are None

  • raise_missing – raise exception if key is not found anywhere

  • print_missing – print message if key is not found anywhere, return None

  • 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)

  • LookupError – if no appropriate value could be found from all search locations (according to options)

magpie.ui.management.views.REMOTE_RESOURCE_TREE_SERVICE[source]
magpie.ui.management.views.RESOURCE_TYPE_DICT: Dict[magpie.typedefs.Str, Type[Resource]][source]
class magpie.ui.management.views.UserGroupStatus[source]

Bases: magpie.utils.FlexibleNameEnum

Supported statuses of user-group relationships.

ALL = 'all'
ACTIVE = 'active'
PENDING = 'pending'
classmethod allowed() List[magpie.typedefs.Str][source]

Returns all supported representation values that can be mapped to a valid status.

class magpie.ui.management.views.UserStatuses[source]

Bases: enum.IntFlag, magpie.utils.FlexibleNameEnum

Values applicable to User statues.

Provides allowed values for the status search query of User and UserPending entries. Also, defines the possible values of User.status field, omitting UserStatuses.Pending reserved for objects defined by UserPending.

Initialize self. See help(type(self)) for accurate signature.

OK = 1
WebhookError = 2
Pending = 4
classmethod _get_one(status: AnyUserStatus) UserStatuses | None[source]
classmethod get(status: None | int | magpie.typedefs.Str | UserStatuses | Iterable[None, int, magpie.typedefs.Str, UserStatuses], default: UserStatuses | None = None) UserStatuses | None[source]

Obtains the combined flag UserStatuses

classmethod allowed() List[None | int | magpie.typedefs.Str][source]

Returns all supported representation values that can be mapped to a valid status for UserSearchService.

classmethod all() UserStatuses[source]

Representation of all flags combined.

__or__(other: UserStatuses | int) UserStatuses[source]

Return self|value.

__and__(other: UserStatuses | int) UserStatuses[source]

Return self&value.

__xor__(other: UserStatuses | int) UserStatuses[source]

Return self^value.

__iter__() Iterable[UserStatuses][source]
__len__()[source]
class magpie.ui.management.views.Permission[source]

Bases: magpie.utils.ExtendedEnum

Applicable Permission values (names) under certain Service and Resource.

READ = 'read'
WRITE = 'write'
ACCESS = 'access'
BROWSE = 'browse'
GET_CAPABILITIES = 'getcapabilities'
GET_MAP = 'getmap'
GET_FEATURE_INFO = 'getfeatureinfo'
GET_LEGEND_GRAPHIC = 'getlegendgraphic'
GET_METADATA = 'getmetadata'
GET_PROPERTY_VALUE = 'getpropertyvalue'
GET_FEATURE = 'getfeature'
GET_FEATURE_WITH_LOCK = 'getfeaturewithlock'
GET_GML_OBJECT = 'getgmlobject'
DESCRIBE_FEATURE_TYPE = 'describefeaturetype'
DESCRIBE_LAYER = 'describelayer'
DESCRIBE_PROCESS = 'describeprocess'
EXECUTE = 'execute'
LOCK_FEATURE = 'lockfeature'
TRANSACTION = 'transaction'
CREATE_STORED_QUERY = 'createstoredquery'
DROP_STORED_QUERY = 'dropstoredquery'
LIST_STORED_QUERIES = 'liststoredqueries'
DESCRIBE_STORED_QUERIES = 'describestoredqueries'
class magpie.ui.management.views.PermissionSet(permission: magpie.typedefs.AnyPermissionType, access: Access | magpie.typedefs.Str | None = None, scope: Scope | magpie.typedefs.Str | None = None, typ: PermissionType | None = None, reason: magpie.typedefs.Str | None = None)[source]

Bases: object

Explicit definition of a Permission with applicable Access and Scope to resolve it.

The Permission is the name of the applicable permission on the magpie.models.Resource. The Scope defines how the Permission should impact the resolution of the perceived Effective Permissions over a magpie.models.Resource tree hierarchy. The Access defines how the Permission access should be interpreted (granted or denied).

Optionally, a 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 Effective Permissions resolution to be more verbose about returned results.

On missing Access or Scope specifications, they default to Access.ALLOW and Scope.RECURSIVE to handle backward compatible naming convention of plain permission_name.

Initializes the permission definition, possibly using required conversion from other implementations.

Parameters:
  • permission – Name of the permission, or any other implementation from which the name can be inferred.

  • access – Effective behaviour of the permissions. Generally, grant or deny the specified permission.

  • scope – Scope for which the permission affects hierarchical resources. Important for effective resolution.

  • typ – Type of permission being represented. Informative only, does not impact behavior if omitted.

  • 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.

__slots__ = ['_name', '_access', '_scope', '_tuple', '_type', '_reason']
__eq__(other: Any) bool[source]

Return self==value.

__ne__(other: Any) bool[source]

Return self!=value.

__lt__(other: Any) bool[source]

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 Access.DENY is more important than Access.ALLOW (to protect the Resource), and Scope.MATCH is closer to the actual Resource than 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 Scope.RECURSIVE is more verbose as it tell other resources under it are also receive the specified 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 Permission priority according to how modifiers are resolved. To obtain the prioritized sorting as strings, a list of PermissionSet (with the strings as input) should be used to convert and correctly interpreted the raw strings, and then be converted back after sorting.

# 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))
__hash__() int[source]

Return hash(self).

__str__() magpie.typedefs.Str[source]

Obtains the compound literal representation of the PermissionSet.

Employed for database storage supporting ziggurat format.

__repr__() magpie.typedefs.Str[source]

Obtains the visual representation of the PermissionSet.

like(other: Any) bool[source]

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.

json() magpie.typedefs.PermissionDict[source]

Obtains the JSON representation of this PermissionSet.

webhook_params() magpie.typedefs.JSON[source]

Obtain JSON representation employed for Webhook reference.

ace(user_or_group: magpie.models.User | magpie.models.Group | None) magpie.typedefs.AccessControlEntryType[source]

Converts the PermissionSet into an ACE that pyramid can understand.

property reason: magpie.typedefs.Str | None

Indicative reason of the returned value defined by type() or inferred by the PermissionTuple.

See also

combine()

Returns:

Single string that describes the reason (source) of the permission, or multiple strings if updated by combination of multiple permissions.

classmethod resolve(permission1: magpie.typedefs.ResolvablePermissionType, permission2: magpie.typedefs.ResolvablePermissionType, context: PermissionType = PermissionType.INHERITED, multiple_choice: magpie.typedefs.Str | None = None) magpie.typedefs.ResolvablePermissionType[source]

Resolves provided permissions into a single one considering various modifiers and groups for a resource.

Permissions MUST have the same Permission name. The associated 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 Effective Permission since it does not handle multi-level Resource resolution. Resolution is accomplished in this case only for a given level in the tree hierarchy.

The comparison considers both the Access and Scope of every Inherited Permission of the User, as well as its Group memberships sorted by their priority.

See also

Parameters:
  • permission1 – Permission to compare.

  • permission2 – Permission to compare.

  • context – Control the resolution context (local/effective) of the permissions (safeguard against invalid definitions).

  • multiple_choice – Alternate explanation to default PERMISSION_REASON_MULTIPLE applied if multiple Permission refer to distinct Group of equal priority and equivalent access definitions, meaning they are interchangeable without impacting resolution to access the same target Resource.

Returns:

Permission with highest priority to resolve access a resource without considering scope.

property group_priority: magpie.typedefs.GroupPriority | None

Priority accessor in case of group inherited permission resolved by PermissionTuple.

property perm_tuple: ziggurat_foundations.permissions.PermissionTuple | None

Get the original PermissionTuple if available (PermissionSet must have been created by one).

property implicit_permission: magpie.typedefs.Str | None

Obtain the implicit string representation of the PermissionSet as plain 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 PermissionSet (notably the 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.

See also

property explicit_permission: magpie.typedefs.Str

Obtain the explicit string representation of the PermissionSet.

This format is always guaranteed to be completely defined contrary to implicit_permission().

See also

property name: Permission
permission
property access: Access
property scope: Scope
property type: PermissionType | None
classmethod _convert(permission: magpie.typedefs.AnyPermissionType) PermissionSet | None[source]

Converts any permission representation to the PermissionSet with applicable enum members.

Supports older Permission representation such that implicit conversion of permission name without access and scope values are padded with defaults. Also, pre-defined partial or full definition from literal string representation are parsed to generate the PermissionSet instance.

Parameters:

permission – implicit or explicit permission name string, or any other known permission implementation

Raises:

ValueError – when the permission name cannot be identified or parsed

magpie.ui.management.views.SERVICE_TYPE_DICT[source]
class magpie.ui.management.views.AdminRequests(request)[source]

Bases: BaseViews

Regroups multiple administration-level operations to be dispatched to the API requests.

create_user_default_template_data(data)[source]

Generates all the default values for the various fields employed for display purposes of the user creation form.

Parameters:

data – any template data that should override the defaults.

Returns:

updated template data with defaults and overridden values.

get_admin_session() magpie.typedefs.CookiesType[source]

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.

get_all_groups(first_default_group=None)[source]
get_group_info(group_name: magpie.typedefs.Str) magpie.typedefs.JSON[source]
get_group_users(group_name: magpie.typedefs.Str, user_group_status: magpie.models.UserGroupStatus = UserGroupStatus.ACTIVE) List[magpie.typedefs.Str][source]
update_group_info(group_name: magpie.typedefs.Str, group_info: magpie.typedefs.JSON) magpie.typedefs.JSON[source]
delete_group(group_name: magpie.typedefs.Str) magpie.typedefs.JSON[source]
get_user_groups(user_name: magpie.typedefs.Str, user_group_status: magpie.models.UserGroupStatus = UserGroupStatus.ACTIVE) List[magpie.typedefs.Str][source]
get_user_names()[source]

Obtains all user names.

get_user_statuses(status: magpie.typedefs.Str | int = 0) List[magpie.typedefs.Str][source]

Obtains all user names that have the corresponding status value.

get_user_emails()[source]
get_user_details(status: str | int | None = None, cookies: magpie.typedefs.CookiesType | None = None) List[magpie.typedefs.JSON][source]

Obtains all user details, optionally filtered to by corresponding status value.

Employ this method to avoid multiple requests fetching individual information.

get_resource_types()[source]
Returns:

dictionary of all resources as {id: ‘resource_type’}

Return type:

dict

static flatten_tree_resource(resource_node, resource_dict)[source]
Parameters:
  • resource_node – any-level dictionary composing the resources tree

  • resource_dict – reference of flattened dictionary across levels

Returns:

flattened dictionary resource_dict of all {id: ‘resource_type’}

Return type:

dict

get_services(cur_svc_type)[source]
get_service_data(service_name)[source]
get_service_types()[source]
update_service_name(old_service_name, new_service_name, service_push)[source]
update_service_url(service_name, new_service_url, service_push)[source]
create_user(data)[source]

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 User will be created. It is up to the calling function to redirect the response and further process the returned data as needed.

Parameters:

data – initial templated data overrides according to who is initiation the user creation.

Returns:

updated template data with any relevant error messages and statuses if applicable.

Raises:

HTTPException – any unhandled or unknown HTTP error received from the API.

class magpie.ui.management.views.BaseViews(request)[source]

Bases: object

Base methods for Magpie UI pages.

MAGPIE_FIXED_GROUP_MEMBERSHIPS = []

Special Group memberships that cannot be edited.

MAGPIE_FIXED_GROUP_EDITS = []

Special Group details that cannot be edited.

MAGPIE_FIXED_USERS = []

Special User details that cannot be edited.

MAGPIE_FIXED_USERS_REFS = []

Special User that cannot have any relationship edited.

This includes both Group memberships and Permission references.

MAGPIE_USER_PWD_LOCKED = []

Special User that could self-edit themselves, but is disabled since conflicting with other policies.

MAGPIE_USER_PWD_DISABLED = []

Special User where password cannot be edited (managed by Magpie configuration settings).

MAGPIE_ANONYMOUS_GROUP = None

Reference to magpie.constants.MAGPIE_ANONYMOUS_GROUP for convenience in UI pages.

add_template_data(data: Dict[magpie.typedefs.Str, Any] | None = None) Dict[magpie.typedefs.Str, Any][source]

Adds required template data for the ‘heading’ mako template applied to every UI page.

render(template: magpie.typedefs.Str, data: Dict[magpie.typedefs.Str, Any] | None = None) pyramid.response.Response[source]

Render the response with an explicit Mako template reference.

Views that are decorated by pyramid.view.view_config() or registered by pyramid.config.Configurator.add_view() with a renderer parameter do not require to call this function as it is auto-resolved with the submitted data.

magpie.ui.management.views.check_response(response: magpie.typedefs.AnyResponseType) magpie.typedefs.AnyResponseType[source]
Returns:

response if the HTTP status code is successful.

Raises:

HTTPError – (of appropriate type) if the response corresponds to an HTTP error code

magpie.ui.management.views.handle_errors(func: Callable) Callable[source]

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 HTTPInternalServerError that can be formulated from available details.

See also

redirect_error()

magpie.ui.management.views.request_api(request: pyramid.request.Request, path: magpie.typedefs.Str, method: magpie.typedefs.Str = 'GET', data: magpie.typedefs.JSON | magpie.typedefs.Str | None = None, headers: magpie.typedefs.HeadersType | None = None, cookies: magpie.typedefs.CookiesType | None = None) magpie.typedefs.AnyResponseType[source]

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 request to pass down to the sub-request (eg: cookies). If they are passed as argument, corresponding values will override the ones found in request.

All sub-requests to the API are assumed to be magpie.common.CONTENT_TYPE_JSON unless explicitly overridden with headers. Headers are also looked for additional Set-Cookie header in case they need to be passed down to cookies.

Parameters:
  • request – incoming Magpie UI request that requires sub-request to Magpie API, to retrieve required details.

  • path – local Magpie API path (relative to root without URL).

  • method – HTTP method to send the API sub-request.

  • data – JSON dictionary or literal string content of the request body.

  • headers – override headers to employ for the API sub-request. Defaults to JSON Accept & Content-Type headers.

  • 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.

magpie.ui.management.views.CONTENT_TYPE_JSON = 'application/json'[source]
magpie.ui.management.views.get_json(request_or_response: magpie.typedefs.AnyRequestType | magpie.typedefs.AnyResponseType) magpie.typedefs.JSON[source]

Retrieves the ‘JSON’ body of a response using the property/callable according to the response’s implementation.

magpie.ui.management.views.get_logger(name: magpie.typedefs.Str, level: int | None = None, force_stdout: bool = None, message_format: magpie.typedefs.Str | None = None, datetime_format: magpie.typedefs.Str | None = None) logging.Logger[source]

Immediately sets the logger level to avoid duplicate log outputs from the root logger and this logger when level is logging.NOTSET.

magpie.ui.management.views.is_json_body(body: Any, return_body: bool = False) bool[source]
magpie.ui.management.views.LOGGER[source]
class magpie.ui.management.views.ManagementViews(request)[source]

Bases: magpie.ui.utils.AdminRequests, magpie.ui.utils.BaseViews

Regroups multiple administration-level operations to be dispatched to the API requests.

goto_service(resource_id)[source]
view_users()[source]
add_user()[source]

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.

edit_user()[source]

Edit the fields of any referenced user profile by an administrator.

See also

view_pending_user()[source]

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.

view_groups()[source]
add_group()[source]
resource_tree_parser(raw_resources_tree, permission)[source]
perm_tree_parser(raw_perm_tree)[source]
edit_group_users(group_name)[source]
edit_user_or_group_resource_permissions(user_or_group_name, is_user=False)[source]
get_user_or_group_resources_permissions_dict(user_or_group_name, services, service_type, is_user=False, is_inherit_groups_permissions=False)[source]

Get the user or group applied permissions as well as applicable permissions for corresponding services.

Result is a tuple of:
  • combined Allowed Permissions (names only) for services and their children Resources.

  • dictionary of key-service-name, each with recursive map value of children resource details including the Applied Permissions or Inherited Resources for the corresponding User or Group accordingly to specified arguments.

edit_group()[source]
static make_sync_error_message(service_names)[source]
sync_services(services: Dict[magpie.typedefs.Str, magpie.typedefs.JSON]) Tuple[List[magpie.typedefs.Str], magpie.typedefs.Str | None][source]

Syncs specified services.

Returns:

names of services that produced a sync error and corresponding sync message (if any).

get_remote_resources_info(res_perms, services, session)[source]
static merge_remote_resources(res_perms, services, session)[source]
static get_last_sync_datetimes(service_ids: List[int], session: sqlalchemy.orm.session.Session) List[datetime.datetime | None][source]
delete_resource(res_id)[source]
get_ids_to_clean(resources)[source]
add_remote_resource(service_type, services_names, user_or_group, remote_id, is_user=False)[source]
get_service_resources(service_name)[source]
view_services()[source]
add_service()[source]
edit_service()[source]
add_resource()[source]