magpie.api.management.user.user_utils

Attributes

SERVICE_TYPE_DICT

LOGGER

USERNAME_REGEX

Classes

WebhookAction

Supported Webhook actions.

TemporaryToken

Model that defines a token for temporary URL completion of a given pending operation.

TokenOperation

Supported operations by the temporary tokens.

PermissionSet

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

PermissionType

Applicable types of Permission according to context.

BaseViews

Base methods for Magpie UI pages.

Functions

format_service(→ magpie.typedefs.JSON)

Formats a Service information into JSON.

get_email_template(→ mako.template.Template)

Retrieves the template file with email content matching the custom application setting or the corresponding default.

send_email(→ bool)

Send email notification using provided template and parameters.

generate_callback_url(→ magpie.typedefs.Str)

Generates a callback URL using Magpie temporary tokens for use by the webhook implementation.

get_permission_update_params(...)

Generates the Webhook parameters based on provided references.

process_webhook_requests(→ None)

Checks the config for any webhooks that correspond to the input action, and prepares corresponding requests.

get_constant(→ magpie.typedefs.SettingValue)

Search in order for matched value of constant_name:

format_permissions(→ Dict[magpie.typedefs.Str, ...)

Obtains the formatted permission representations after validation that each of their name is a known member of

service_factory(→ ServiceInterface)

Retrieve the specific service class from the provided database service entry.

get_logger(→ logging.Logger)

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

get_settings_from_config_ini(...)

create_user(→ pyramid.httpexceptions.HTTPException)

Creates a User if it is permitted and not conflicting with existing ones.

update_user(→ None)

Applies updates of user details with specified values after validation.

create_user_resource_permission_response(...)

Creates a permission on a user/resource combination if it is permitted, and optionally not conflicting.

assign_user_group(→ None)

Creates a user-group relationship (user membership to a group).

send_group_terms_email(...)

Sends an email for terms and conditions confirmation.

create_pending_or_assign_user_group(...)

Associates the pending user or existing user to the group.

handle_user_group_terms_confirmation(...)

Handles the confirmation of a user to accept the terms and conditions of a group.

delete_user_group(→ None)

Deletes a user-group relationship (user membership to a group).

delete_user_resource_permission_response(...)

Get validated response on deleted user resource permission.

get_similar_user_resource_permission(...)

Obtains the user service/resource permission that corresponds to the provided one.

get_user_resource_permissions(...)

Retrieves user resource permissions applied directly, with inherited group permissions, or resolve between them.

get_user_resource_permissions_response(...)

Retrieves user resource permissions with or without inherited group permissions.

get_user_services(→ magpie.typedefs.UserServicesType)

Returns services by type with corresponding services by name containing sub-dict information.

get_user_service_permissions(...)

Retrieve the permissions the user has directly on a service or inherited permissions by its group memberships.

filter_user_permission(...)

Retrieves only user Direct Permissions amongst a list of user/group resource/service permissions.

resolve_user_group_permissions(...)

Reduces overlapping user Inherited Permission for corresponding resources/services amongst the given list.

regroup_permissions_by_resource(...)

Regroups multiple uncategorized permissions into a dictionary of corresponding resource IDs.

get_user_resources_permissions_dict(...)

Creates a dictionary of resources ID with corresponding permissions of the user.

get_user_service_resources_permissions_dict(...)

Retrieves all permissions the user has for every Resource nested under the Service.

check_user_info(→ None)

Validates provided user information to ensure they are adequate for user creation.

check_user_editable(→ None)

Verify if the specified user is allowed to receive modifications (to it directly or any resource referring to it).

get_user_groups_checked(→ List[magpie.typedefs.Str])

Obtains the validated list of group names from a pre-validated user.

Module Contents

magpie.api.management.user.user_utils.format_service(service: magpie.models.Service, permissions: List[magpie.permissions.PermissionSet] | None = None, permission_type: magpie.permissions.PermissionType | None = None, show_private_url: bool = False, show_public_url: bool = True, show_resources_allowed: bool = False, show_configuration: bool = False, basic_info: bool = False, dotted: bool = False) magpie.typedefs.JSON[source]

Formats a Service information into JSON.

Note

Automatically finds permissions of the service if not specified. To preserve empty permissions such as during listing of user/group resource permissions, an empty list should be specified.

Parameters:
  • serviceService to be formatted.

  • permissions – Permissions to list along with the resource. By default, these are the applicable permissions for that corresponding resource type.

  • permission_type – Override indication of provenance to apply to permissions. Only applicable when they are provided.

  • show_private_url – Display the protected and private URL employed at service registration.

  • show_public_url – Display the generated public URL from configured Twitcher Settings.

  • show_resources_allowed – Display children resource details.

  • show_configuration – Display the applicable configuration of the Service if it supports it.

  • basic_info – If True, return only sufficient details to identify the service, without any additional details about permissions, children resources or configuration information is returned.

  • dotted – Employ a dot (.) instead of underscore (_) to separate Service from its basic information.

magpie.api.management.user.user_utils.get_email_template(template_constant: magpie.typedefs.Str, container: magpie.typedefs.AnySettingsContainer | None = None) mako.template.Template[source]

Retrieves the template file with email content matching the custom application setting or the corresponding default.

Allowed values of template_constant are:

Raises:

IOError – if an explicit override value of the requested template cannot be located.

Returns:

template formatter from the requested template file.

magpie.api.management.user.user_utils.send_email(recipient: magpie.typedefs.Str, container: magpie.typedefs.AnySettingsContainer, template: mako.template.Template, parameters: TemplateParameters | None = None) bool[source]

Send email notification using provided template and parameters.

The preparation steps of the email (retrieve SMTP configuration, setup the SMTP connection, define email content parameters and attempt template generation) will directly raise if invalid as they correspond to incorrect application code or configuration settings.

Following step to send the email with the established SMTP connection is caught and logged if raising an exception. This is to allow the calling operation to ignore failing email notification and act accordingly using the resulting email status.

Parameters:
  • recipient – Email address of the intended recipient to which the email must be sent.

  • template – Mako template used for the email contents.

  • container – Any container to retrieve application settings.

  • parameters – Parameters to provide for templating email contents. They are applied on top of various defaults values provided to all emails.

Raises:

any SMTP server configuration, template generator or parameter parsing error for email setup.

Returns:

success status of the notification email (sent without error, no guarantee of reception).

class magpie.api.management.user.user_utils.WebhookAction[source]

Bases: magpie.utils.ExtendedEnum

Supported Webhook actions.

CREATE_USER = 'create_user'

Triggered when a new User gets successfully created.

See also

User Creation

DELETE_USER = 'delete_user'

Triggered when an existing User gets successfully deleted.

See also

User Deletion

UPDATE_USER_STATUS = 'update_user_status'

Triggered when an existing User status gets successfully updated.

CREATE_USER_PERMISSION = 'create_user_permission'

Triggered when a Permission onto a Service or Resource gets created for a User.

DELETE_USER_PERMISSION = 'delete_user_permission'

Triggered when a Permission onto a Service or Resource gets deleted for a User.

CREATE_GROUP_PERMISSION = 'create_group_permission'

Triggered when a Permission onto a Service or Resource gets created for a Group.

DELETE_GROUP_PERMISSION = 'delete_group_permission'

Triggered when a Permission onto a Service or Resource gets deleted for a Group.

magpie.api.management.user.user_utils.generate_callback_url(operation: magpie.models.TokenOperation, db_session: sqlalchemy.orm.session.Session, user: magpie.models.AnyUser | None = None, group: magpie.models.Group | None = None) magpie.typedefs.Str[source]

Generates a callback URL using Magpie temporary tokens for use by the webhook implementation.

Parameters:
  • operation – targeted operation that employs the callback URL for reference.

  • db_session – database session to store the generated temporary token.

  • user – user reference associated to the operation as applicable.

  • group – group reference associated to the operation as applicable.

Returns:

generated callback URL.

magpie.api.management.user.user_utils.get_permission_update_params(target: magpie.models.User | magpie.models.Group, resource: magpie.typedefs.ServiceOrResourceType, permission: magpie.permissions.PermissionSet, db_session: sqlalchemy.orm.session.Session) magpie.typedefs.WebhookTemplateParameters[source]

Generates the Webhook parameters based on provided references.

magpie.api.management.user.user_utils.process_webhook_requests(action: WebhookAction, params: magpie.typedefs.WebhookTemplateParameters, update_user_status_on_error: bool = False, settings: magpie.typedefs.AnySettingsContainer | None = None) None[source]

Checks the config for any webhooks that correspond to the input action, and prepares corresponding requests.

Parameters:
  • action – tag identifying which webhooks to use in the config

  • params – Dictionary containing the required parameters and associated values for the request following the event action. Parameters will replace templates found in the payload definition of the webhook.

  • update_user_status_on_error – update the user status or not in case of a webhook error.

  • settings – application settings where webhooks configuration can be retrieved.

magpie.api.management.user.user_utils.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)

class magpie.api.management.user.user_utils.TemporaryToken(*_, **__)[source]

Bases: ziggurat_foundations.models.base.BaseModel, Base

Model that defines a token for temporary URL completion of a given pending operation.

__tablename__ = 'tmp_tokens'
token
operation
created
user_id
_user
user_pending_id
_pending_user
group_id
group
user() AnyUser[source]
url(settings: magpie.typedefs.AnySettingsContainer = None) magpie.typedefs.Str[source]
expired() bool[source]
static by_token(token: magpie.typedefs.Str | sqlalchemy.dialects.postgresql.UUID, db_session: sqlalchemy.orm.session.Session | None = None) TemporaryToken | None[source]
static by_user(user: AnyUser, db_session: sqlalchemy.orm.session.Session | None = None) sqlalchemy.orm.query.Query | None[source]
json() magpie.typedefs.JSON[source]
class magpie.api.management.user.user_utils.TokenOperation[source]

Bases: magpie.utils.ExtendedEnum

Supported operations by the temporary tokens.

GROUP_ACCEPT_TERMS = 'group-accept-terms'

Temporary token associated to an URL endpoint called by a user that accepts the terms and conditions (T&C) to join a particular group.

USER_PASSWORD_RESET = 'user-password-reset'

Temporary token associated to an URL endpoint to request a user password reset.

USER_REGISTRATION_CONFIRM_EMAIL = 'user-registration-confirm-email'

Temporary token associated to a pending user registration that requires email validation by visiting the link.

USER_REGISTRATION_ADMIN_APPROVE = 'user-registration-admin-approve'

Temporary token associated to a pending user registration that will be approved by an administrator when visited.

USER_REGISTRATION_ADMIN_DECLINE = 'user-registration-admin-decline'

Temporary token associated to a pending user registration that will be declined by an administrator when visited.

WEBHOOK_USER_STATUS_ERROR = 'webhook-user-status-error'

Temporary token employed to provide a callback URL that a registered webhook can call following the triggered event to indicate that the corresponding operation resulted into an invalid user status.

class magpie.api.management.user.user_utils.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

class magpie.api.management.user.user_utils.PermissionType[source]

Bases: magpie.utils.ExtendedEnum

Applicable types of Permission according to context.

ACCESS = 'access'
ALLOWED = 'allowed'
APPLIED = 'applied'
DIRECT = 'direct'
INHERITED = 'inherited'
EFFECTIVE = 'effective'
OWNED = 'owned'
magpie.api.management.user.user_utils.format_permissions(permissions: Collection[magpie.typedefs.AnyPermissionType] | None, permission_type: PermissionType | None = None, force_unique: bool = True) Dict[magpie.typedefs.Str, List[magpie.typedefs.Str] | magpie.typedefs.PermissionDict | magpie.typedefs.Str][source]

Obtains the formatted permission representations after validation that each of their name is a known member of Permission enum, and optionally with modifiers as defined by PermissionSet.

The returned lists are sorted alphabetically by permission name, and then in order of resolution priority (from highest to lowest) for each subset or corresponding name.

The permissions are cleaned from any duplicate entries, unless force_unique is specified to allow it. If no or empty permissions is provided, empty lists are returned.

Note

Field permission_names provides both the older implicit permission names and the newer explicit name representation. For this reason, there will be semantically “duplicate” permissions in that list, but there will not be any literal string duplicates. Implicit names are immediately followed by their explicit name, unless implicit names do not apply for the given permission (e.g.: when Access.DENY did not exist). Only detailed and explicit JSON representations are provided in the permissions list.

When permission_type is equal to PermissionType.ALLOWED, the collection of every applicable PermissionSet is automatically generated by expanding all combinations of Access and Scope with every provided Permission name in permissions. This allows more concise definition of allowed permissions under magpie.services.Services and their children Resource by only defining Permission names without manually listing all variations of PermissionSet.

For other permission_type values, which represent Applied Permission only explicitly provided permissions are returned, to effectively return the collection of active permissions.

Parameters:
  • permissions – multiple permissions of any implementation and type, to be rendered both as names and JSON.

  • permission_type – indication of the represented permissions to be formatted, for informative indication.

  • force_unique – whether to remove duplicate entries by association of name, access and scope or not.

Returns:

JSON with the permissions listed as implicit+explicit names, as permission set objects, and their type.

magpie.api.management.user.user_utils.SERVICE_TYPE_DICT[source]
magpie.api.management.user.user_utils.service_factory(service: magpie.models.Service, request: pyramid.request.Request) ServiceInterface[source]

Retrieve the specific service class from the provided database service entry.

class magpie.api.management.user.user_utils.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.api.management.user.user_utils.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.api.management.user.user_utils.get_settings_from_config_ini(config_ini_path: magpie.typedefs.Str, ini_main_section_name: magpie.typedefs.Str = 'app:magpie_app') magpie.typedefs.SettingsType[source]
magpie.api.management.user.user_utils.LOGGER[source]
magpie.api.management.user.user_utils.USERNAME_REGEX[source]
magpie.api.management.user.user_utils.create_user(user_name: magpie.typedefs.Str, password: magpie.typedefs.Str | None, email: magpie.typedefs.Str, group_name: magpie.typedefs.Str | None, db_session: sqlalchemy.orm.session.Session, **extra_fields) pyramid.httpexceptions.HTTPException[source]

Creates a User if it is permitted and not conflicting with existing ones.

Password must be set to None if using an external identity or skip its encrypted value generation.

Created User will immediately be assigned membership to the group matching group_name (can be MAGPIE_ANONYMOUS_GROUP for minimal access). If no group is provided, this anonymous group will be applied by default, creating a user effectively without any permissions other than ones set directly for him and inherited from Public Access.

Furthermore, the User always gets associated with MAGPIE_ANONYMOUS_GROUP (if not already explicitly or implicitly requested with group_name) to allow access to resources with public permission. This means that when group_name is provided with another name than MAGPIE_ANONYMOUS_GROUP, the User will have two memberships initially.

Argument group_name MUST be an existing group if provided.

Note

In order to properly handle subscribed Webhook that could request to change the user status to an error following a failing external operation, the created user is immediately committed. This way, following requests will have access to the instance from the database. Because of this requirement, any operation that desire an handle to the created User instance should retrieve it again from the database session.

Parameters:
  • user_name – Unique name of the user to validate and employ for creation.

  • password – Raw password of the user to validate and employ for creation. If Skipped if None. Otherwise, apply hash encryption on the value.

  • email – User email to be validated and employed for creation.

  • group_name – Group name to associate the user with at creation time.

  • db_session – database connection.

  • extra_fields – Additional fields that should be set for the user. Must be known properties of the instance.

Returns:

valid HTTP response on successful operation, or the User when requested.

magpie.api.management.user.user_utils.update_user(user: magpie.models.User, request: pyramid.request.Request, new_user_name: magpie.typedefs.Str | None = None, new_password: magpie.typedefs.Str | None = None, new_email: magpie.typedefs.Str | None = None, new_status: magpie.models.UserStatuses | None = None) None[source]

Applies updates of user details with specified values after validation.

Parameters:
  • user – targeted user to update .

  • request – request that produced this update operation.

  • new_user_name – new name to apply (if provided).

  • new_password – new password to apply (if provided).

  • new_email – new email to apply (if provided).

  • new_status – new status to apply (if provided).

Returns:

None if update was successful.

magpie.api.management.user.user_utils.create_user_resource_permission_response(user: magpie.models.User, resource: magpie.typedefs.ServiceOrResourceType, permission: magpie.permissions.PermissionSet, db_session: sqlalchemy.orm.session.Session, overwrite: bool = False) pyramid.httpexceptions.HTTPException[source]

Creates a permission on a user/resource combination if it is permitted, and optionally not conflicting.

Parameters:
  • user – user for which to create/update the permission.

  • resource – service or resource for which to create the permission.

  • permission – permission with modifiers to be applied.

  • db_session – database connection.

  • overwrite – If the corresponding (user, resource, permission[name]) exists, there is a conflict. Conflict is considered only by permission-name regardless of other modifiers. If permissions match exactly (including modifiers), conflict is raised regardless of overwrite value. If overwrite is False, the conflict will be raised and not be applied. If overwrite is True, the permission modifiers will be replaced by the new ones, or created if missing.

Returns:

valid HTTP response on successful operation.

magpie.api.management.user.user_utils.assign_user_group(user: magpie.models.User, group: magpie.models.Group, db_session: sqlalchemy.orm.session.Session) None[source]

Creates a user-group relationship (user membership to a group).

Returns:

nothing - user-group is created.

Raises:

HTTPError – corresponding error matching problem encountered.

magpie.api.management.user.user_utils.send_group_terms_email(user: magpie.models.User, group: magpie.models.Group, db_session: sqlalchemy.orm.session.Session) pyramid.httpexceptions.HTTPSuccessful[source]

Sends an email for terms and conditions confirmation.

Terms and conditions email are sent in the case of a request for the creation of a user-group relationship where the group requires a terms and conditions confirmation.

Returns:

valid HTTP response on successful operations.

Raises:

HTTPError – corresponding error matching problem encountered.

magpie.api.management.user.user_utils.create_pending_or_assign_user_group(user: magpie.models.User, group: magpie.models.Group, db_session: sqlalchemy.orm.session.Session) pyramid.httpexceptions.HTTPSuccessful[source]

Associates the pending user or existing user to the group.

Creates either a new user-group relationship (user membership to a group) or a pending terms and conditions confirmation. If the group requires a T&C confirmation, sends an email for T&C confirmation, else, the user is assigned directly to the group.

Returns:

valid HTTP response on successful operations.

Raises:

HTTPError – corresponding error matching problem encountered.

magpie.api.management.user.user_utils.handle_user_group_terms_confirmation(tmp_token: magpie.models.TemporaryToken, request: pyramid.request.Request) pyramid.response.Response[source]

Handles the confirmation of a user to accept the terms and conditions of a group.

Generates the appropriate response that will be displayed to the user.

magpie.api.management.user.user_utils.delete_user_group(user: magpie.models.User, group: magpie.models.Group, db_session: sqlalchemy.orm.session.Session) None[source]

Deletes a user-group relationship (user membership to a group).

Returns:

nothing - user-group is deleted.

Raises:

HTTPNotFound – if the combination cannot be found.

magpie.api.management.user.user_utils.delete_user_resource_permission_response(user: magpie.models.User, resource: magpie.typedefs.ServiceOrResourceType, permission: magpie.permissions.PermissionSet, db_session: sqlalchemy.orm.session.Session, similar: bool = True) pyramid.httpexceptions.HTTPException[source]

Get validated response on deleted user resource permission.

Parameters:
  • user – user for which to delete the permission.

  • resource – service or resource for which to delete the permission.

  • permission – permission with modifiers to be deleted.

  • db_session – database connection.

  • similar – Allow matching provided permission against any similar database permission. Otherwise, must match exactly.

Returns:

valid HTTP response on successful operations.

Raises:

HTTPException – error HTTP response of corresponding situation.

magpie.api.management.user.user_utils.get_similar_user_resource_permission(user: magpie.models.User, resource: magpie.typedefs.ServiceOrResourceType, permission: magpie.permissions.PermissionSet, db_session: sqlalchemy.orm.session.Session) magpie.permissions.PermissionSet | None[source]

Obtains the user service/resource permission that corresponds to the provided one.

Lookup considers only similar applied permission such that other permission modifiers don’t affect comparison.

magpie.api.management.user.user_utils.get_user_resource_permissions(user: magpie.models.User, resource: magpie.models.Resource, db_session: sqlalchemy.orm.session.Session, inherit: bool = False, resolve: bool = False) Tuple[List[magpie.permissions.PermissionSet], magpie.permissions.PermissionType, bool][source]

Retrieves user resource permissions applied directly, with inherited group permissions, or resolve between them.

Parameters:
  • user – user for which to retrieve permissions for the resource, and optionally its groups as well.

  • resource – resource for which permissions to retrieve are applied on.

  • db_session – database session

  • inherit – obtain permissions with user’s group inheritance (duplicate permissions possible across user/groups)

  • resolve – resolve permissions across user/groups to obtain a single highest priority permission on resource.

magpie.api.management.user.user_utils.get_user_resource_permissions_response(user: magpie.models.User, resource: magpie.typedefs.ServiceOrResourceType, request: pyramid.request.Request, inherit_groups_permissions: bool = True, resolve_groups_permissions: bool = False, effective_permissions: bool = False) pyramid.httpexceptions.HTTPException[source]

Retrieves user resource permissions with or without inherited group permissions.

Alternatively retrieves the effective user resource permissions, where group permissions are implied as True.

Warning

Does not consider direct Resource ownership.

See also

Returns:

valid HTTP response on successful operations.

Raises:

HTTPException – error HTTP response of corresponding situation.

magpie.api.management.user.user_utils.get_user_services(user: magpie.models.User, request: pyramid.request.Request, cascade_resources: bool = False, format_as_list: bool = False, inherit_groups_permissions: bool = False, resolve_groups_permissions: bool = False, service_types: List[magpie.typedefs.Str] | None = None) magpie.typedefs.UserServicesType[source]

Returns services by type with corresponding services by name containing sub-dict information.

Parameters:
  • user – user for which to find services

  • request – request with database session connection

  • cascade_resources – If False, return only services which the User has Immediate Permissions on specialized top-level resources corresponding to a Service. Otherwise, return every service that has at least one sub-resource with permissions (children at any-level). In both cases, the permissions looked for consider either only Direct Permissions or any Inherited Permission according to the value of inherit_groups_permissions.

  • inherit_groups_permissions – If False, return only user-specific service/sub-resources Direct Permissions. Otherwise, resolve Inherited Permissions using all groups the user is member of.

  • resolve_groups_permissions – Whether to combine Direct Permissions and Inherited Permissions for respective resources or not.

  • format_as_list – Returns as list of service dict information (not grouped by type and by name)

  • service_types – Filter list of service types for which to return details. All service types are used if omitted.

Returns:

Only services which the user as Direct Permissions or considering all tree hierarchy, and for each case, either considering only user permissions or every Inherited Permission, according to provided options.

Return type:

Mapping of services by type to corresponding services by name containing each sub-mapping of their information, unless format_as_list is True, in which case a flat list of service information is returned.

magpie.api.management.user.user_utils.get_user_service_permissions(user: magpie.models.User, service: magpie.models.Service, request: pyramid.request.Request, inherit_groups_permissions: bool = True, resolve_groups_permissions: bool = False) List[magpie.permissions.PermissionSet][source]

Retrieve the permissions the user has directly on a service or inherited permissions by its group memberships.

Warning

magpie.api.management.user.user_utils.filter_user_permission(resource_permission_list: List[ziggurat_foundations.permissions.PermissionTuple], user: magpie.models.User) Iterable[ziggurat_foundations.permissions.PermissionTuple][source]

Retrieves only user Direct Permissions amongst a list of user/group resource/service permissions.

magpie.api.management.user.user_utils.resolve_user_group_permissions(resource_permission_list: List[magpie.typedefs.ResolvablePermissionType]) Iterable[magpie.permissions.PermissionSet][source]

Reduces overlapping user Inherited Permission for corresponding resources/services amongst the given list.

User Direct Permissions have the top-most priority and are therefore selected first if permissions are found for corresponding resource. In such case, only one entry is possible (it is invalid to have more than one combination of (User, Resource, Permission), including modifiers, as per validation during their creation).

Otherwise, for corresponding Inherited Permissions, resolve the prioritized Permission across every group. Similarly to users, magpie.groups.group_utils.get_similar_group_resource_permission() validate that only one combination of (Group, Resource, Permission) can exist including permission modifiers. Only, cross-group memberships for a given resource must then be computed.

Priority of combined group-only permissions follows 3 conditions:
  1. Permissions inherited from special group MAGPIE_ANONYMOUS_GROUP have lower priority than any other more explicit group membership, regardless of permission modifiers applied on it.

  2. Permissions of same group priority with Access.DENY are prioritized over Access.ALLOW.

  3. Permissions of same group priority with Scope.RECURSIVE are prioritized over Access.MATCH as they affect a larger range of resources when Effective Permissions are eventually requested.

Note

Resource tree inherited resolution is not considered here (no recursive Effective Permission computed). Only same-level scope of every given resource is processed independently. The intended behaviour here is therefore to help illustrate in responses how deep is a given permission going to have an impact onto lower-level resources, making Scope.RECURSIVE more important than specific instance Scope.MATCH.

See also

  • Sorting methods of magpie.permissions.PermissionSet that orders the permissions with desired result.

  • magpie.groups.group_utils.get_similar_group_resource_permission()

  • magpie.users.user_utils.get_similar_user_resource_permission()

magpie.api.management.user.user_utils.regroup_permissions_by_resource(resource_permissions: Iterable[magpie.typedefs.ResolvablePermissionType], resolve: bool = False) magpie.typedefs.ResourcePermissionMap[source]

Regroups multiple uncategorized permissions into a dictionary of corresponding resource IDs.

While regrouping the various permissions (both Direct Permissions and any amount of groups Inherited Permissions) under their respective resource by ID, optionally resolve overlapping or conflicting permissions by name such that only one permission persists for that resource and name.

Parameters:
  • resource_permissions – List of resource permissions to process. Can include both user Direct Permissions and its groups Inherited Permissions.

  • resolve – When False, only mapping by resource ID is accomplished. Full listing of permissions is returned. Otherwise, resolves the corresponding resource permissions (by same ID) considering various priority rules to obtain unique permission names per resource.

Returns:

resolved permission

magpie.api.management.user.user_utils.get_user_resources_permissions_dict(user: magpie.models.User, request: pyramid.request.Request, resource_types: List[magpie.typedefs.Str] | None = None, resource_ids: List[int] | None = None, inherit_groups_permissions: bool = True, resolve_groups_permissions: bool = False) magpie.typedefs.ResourcePermissionMap[source]

Creates a dictionary of resources ID with corresponding permissions of the user.

Parameters:
  • user – user for which to find resources permissions

  • request – request with database session connection

  • resource_types – filter the search query with only the specified resource types

  • resource_ids – filter the search query to only the specified resource IDs

  • inherit_groups_permissions – Whether to include group inherited permissions from user memberships or not. If False, return only user-specific resource permissions. Otherwise, resolve inherited permissions using all groups the user is member of.

  • resolve_groups_permissions – whether to combine corresponding user/group permissions into one or not.

Returns:

Only resources which the user has permissions on, or including all Inherited Permissions, according to inherit_groups_permissions argument.

magpie.api.management.user.user_utils.get_user_service_resources_permissions_dict(user: magpie.models.User, service: magpie.models.Service, request: pyramid.request.Request, inherit_groups_permissions: bool = True, resolve_groups_permissions: bool = False) magpie.typedefs.ResourcePermissionMap[source]

Retrieves all permissions the user has for every Resource nested under the Service.

The retrieved permissions can either include only Direct Permissions or a combination of user and group Inherited Permissions accordingly to provided options.

Returns:

dictionary of resource IDs with corresponding permissions.

magpie.api.management.user.user_utils.check_user_info(user_name: magpie.typedefs.Str = None, email: magpie.typedefs.Str = None, password: magpie.typedefs.Str = None, group_name: magpie.typedefs.Str = None, check_name: bool = True, check_email: bool = True, check_password: bool = True, check_group: bool = True) None[source]

Validates provided user information to ensure they are adequate for user creation.

Using check_ prefixed arguments, individual field checks can be disabled (check all by default).

Raises:

HTTPException – appropriate error for the invalid field value or format that was checked as applicable.

Returns:

nothing if all enabled checks are successful.

magpie.api.management.user.user_utils.check_user_editable(user: magpie.models.User, container: magpie.typedefs.AnySettingsContainer) None[source]

Verify if the specified user is allowed to receive modifications (to it directly or any resource referring to it).

Parameters:
  • user – User to validate.

  • container – Any container to retrieve application settings.

Raises:

HTTPForbidden – When user is not allowed to be edited.

Returns:

Nothing if allowed edition.

magpie.api.management.user.user_utils.get_user_groups_checked(user: magpie.models.User, db_session: sqlalchemy.orm.session.Session) List[magpie.typedefs.Str][source]

Obtains the validated list of group names from a pre-validated user.