Lib

This section contains a complete API reference of the kadi.lib Python module.

API

class kadi.lib.api.blueprint.APIBlueprint(name: str, import_name: str, static_folder: ~typing.Optional[~typing.Union[str, ~os.PathLike]] = None, static_url_path: ~typing.Optional[str] = None, template_folder: ~typing.Optional[~typing.Union[str, ~os.PathLike]] = None, url_prefix: ~typing.Optional[str] = None, subdomain: ~typing.Optional[str] = None, url_defaults: ~typing.Optional[dict] = None, root_path: ~typing.Optional[str] = None, cli_group: ~typing.Optional[str] = <object object>)[source]

Bases: Blueprint

Custom Flask blueprint with support for API versioning.

route(rule, **options)[source]

Decorator to register a view function for a given URL rule.

Adds a new option v to Flask’s route decorator, allowing to set an API endpoint for one or multiple specific API versions.

Example:

@blueprint.route("/records", v=["v1", "v2"])
def get_records():
    pass

The specified API versions all have to be valid, i.e. they have to be part of the available API versions defined in kadi.lib.constants.API_VERSIONS. If no versions are given, the endpoint defaults to all available versions. In any case, the normal endpoint without any version will be created as well, pointing to the same function as the endpoint with the latest version.

For example, the above code would lead to the following endpoints and URLs (assuming an URL prefix of "/api"), where the last two endpoints would point to the same function:

  • "api.get_records_v1" -> "/api/v1/records"

  • "api.get_records_v2" -> "/api/v2/records"

  • "api.get_records" -> "/api/records"

Alternatively, the version can be set to None explicitly, in which case this decorator will behave like the standard route decorator, i.e. no versioning will be used at all. This is especially useful for internal endpoints where versioning is unnecessary.

The version is also used when generating the API documentation.

Parameters:
  • rule – The URL rule as string.

  • endpoint – (optional) The endpoint for the registered URL rule. Defaults to the name of the function with the version appended, if present.

  • v – (optional) A string or list of strings specifying the supported API versions.

  • **options – Additional options to be forwarded to the underlying rule system of Flask.

kadi.lib.api.core.json_response(status_code, body=None)[source]

Return a JSON response to a client.

Parameters:
  • status_code – The HTTP status code of the response.

  • body – (optional) The response body, which must be JSON serializable. Defaults to an empty dictionary.

Returns:

The JSON response.

kadi.lib.api.core.json_error_response(status_code, message=None, description=None, **kwargs)[source]

Return a JSON error response to a client.

Uses json_response() with the given headers and a body in the following form, assuming no additional error information was provided:

{
    "code": 404,
    "message": "<message>",
    "description": "<description>",
}
Parameters:
  • status_code – See json_response().

  • message – (optional) The error message. Defaults to the result of kadi.lib.web.get_error_message() using the given status code.

  • description – (optional) The error description. Defaults to the result of kadi.lib.web.get_error_description() using the given status code.

  • **kwargs – Additional error information that will be included in the response body. All values need to be JSON serializable.

Returns:

The JSON response.

kadi.lib.api.core.get_access_token()[source]

Get an access token from the current request.

Currently, this will either be a personal token or an OAuth2 server token. The token value has to be included as a “Bearer” token within an “Authorization” header.

Returns:

An access token object or None if no valid token can be found or no request context currently exists.

kadi.lib.api.core.check_access_token_scopes(*scopes, operator='and')[source]

Check if the current access token contains certain scope values.

The current access token will be retrieved using utils.get_access_token().

Parameters:
  • *scopes – One or multiple scope values to check in the form of "<object>.<action>".

  • operator – (optional) The operator the given scope values should be combined with. One of "and" or "or".

Returns:

True if the access token either contains all given scope values, has full access or the current request contains no valid access token at all, False otherwise or if the given operator is invalid.

kadi.lib.api.core.scopes_required(*scopes, operator='and')[source]

Decorator to add required access token scope values to an API endpoint.

Uses check_access_token_scopes(), so the scopes are only checked if the current request actually contains a valid access token. Therefore, this decorator usually only makes sense for public API endpoints that can be accessed by using an access token.

The scope values are also used when generating the API documentation.

Example:

@blueprint.route("/records")
@login_required
@scopes_required("record.read")
def get_records():
    pass
Parameters:
kadi.lib.api.core.internal(func)[source]

Decorator to mark an API endpoint as internal.

The information about an endpoint being internal is also used when generating the API documentation.

Internal endpoints can only be accessed via the session, not via access tokens. This is not to be confused with kadi.lib.api.utils.is_internal_api_request().

kadi.lib.api.core.experimental(func)[source]

Decorator to mark an API endpoint as experimental.

The information about an endpoint being experimental is also used when generating the API documentation.

Experimental endpoints can only be called if the EXPERIMENTAL_FEATURES flag in the application’s configuration is set.

class kadi.lib.api.models.PersonalToken(**kwargs)[source]

Bases: SimpleReprMixin, AccessTokenMixin, Model

Model to represent personal tokens.

These kind of access tokens always belong to and are managed by a certain user, so they may also be referred to as personal access tokens (PAT).

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'name']

See SimpleReprMixin.

check_constraints = {'name': {'length': {'max': 150}}}

See kadi.lib.db.generate_check_constraints().

id

The ID of the personal token, auto incremented.

name

The name of the personal token.

Restricted to a maximum length of 150 characters.

token_hash

The actual, hashed token value.

expires_at

The optional date and time the personal token expires in.

scope

The optional scope of the access token.

Represented as a single string defining a list of space-delimited scope values.

user

The user relationship of the access token.

A corresponding relationship should also be defined in the user table.

user_id

The ID of the user the access token belongs to.

created_at

The date and time the personal token was created at.

last_used

The date and time the personal token was last used.

property is_expired

Check if the personal token is expired.

static new_token(include_prefix=True)[source]

Create a new random token value.

Parameters:

include_prefix – (optional) Whether to include a prefix before the actual token value to distinguish it with other types of access tokens.

Returns:

The generated token value.

static hash_token(token)[source]

Create a secure hash of a token value.

Parameters:

token – The token value to hash.

Returns:

The calculated hash as a hexadecimal value.

classmethod get_by_token(token)[source]

Get a personal token using a token value.

Parameters:

token – The token value to search for.

Returns:

The personal token or None.

classmethod create(*, user, name, scope=None, expires_at=None, token=None)[source]

Create a new personal token and add it to the database session.

Parameters:
  • user – The user the personal token should belong to.

  • name – The name of the personal token.

  • scope – (optional) The scope of the personal token.

  • expires_at – (optional) The expiration date of the personal token.

  • token – (optional) The actual token value, which will be hashed before persisting. Defaults to a token value created by new_token().

Returns:

The new PersonalToken object.

class kadi.lib.api.schemas.PersonalTokenSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent personal tokens.

See PersonalToken.

kadi.lib.api.utils.is_api_request()[source]

Check if the current request is an API request.

A request is an API request if the path of the current request path starts with "/api".

Returns:

True if the request is an API request, False otherwise.

kadi.lib.api.utils.is_internal_api_request()[source]

Check if the current API request is an “internal” one.

An API request is marked as internal if it includes a query parameter _internal with any value (e.g. "https://...?_internal=true"). This can be useful for e.g. returning additional data that is only relevant for internal use. Note that it does not matter whether the request uses the session or an access token.

Returns:

True if the request is internal, False otherwise.

kadi.lib.api.utils.get_api_version()[source]

Get the API version from the current request path.

Returns:

The current API version or None if the current request is not an API request or no valid version is found.

kadi.lib.api.utils.get_access_token_scopes()[source]

Get all available access token scopes.

The available scopes are combined from all resource permissions (specifically, all regular and global actions) and some additional scopes as defined in kadi.lib.constants.ACCESS_TOKEN_SCOPES.

Returns:

A dictionary mapping a scope’s object to a list of respective actions.

kadi.lib.api.utils.create_pagination_data(total, page, per_page, endpoint=None, **kwargs)[source]

Create pagination information for use in a JSON response.

Since the pagination data will include links to the current, next and previous “pages”, the necessary information to build said links needs to be given as well, i.e. the endpoint and its corresponding URL parameters.

Parameters:
  • total – The total amount of items.

  • page – The current page.

  • per_page – Items per page.

  • endpoint – The endpoint used to build links to the current, next and previous page. Defaults to the endpoint of the current request.

  • **kwargs – Additional keyword arguments to build the links with.

Returns:

The pagination information as dictionary in the following form:

{
    "_pagination": {
        "page": 2,
        "per_page": 10,
        "total_pages": 3,
        "total_items": 25,
        "_links": {
            "prev": "https://...?page=1&...",
            "self": "https://...?page=2&...",
            "next": "https://...?page=3&...",
        }
    }
}

The list of items is initially empty and can be filled afterwards with whatever data should be returned. Note that the links to the previous and next pages are only present if the respective page actually exists.

kadi.lib.api.utils.check_max_content_length()[source]

Check whether the current request exceeds the maximum configured content length.

This can be used in places where the content length is not checked automatically, which currently is only done when parsing form data.

Will make use of the MAX_CONTENT_LENGTH in the application’s configuration. If the content length is exceeded, automatically aborts the current request with a JSON error response and status code 413.

kadi.lib.api.utils.status(status_code, description)[source]

Decorator to add response status information to an API endpoint.

This information is currently only used when generating the API documentation.

Parameters:
  • status_code – The status code of the response.

  • description – The description corresponding to the status code, describing when the status code occurs or whether there is a response body. Supports reST syntax.

kadi.lib.api.utils.reqschema(schema, description='', bind=True)[source]

Decorator to add request body information to an API endpoint using a schema.

This information is mainly used when generating the API documentation.

Parameters:
  • schema – The schema class or instance to use as base for the request body information.

  • description – (optional) Additional description of the request body. Supports reST syntax.

  • bind – (optional) Flag indicating whether the schema should also be injected into the decorated function as keyword argument schema.

kadi.lib.api.utils.reqform(form_data, description='', enctype='multipart/form-data')[source]

Decorator to add request body information to an API endpoint using form data.

This information is currently only used when generating the API documentation.

Parameters:
  • form_data

    The request body information as a list of tuples in the following form:

    [
        (
            "<field>",
            {
                # Defaults to "String".
                "type": "Integer",
                # Defaults to False.
                "required": True,
                # The default value will be converted to a string.
                "default": 1,
            }
    
        )
    ]
    

  • description – (optional) Additional description of the request body. Supports reST syntax.

  • enctype – (optional) The encoding type of the form data.

Cache

kadi.lib.cache.memoize_request(func)[source]

Decorator to cache a function call’s result during a request.

Uses an in-memory dictionary as cache that will be deleted again after the current request. The functions fully qualified name and arguments will be used as key to store its result for following calls.

Disabled during testing.

Config

kadi.lib.config.core.get_sys_config(key, use_fallback=True)[source]

Get the value of a global config item from the database.

This function can be used as an alternative to directly accessing the application’s configuration if a certain config item can be stored in the database as well.

Parameters:
  • key – The key of the config item.

  • use_fallback – (optional) Whether the application’s configuration should be used as a fallback if no matching key could be found in the database.

Returns:

The value of the config item or kadi.lib.config.core.MISSING if no matching item could be found.

kadi.lib.config.core.set_sys_config(key, value)[source]

Set the value of a global config item in the database.

Note that trying to set an existing config item to its default value, as specified in the application’s current configuration class, will instead remove this config item from the database.

Parameters:
  • key – The key of the config item.

  • value – The value of the config item, which needs to be JSON serializable.

Returns:

The created or updated config item or None if either the given key does not exist in the application’s current configuration class or the given value matches the default value of the corresponding key.

kadi.lib.config.core.remove_sys_config(key)[source]

Remove a global config item from the database.

Parameters:

key – The key of the config item.

Returns:

True if the config item was deleted successfully, False if no such item exists.

kadi.lib.config.core.get_user_config(key, user=None, default=<kadi.lib.config.core.MISSING>, decrypt=False)[source]

Get the value of a user-specific config item from the database.

Parameters:
  • key – The key of the config item.

  • user – (optional) The user the config item belongs to. Defaults to the current user.

  • default – (optional) The value to return if no config item was found. Defaults to kadi.lib.config.core.MISSING.

  • decrypt – (optional) Flag indicating whether the value of the config item should be decrypted.

Returns:

The value of the config item or the default value if either no matching item could be found or if decrypt is True and the value could not be decrypted.

kadi.lib.config.core.set_user_config(key, value, user=None, encrypt=False)[source]

Set the value of a user-specific config item in the database.

Parameters:
  • key – The key of the config item.

  • value – The value of the config item, which needs to be JSON serializable.

  • user – (optional) The user the config item belongs to. Defaults to the current user.

  • encrypt – (optional) Flag indicating whether the value of the config item should be encrypted.

Returns:

The created or updated config item.

kadi.lib.config.core.remove_user_config(key, user=None)[source]

Remove a user-specific config item from the database.

Parameters:
  • key – The key of the config item.

  • user – (optional) The user the config item belongs to. Defaults to the current user.

Returns:

True if the config item was deleted successfully, False if no such item exists.

class kadi.lib.config.models.ConfigItem(**kwargs)[source]

Bases: SimpleReprMixin, SimpleTimestampMixin, Model

Model to store global or user-specific config items.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'key', 'user_id']

See SimpleReprMixin.

id

The ID of the config item, auto incremented.

key

The key of the config item.

value

The value of the config item.

created_at

The date and time an object has been created at.

Always uses the current UTC time.

last_modified

The date and time an object was last modified.

Always uses the current UTC time as initial value. After calling register_timestamp_listener() for an inheriting mixin class, this timestamp can automatically get updated by implementing “_before_flush_timestamp” as a class method.

user_id

The optional ID of the user the config item belongs to.

If not set, the config item is global.

classmethod create(*, key, value, user=None)[source]

Create a new config item and add it to the database session.

Parameters:
  • key – The key of the config item.

  • value – The value of the config item, which needs to be JSON serializable.

  • user – (optional) The user the config item belongs to.

Returns:

The new ConfigItem object.

classmethod update_or_create(*, key, value, user=None)[source]

Update an existing config item or create one if it does not exist yet.

See create() for an explanation of the parameters.

Returns:

The new or updated ConfigItem object.

Conversion

kadi.lib.conversion.strip(value)[source]

Strip all surrounding whitespaces in one or multiple strings.

Parameters:

value – A single string or a list of strings to strip.

Returns:

The stripped string(s) or None if the input was None as well.

kadi.lib.conversion.normalize(value)[source]

Normalize all and strip surrounding whitespaces in one or multiple strings.

Parameters:

value – A single string or a list of strings to normalize.

Returns:

The normalized string(s) or None if the input was None as well.

kadi.lib.conversion.lower(value)[source]

Lowercase all characters in one or multiple strings.

Parameters:

value – A single string or a list of strings to lowercase.

Returns:

The lowercased string(s) or None if the input was None as well.

kadi.lib.conversion.truncate(value, length)[source]

Truncate one or multiple strings based on a given length.

Parameters:
  • value – A single string or a list of strings to truncate.

  • length – The maximum length of the string.

Returns:

The truncated string(s) or None if the input was None as well.

kadi.lib.conversion.recode_string(value, from_encoding='utf-8', to_encoding='utf-8')[source]

Change the encoding of a string.

Parameters:
  • value – The string value.

  • from_encoding – (optional) The original encoding of the string.

  • to_encoding – (optional) The target encoding of the string.

Returns:

A copy of the newly encoded string or the original value if the given value was not a string or the recoding failed.

kadi.lib.conversion.clamp(value, min_value, max_value)[source]

Return a value clamped to the inclusive range of the given min and max values.

Parameters:
  • min_value – The minumum value.

  • max_value – The maximum value.

Returns:

The clamped or unmodified value.

kadi.lib.conversion.none(value)[source]

Return None if a given value is falsy.

Parameters:

value – A value to check for truthness.

Returns:

The unmodified value or None if it is falsy.

kadi.lib.conversion.empty_str(value)[source]

Return an empty string if a given value is None.

Parameters:

value – A value to check for being None.

Returns:

The unmodified value or an empty string if it is None.

kadi.lib.conversion.to_primitive_type(value)[source]

Convert any non-primitive value to a string.

The primitive types considered here are str, int, float, bool. A None value will also be returned as is.

Parameters:

value – The value to convert.

Returns:

The string representation of the value or the unmodified value if it is a primitive type or None.

kadi.lib.conversion.parse_datetime_string(value)[source]

Parse a datetime string.

Parameters:

value – The datetime string to parse.

Returns:

A timezone aware datetime object in UTC as specified in Python’s datetime module or None if the given string is not valid.

kadi.lib.conversion.parse_boolean_string(value)[source]

Parse a boolean string.

The given string is parsed based on typical values used for thruthness, including True, "true", "t", "yes", "y", "on" and "1" (case insensitive for all string values), instead of using Python’s bool conversion. All other values are considered false.

Parameters:

value – The boolean string to parse.

Returns:

True if the given string is considered truthy, False otherwise.

kadi.lib.conversion.parse_json_object(value)[source]

Parse a JSON object string as a dictionary.

Parameters:

value – The JSON object string to parse.

Returns:

The parsed dictionary or an empty dictionary if the given string is not valid.

kadi.lib.conversion.markdown_to_html(value)[source]

Render a markdown string as HTML.

Note that manually entered HTML will be left intact, as it will be escaped accordingly.

Parameters:

value – The string to render.

Returns:

The rendered string or None if the input was None as well.

kadi.lib.conversion.strip_markdown(value)[source]

Strip a string of its markdown directives.

Note that not all directives may be stripped, since some may not be supported by the markdown renderer used in markdown_to_html().

Parameters:

value – The string to strip.

Returns:

The stripped string copy or None if the input was None as well.

Database

class kadi.lib.db.UTCDateTime(*args, **kwargs)[source]

Bases: TypeDecorator

Custom timezone aware DateTime type using UTC.

As dates are currently saved without timezone information (and always interpreted as UTC), the timezone information has to be removed from datetime objects before persisting, as otherwise they are converted to local time. When retrieving the value, the timezone will be added back in.

impl

alias of DateTime

process_bind_param(value, dialect)[source]

Convert to UTC and then remove the timezone.

process_result_value(value, dialect)[source]

Replace the missing timezone with UTC.

class kadi.lib.db.BaseTimestampMixin[source]

Bases: object

Base mixin class for SQLAlchemy models to add timestamp columns.

In all current implementations, changes in columns and relationship-based collections can be ignored by specifying the Meta.timestamp_exclude attribute in the inheriting class. It should be a list of strings specifying the attribute names to exclude.

Example:

class Foo:
    class Meta:
        timestamp_exclude = ["bar", "baz"]
created_at = Column(None, UTCDateTime(), table=None, nullable=False, default=ColumnDefault(<function utcnow>))

The date and time an object has been created at.

Always uses the current UTC time.

last_modified = Column(None, UTCDateTime(), table=None, nullable=False, default=ColumnDefault(<function utcnow>))

The date and time an object was last modified.

Always uses the current UTC time as initial value. After calling register_timestamp_listener() for an inheriting mixin class, this timestamp can automatically get updated by implementing “_before_flush_timestamp” as a class method.

classmethod register_timestamp_listener()[source]

Register a listener to automatically update the last modification timestamp.

Uses SQLAlchemy’s before_flush event and propagates to all inheriting models.

update_timestamp()[source]

Manually trigger an update to the last modification timestamp.

class kadi.lib.db.SimpleTimestampMixin[source]

Bases: BaseTimestampMixin

Timestamp mixin class which triggers on all changes.

class kadi.lib.db.StateTimestampMixin[source]

Bases: BaseTimestampMixin

Timestamp mixin class which only triggers on changes in active objects.

An object is considered active if its marked as active via its state attribute, which needs to be present in an inheriting model. Besides the object itself, changes in relationship-based collections consisting of inactive objects only are also ignored.

update_timestamp()[source]

Manually trigger an update to the last modification timestamp.

Only actually triggers the update if the object is marked as active.

class kadi.lib.db.NestedTransaction(exc=<class 'sqlalchemy.exc.SQLAlchemyError'>)[source]

Bases: object

Context manager to start a “nested” transaction.

The nested transaction uses the SAVEPOINT feature of the database, which will be triggered when entering the context manager. Once the context manager exits, the savepoint is released, which does not actually persist the changes done in the savepoint yet. If the release produces the given exception, the savepoint will be rolled back automatically. The success attribute of the transaction can be used to check the result of the release operation afterwards.

Parameters:

exc – (optional) The exception to catch when releasing the savepoint.

property success

Get the status of the nested transaction once the savepoint is released.

Will always be False before the context manager exits.

kadi.lib.db.update_object(obj, **kwargs)[source]

Convenience function to update database objects.

Only columns (i.e. attributes) that actually exist will get updated.

Parameters:
  • obj – The object to update.

  • **kwargs – The columns to update and their respective values.

kadi.lib.db.composite_index(tablename, *cols)[source]

Generate a composite index.

Parameters:
  • tablename – The name of the table.

  • *cols – The names of the columns.

Returns:

The Index instance.

kadi.lib.db.unique_constraint(tablename, *cols)[source]

Generate a unique constraint.

Parameters:
  • tablename – The name of the table.

  • *cols – The names of the columns.

Returns:

The UniqueConstraint instance.

kadi.lib.db.check_constraint(constraint, name)[source]

Generate a check constraint.

Parameters:
  • constraint – The constraint expression as string.

  • name – The name of the constraint.

Returns:

The CheckConstraint instance.

kadi.lib.db.length_constraint(col, min_value=None, max_value=None)[source]

Generate a length check constraint for a column.

Parameters:
  • col – The name of the column.

  • min_value – (optional) Minimum length.

  • max_value – (optional) Maximum length.

Returns:

The CheckConstraint instance.

kadi.lib.db.range_constraint(col, min_value=None, max_value=None)[source]

Generate a range check constraint for a column.

Parameters:
  • col – The name of the column.

  • min_value – (optional) Minimum value.

  • max_value – (optional) Maximum value.

Returns:

The CheckConstraint instance.

kadi.lib.db.values_constraint(col, values)[source]

Generate a values check constraint for a column.

Parameters:
  • col – The name of the column.

  • values – List of values.

Returns:

The CheckConstraint instance.

kadi.lib.db.generate_check_constraints(constraints)[source]

Generate database check constraints.

Supports check constraints of type "length", "range" and "values". The constraints have to be given in the following form:

{
    "col_1": {"length": {"min": 0, "max": 10}},
    "col_2": {"range": {"min": 0, "max": 10}},
    "col_3": {"values": ["val_1", "val_2"]},
}
Parameters:

constraints – Dictionary of constraints to generate.

Returns:

A tuple of CheckConstraint instances.

kadi.lib.db.get_class_by_tablename(tablename)[source]

Get the model class mapped to a certain database table name.

Parameters:

tablename – Name of the table.

Returns:

The class reference or None if the table does not exist.

kadi.lib.db.is_column(model, attr)[source]

Check if a model’s attribute is a regular column.

Parameters:
  • model – The model that contains the column.

  • attr – Name of the column attribute.

Returns:

True if the attribute is a column, False otherwise.

kadi.lib.db.get_column_type(model, attr)[source]

Get the type of a column.

Parameters:
  • model – The model that contains the column.

  • attr – Name of the column attribute.

Returns:

The type of the column or None if the attribute is not a regular column.

kadi.lib.db.is_relationship(model, attr)[source]

Check if a model’s attribute is a relationship.

Parameters:
  • model – The model that contains the column.

  • attr – Name of the relationship attribute.

Returns:

True if the attribute is a relationship, False otherwise.

kadi.lib.db.is_many_relationship(model, attr)[source]

Check if a model’s attribute is a many-relationship.

Parameters:
  • model – The model that contains the column.

  • attr – Name of the relationship attribute.

Returns:

True if the attribute is a many-relationship, False otherwise.

kadi.lib.db.get_class_of_relationship(model, attr)[source]

Get the class of a relationship.

Parameters:
  • model – The model that contains the relationship.

  • attr – Name of the relationship attribute.

Returns:

The class reference or None if the attribute is not a relationship.

kadi.lib.db.escape_like(value, escape='\\')[source]

Escape a string for use in LIKE queries.

Will escape "%", "_" and the escape character specified by escape.

Parameters:
  • value – The string to escape.

  • escape – (optional) The escape character to use.

Returns:

The escaped string.

kadi.lib.db.acquire_lock(obj)[source]

Acquire a database lock on a given object.

The database row corresponding to the given object will be locked using FOR UPDATE until the session is committed or rolled back. Once the lock is acquired, the given object is also refreshed. Should only be used if strictly necessary, e.g. to prevent certain race conditions.

Parameters:

obj – The object to lock.

Returns:

The locked and refreshed object.

kadi.lib.db.has_extension(extension_name)[source]

Check if a given database extension is installed.

Currently only supported for PostgreSQL databases.

Parameters:

extension_name – The name of the extension.

Returns:

True if the extension is installed, False if the extension is not installed or the database is not PostgreSQL.

kadi.lib.db.has_pending_revisions()[source]

Check if the database has pending revisions.

Returns:

True if there are pending revisions, False otherwise.

Exceptions

exception kadi.lib.exceptions.KadiException[source]

Bases: Exception

Base exception class.

exception kadi.lib.exceptions.KadiConfigurationError[source]

Bases: KadiException

For general configuration errors.

exception kadi.lib.exceptions.KadiStorageError[source]

Bases: KadiException

For general file storage errors.

exception kadi.lib.exceptions.KadiFilesizeExceededError[source]

Bases: KadiStorageError

For errors relating to exceeded file size.

exception kadi.lib.exceptions.KadiFilesizeMismatchError[source]

Bases: KadiStorageError

For errors relating to file size validation.

exception kadi.lib.exceptions.KadiChecksumMismatchError[source]

Bases: KadiStorageError

For errors relating to file checksum validation.

exception kadi.lib.exceptions.KadiValidationError[source]

Bases: KadiException

For general validation errors.

exception kadi.lib.exceptions.KadiPermissionError[source]

Bases: KadiException

For general permissions errors.

exception kadi.lib.exceptions.KadiDatabaseError[source]

Bases: KadiException

For general database errors.

exception kadi.lib.exceptions.KadiDecryptionKeyError[source]

Bases: KadiDatabaseError

For errors relating to an invalid decryption key for encrypted fields.

Export

class kadi.lib.export.PDF(title='')[source]

Bases: FPDF

Base PDF export class using FPDF.

Parameters:

title – (optional) The title of the PDF, which will appear in the header on each page and in the metadata of the PDF itself.

static format_date(date_time, include_micro=False)[source]

Format a datetime object in a user-readable manner.

Parameters:
  • date_time – The datetime object to format as specified in Python’s datetime module.

  • include_micro – (optional) Flag indicating whether to include microseconds in the formatted datetime.

Returns:

The formatted datetime string.

header()[source]

Automatically prints a header on each page of the generated PDF.

footer()[source]

Automatically prints a footer on each page of the generated PDF.

truncated_cell(w, txt='', **kwargs)[source]

Print a cell with potentially truncated text based on the cell’s width.

Parameters:
  • w – The width of the cell.

  • txt – (optional) The text content of the cell.

  • **kwargs – Additional keyword arguments to pass to fpdf2’s cell function.

calculate_max_height(contents)[source]

Calculate the maximum height that will be required by multiple multi-cells.

Note that this method always uses the current font family and size for its calculations.

Parameters:

contents – A list of tuples containing the width, the text content and the font style of each cell.

Returns:

The maximum height the cells will require.

class kadi.lib.export.ROCrate(*args, version=None, sized=True, **kwargs)[source]

Bases: ZipStream

Base RO-Crate export class.

This class behaves like a ZipStream, which can be used to attach file paths and streams. Note that the files and the content of the metadata are currently not synchronized automatically.

Parameters:
  • *args – Additional arguments to pass to the ZipStream.

  • version – (optional) A version string that represents the current specification that is used for the RO-Crate, which will be saved as “version” in the metadata describing the main metadata file.

  • sized – (optional) Whether the crate should keep track of its size.

  • **kwargs – Additional keyword arguments to pass to the ZipStream.

property root_graph

Get the root graph of the RO-Crate metadata.

property root_dataset

Get the root dataset of the RO-Crate metadata.

get_entity(entity_id)[source]

Get an entity of the root graph by its ID.

Parameters:

entity_id – The ID of the entity to retrieve.

Returns:

The entity or None if no suitable entity could be found.

dump_metadata()[source]

Dump the RO-Crate metadata as formatted JSON string.

Returns:

The JSON formatted string.

class kadi.lib.export.RDFGraph(*args, **kwargs)[source]

Bases: Graph

Base RDF graph export class.

author_ref(user_data)[source]

Create an URI reference of an author.

Parameters:

user_data – The serialized data of the user, via UserSchema, to use as an author.

Returns:

The created URI reference.

Favorites

class kadi.lib.favorites.core.FavoriteMixin[source]

Bases: object

Mixin for SQLALchemy models to check whether an object is favorited.

is_favorite(user=None)[source]

Check if the current object is favorited by the given user.

Wraps is_favorite() with the type and ID of the current object.

Parameters:

user – (optional) The user whose favorites should be checked. Defaults to the current user.

Returns:

See is_favorite().

kadi.lib.favorites.core.is_favorite(object_name, object_id, user=None)[source]

Check if the given object is favorited by the given user.

Parameters:
  • object_name – The type of object.

  • object_id – The ID of a specific object.

  • user – (optional) The user whose favorites should be checked. Defaults to the current user.

Returns:

True if the object is favorited, False otherwise.

kadi.lib.favorites.core.toggle_favorite(object_name, object_id, user=None)[source]

Toggle the favorite state of the given object.

If a favorite already exists for the given object and user, it will be deleted from the database, otherwise it will be created.

Parameters:
  • object_name – The type of object.

  • object_id – The ID of a specific object.

  • user – (optional) The user the favorite object belongs to. Defaults to the current user.

class kadi.lib.favorites.models.Favorite(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model representing favorited objects.

Each favorite is associated with a user, a specific type of object and an ID referring to a specific object instance.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'object', 'object_id']

See SimpleReprMixin.

id

The ID of the favorite, auto incremented.

user_id

The ID of the user the favorite belongs to.

object

The type of object the favorite refers to.

Currently always refers to a specific model via its table name.

object_id

The ID of the object the favorite refers to.

created_at

The date and time the favorite was created at.

classmethod create(*, user, object, object_id)[source]

Create a new favorite and add it to the database session.

Parameters:
  • user – The user the favorite belongs to.

  • object – The object the favorite refers to.

  • object_id – The ID of the object.

Returns:

The new Favorite object.

Format

kadi.lib.format.duration(seconds)[source]

Create a human-readable, translated duration string from an amount of seconds.

Note that locale-aware translations are only supported when having an active request context.

Parameters:

seconds – The amount of seconds.

Returns:

The formatted duration string.

kadi.lib.format.filesize(num_bytes)[source]

Create a human-readable, localized file size from a given amount of bytes.

Based on Jinja’s filesizeformat filter. Note that locale-aware localization is only supported when having an active request context.

Parameters:

num_bytes – The amount of bytes as a string or number.

Returns:

The formatted file size string.

kadi.lib.format.timestamp(date_time=None, include_micro=False)[source]

Build a UTC timestamp from a specific date and time.

The timestamp will be in the form of "YYYYMMDDHHmmss".

Parameters:
  • date_time – (optional) A datetime object as specified in Python’s datetime module. Defaults to the current time.

  • include_micro – (optional) Flag indicating whether to include microseconds in the timestamp as well or not.

Returns:

The formatted timestamp string.

kadi.lib.format.pretty_type_name(cls_or_string)[source]

Return a pretty type name based on a class or a string.

Parameters:

cls_or_string – A class reference (e.g. str) or a corresponding string (e.g. "str").

Returns:

The pretty type name string.

Forms

class kadi.lib.forms.CustomFieldMixin[source]

Bases: object

Mixin class for all custom fields and for wrapping existing fields.

Adds a common dictionary conversion to all inheriting fields and also handles some common corner cases.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.BooleanField(*args, **kwargs)[source]

Bases: CustomFieldMixin, BooleanField

Regular boolean field inheriting from CustomFieldMixin.

class kadi.lib.forms.IntegerField(*args, **kwargs)[source]

Bases: CustomFieldMixin, IntegerField

Regular integer field inheriting from CustomFieldMixin.

class kadi.lib.forms.StringField(*args, **kwargs)[source]

Bases: CustomFieldMixin, StringField

Regular string field inheriting from CustomFieldMixin.

class kadi.lib.forms.SubmitField(*args, **kwargs)[source]

Bases: CustomFieldMixin, SubmitField

Regular submit field inheriting from CustomFieldMixin.

class kadi.lib.forms.PasswordField(*args, **kwargs)[source]

Bases: CustomFieldMixin, PasswordField

Regular password field inheriting from CustomFieldMixin.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.FileField(*args, **kwargs)[source]

Bases: CustomFieldMixin, FileField

Custom file field.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.LFTextAreaField(*args, **kwargs)[source]

Bases: CustomFieldMixin, TextAreaField

Custom text area field that converts CRLF to LF.

process_formdata(valuelist)[source]

Process data received over the wire from a form.

This will be called during form construction with data supplied through the formdata argument.

Parameters:

valuelist – A list of strings to process.

class kadi.lib.forms.UTCDateTimeField(*args, **kwargs)[source]

Bases: CustomFieldMixin, DateTimeField

Custom timezone aware DateTimeField using UTC.

Parameters:

date_format – (optional) The date format to use for parsing and serializing.

process_formdata(valuelist)[source]

Process data received over the wire from a form.

This will be called during form construction with data supplied through the formdata argument.

Parameters:

valuelist – A list of strings to process.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.SelectField(*args, **kwargs)[source]

Bases: CustomFieldMixin, SelectField

Custom select field.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.DynamicSelectField(*args, **kwargs)[source]

Bases: CustomFieldMixin, SelectField

Custom select field for dynamically generated selections.

The instance variable initial can be used to set an initial value to prefill the selection with.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.DynamicMultiSelectField(*args, **kwargs)[source]

Bases: CustomFieldMixin, SelectMultipleField

Custom multi select field for dynamically generated selections.

The instance variable initial can be used to set initial values to prefill the selection with.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.JSONField(*args, **kwargs)[source]

Bases: CustomFieldMixin, Field

Custom field that processes its data as JSON.

process_formdata(valuelist)[source]

Process data received over the wire from a form.

This will be called during form construction with data supplied through the formdata argument.

Parameters:

valuelist – A list of strings to process.

to_dict()[source]

Convert this field into a dictionary representation.

class kadi.lib.forms.KadiForm(*args, **kwargs)[source]

Bases: FlaskForm

Base class for all forms.

Parameters:

suffix – (optional) A suffix that will be appended to all field IDs in the form of "<id>_<suffix>". This is especially useful when dealing with multiple forms on the same page. Note that this differs in behavior from the prefix parameter of WTForms, since only the IDs of fields are effected and not their names.

class kadi.lib.forms.BaseConfigForm(*args, **kwargs)[source]

Bases: KadiForm

Base form class for use in setting config items.

All fields in an inheriting form will be populated automatically from suitable config items stored in the database, if applicable. As keys for the config items, the field names are taken in uppercase.

Parameters:
  • user – (optional) A user indicating whether global or user-specific config items are to be used for prepopulating the form and when setting the values of config items in the database via set_config_values().

  • key_prefix – (optional) A string value to use as a prefix for all config items retrieved from and saved in the database. The prefix is used in uppercase and combined with each uppercase field name in the form of "<key_prefix>_<field_name>".

  • ignored_fields – (optional) A set of field names, as specified in the class attributes, to ignore when prepopulating the form and when setting the values of config items in the database via set_config_values(). Note that the "submit" field is always ignored.

  • encrypted_fields – (optional) A set of field names, as specified in the class attributes, to use encryption/decryption for when prepopulating the form and when setting the values of config items in the database via set_config_values(). Note that this only works for user-specific config items.

  • **kwargs – Additional keyword arguments to pass to KadiForm.

set_config_values()[source]

Automatically set all config items based on the respective field data.

Useful to populate all relevant config items in the database after a form is submitted. Similar to prepopulating the form fields, the names of the fields are taken in uppercase as keys for each config item.

kadi.lib.forms.validate_identifier(form, field)[source]

Validate an identifier in a form field.

Uses kadi.lib.validation.validate_identifier().

Parameters:
  • form – The form object.

  • field – The field object.

kadi.lib.forms.validate_mimetype(form, field)[source]

Validate a MIME type in a form field.

Uses kadi.lib.validation.validate_mimetype().

Parameters:
  • form – The form object.

  • field – The field object.

kadi.lib.forms.validate_username(form, field)[source]

Validate a local username in a form field.

Uses kadi.lib.validation.validate_username().

Parameters:
  • form – The form object.

  • field – The field object.

kadi.lib.forms.validate_iri(form, field)[source]

Validate an IRI in a form field.

Uses kadi.lib.validation.validate_iri().

Parameters:
  • form – The form object.

  • field – The field object.

kadi.lib.forms.check_duplicate_identifier(model, identifier, exclude=None)[source]

Check for a duplicate identifier in a form.

Parameters:
  • model – The model class to check the identifier of.

  • identifier – The identifier to check.

  • exclude – (optional) An instance of the model that should be excluded in the check.

Jinja

class kadi.lib.jinja.SnippetExtension(environment: Environment)[source]

Bases: Extension

Jinja extension to pass variables to HTML snippets.

See render_snippet() for an explanation of the parameters.

Example:

{% snippet "my_snippet", foo=1, bar=2 %}
tags: Set[str] = {'snippet'}

if this extension parses this is the list of tags it’s listening to.

parse(parser)[source]

Parse the snippet tag and arguments.

kadi.lib.jinja.render_snippet(snippet, _module=None, **kwargs)[source]

Render an HTML snippet.

The snippet has to be in a directory called “snippets”. Otherwise, the same rules apply as in Flask’s render_template function.

Parameters:
  • snippet – The name of the snippet without the “.html” extension.

  • _module – (optional) If the snippet is part of a module, the name of this module can be specified using this parameter. It will be prepended before the snippet path.

  • **kwargs – The keyword arguments to pass to the snippet.

Returns:

The rendered snippet.

Licenses

class kadi.lib.licenses.models.License(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model to represent licenses.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'name']

See SimpleReprMixin.

id

The ID of the license, auto incremented.

name

The unique name of the license.

title

The title of the license.

url

The optional URL of the license.

classmethod create(*, name, title, url=None)[source]

Create a new license and add it to the database session.

Parameters:
  • name – The name of the license.

  • title – The title of the license.

  • url – (optional) The URL of the license.

Returns:

The new License object.

class kadi.lib.licenses.schemas.LicenseSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent licenses.

See License.

kadi.lib.licenses.utils.get_builtin_licenses()[source]

Get all built-in licenses.

Returns:

The licenses as dictionary, mapping the unique name of each license to another dictionary, containing the title ("title") and url ("url") of each license.

kadi.lib.licenses.utils.get_plugin_licenses()[source]

Get all licenses added via plugins.

Uses the kadi.plugins.spec.kadi_get_licenses() plugin hook to collect the licenses. Invalid licenses will be ignored.

Returns:

The licenses as dictionary, in the same format as returned via get_builtin_licenses().

LDAP

kadi.lib.ldap.make_upn(username, dn)[source]

Create a user principal name (UPN) for use in an Active Directory.

Parameters:
  • username – The name of a user to use as a prefix for the UPN.

  • dn – A DN to parse in order to retrieve the suffix of the UPN.

Returns:

The UPN in the form of "<username>@<domain>" or None if the given DN could not be parsed or does not contain any domain components.

kadi.lib.ldap.bind(connection)[source]

Try to authenticate with a server given an LDAP connection.

By default, LDAP connections are anonymous. The BIND operation establishes an authentication state between a client and a server.

Parameters:

connection – The connection object, see also make_connection().

Returns:

True if the BIND operation was successful, False otherwise.

kadi.lib.ldap.unbind(connection)[source]

Disconnect a given LDAP connection.

Parameters:

connection – The connection object, see also make_connection().

kadi.lib.ldap.make_server(host, port=389, use_ssl=False, validate_cert='REQUIRED', ciphers=None)[source]

Create a new LDAP Server object.

Parameters:
  • host – The host name or IP address of the LDAP server.

  • port – (optional) The port the LDAP server is listening on.

  • use_ssl – (optional) Flag indicating whether the entire connection should be secured via SSL/TLS.

  • validate_cert – (optional) Whether the certificate of the server should be validated. One of "NONE", "OPTIONAL" or "REQUIRED".

  • ciphers – (optional) One or more SSL/TLS ciphers to use as a single string according to the OpenSSL cipher list format. May also be set to "DEFAULT", in which case the default ciphers of the installed OpenSSL version are used.

Returns:

The new Server object or None if it could not be created.

kadi.lib.ldap.make_connection(server, user=None, password=None, use_starttls=False)[source]

Create a new LDAP Connection object.

Parameters:
  • server – The server object to use for the connection. See make_server().

  • user – (optional) The user for simple BIND.

  • password – (optional) The password of the user for simple BIND.

  • use_starttls – (optional) Flag indicating whether the connection should be secured via STARTTLS.

Returns:

The new Connection object or None if it could not be created.

kadi.lib.ldap.search(connection, search_base, search_filter, attribute_map, keep_list_attrs=False)[source]

Perform a search in an LDAP database given a connection.

Parameters:
  • connection – The LDAP connection to use. See make_connection().

  • search_base – The base of the search request.

  • search_filter – The filter of the search request.

  • attribute_map – A dictionary mapping arbitrary names to LDAP attribute names. The former names specify the keys to use for each search result (e.g. "firstname"), while the latter names specify the name of the attribute that should be extracted from the resulting LDAP entry (e.g. "givenName").

  • keep_list_attrs – (optional) Flag to indicate if results that have multiple values should be returned as lists or not. If not, only the first value of a result will be returned.

Returns:

A dictionary similar to the given attribute_map or None if no results could be retrieved. The LDAP attribute names will be replaced by the respective result value(s) in the result or with None if the attribute could not be found.

kadi.lib.ldap.modify_password(connection, user, new_password, old_password=None, active_directory=False)[source]

Modify a user’s LDAP password using an extended password modification operation.

Parameters:
  • connection – The LDAP connection to use. See make_connection().

  • user – The user whose password should be changed.

  • new_password – The new password of the user.

  • old_password – (optional) The old password of the user, if the LDAP server requires it.

  • active_directory – (optional) Flag indicating whether the LDAP server is an Active Directory, which does not support the standard extended password modification operation.

Returns:

A boolean value indicating whether the change was successful.

Mails

kadi.lib.mails.core.send_mail(*, subject, message, to_addresses, from_address=None, cc=None, bcc=None, attachments=None, reply_to=None, html_message=None, headers=None)[source]

Send an email to one or multiple recipients.

Uses the configuration values SMTP_HOST, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, SMTP_TIMEOUT and SMTP_USE_TLS set in the application’s configuration for the connection.

Parameters:
  • subject – The subject of the email.

  • message – The plain text body of the email.

  • to_addresses – A list of recipient addresses.

  • from_address – (optional) The sender’s email address. Defaults to the address set in MAIL_NO_REPLY in the current application’s configuration.

  • cc – (optional) A list of recipient addresses used in the “CC” header when sending the email.

  • bcc – (optional) A list of recipient addresses used in the “BCC” header when sending the email.

  • attachments – (optional) A list of attachments to put on the message. The list has to consist of triples in the form of (filename, content, mimetype). The content can either be a string or bytes object, while the MIME type will be guessed based on the given filename if omitted (i.e. set to None).

  • reply_to – (optional) A list of recipient addresses used in the “Reply-To” header when sending the email.

  • html_message – (optional) An HTML body of the email as alternative to the plain text version.

  • headers – (optional) A dictionary of additional headers to put on the message, mapping header names to their respective values.

Returns:

The number of emails that were sent successfully.

Raises:

ConnectionRefusedError: If no connection with the SMTP server could be established.

kadi.lib.mails.tasks.start_send_mail_task(*, subject, message, to_addresses, from_address=None, cc=None, bcc=None, attachments=None, reply_to=None, html_message=None, headers=None)[source]

Send a mail in a background task.

See kadi.lib.mails.core.send_mail() for the possible parameters.

In case the connection to the mail server fails, the task will be retried every 60 seconds until a maximum defined in CELERY_ANNOTATIONS in the application’s configuration is reached. Other errors will cause the task to fail, however.

Returns:

True if the task was started successfully, False otherwise. Note that the task being started successfully does not necessarily mean that the email will be sent successfully as well.

kadi.lib.mails.utils.send_email_confirmation_mail(identity, email=None)[source]

Send an email confirmation mail in a background task.

Uses kadi.lib.mails.tasks.start_send_mail_task() to send the mail.

Parameters:
  • identity – The local identity of the user whose email should be confirmed.

  • email – (optional) The email address to use as the recipient address and to include in the email confirmation token. Defaults to the email address of the given identity.

Returns:

See kadi.lib.mails.tasks.start_send_mail_task().

kadi.lib.mails.utils.send_password_reset_mail(identity)[source]

Send a password reset mail in a background task.

Uses kadi.lib.mails.tasks.start_send_mail_task() to send the mail.

Parameters:

identity – The local identity of the user whose password should be reset.

Returns:

See kadi.lib.mails.tasks.start_send_mail_task().

kadi.lib.mails.utils.send_test_mail(user)[source]

Send a test mail in a background task.

Uses kadi.lib.mails.tasks.start_send_mail_task() to send the mail.

Parameters:

user – The user to send the test email to.

Returns:

See kadi.lib.mails.tasks.start_send_mail_task().

Notifications

kadi.lib.notifications.core.create_notification_data(notification)[source]

Create notification data suitable for presenting it to a client.

Parameters:

notification – A Notification object to use for creating the notification data.

Returns:

A tuple containing the title and the HTML body of the notification.

kadi.lib.notifications.core.dismiss_notification(notification)[source]

Dismiss a notification.

If the notification is of type "task_status", the referenced task will be revoked as well.

Parameters:

notification – The Notification to dismiss.

class kadi.lib.notifications.models.NotificationNames[source]

Bases: StringEnum

String enum containing all possible name values for notifications.

class kadi.lib.notifications.models.Notification(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model to represent notifications.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'name']

See SimpleReprMixin.

id

The ID of the notification, auto incremented.

user_id

The ID of the user the notification belongs to.

name

The name of the notification.

data

The optional data of the notification, depending on its type.

created_at

The date and time the notification was created at.

classmethod create(*, user, name, data=None)[source]

Create a new notification and add it to the database session.

Parameters:
  • user – The user the notification belongs to.

  • name – The name of the notification.

  • data – (optional) The data of the notification.

Returns:

The new Notification object.

class kadi.lib.notifications.schemas.NotificationSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent notifications.

See Notification.

OAuth

class kadi.lib.oauth.core.AuthorizationCodeGrant(request, server)[source]

Bases: AuthorizationCodeGrant

OAuth2 authorization code grant.

TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_post']

Allowed client auth methods for token endpoint

save_authorization_code(code, request)[source]

Save authorization_code for later use. Developers MUST implement it in subclass. Here is an example:

def save_authorization_code(self, code, request):
    client = request.client
    item = AuthorizationCode(
        code=code,
        client_id=client.client_id,
        redirect_uri=request.redirect_uri,
        scope=request.scope,
        user_id=request.user.id,
    )
    item.save()
query_authorization_code(code, client)[source]

Get authorization_code from previously savings. Developers MUST implement it in subclass:

def query_authorization_code(self, code, client):
    return Authorization.get(code=code, client_id=client.client_id)
Parameters:
  • code – a string represent the code.

  • client – client related to this code.

Returns:

authorization_code object

delete_authorization_code(authorization_code)[source]

Delete authorization code from database or cache. Developers MUST implement it in subclass, e.g.:

def delete_authorization_code(self, authorization_code):
    authorization_code.delete()
Parameters:

authorization_code – the instance of authorization_code

authenticate_user(authorization_code)[source]

Authenticate the user related to this authorization_code. Developers MUST implement this method in subclass, e.g.:

def authenticate_user(self, authorization_code):
    return User.query.get(authorization_code.user_id)
Parameters:

authorization_code – AuthorizationCode object

Returns:

user

class kadi.lib.oauth.core.RefreshTokenGrant(request, server)[source]

Bases: RefreshTokenGrant

OAuth2 refresh token grant.

TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_post']

Allowed client auth methods for token endpoint

INCLUDE_NEW_REFRESH_TOKEN = True

The authorization server MAY issue a new refresh token

authenticate_refresh_token(refresh_token)[source]

Get token information with refresh_token string. Developers MUST implement this method in subclass:

def authenticate_refresh_token(self, refresh_token):
    token = Token.get(refresh_token=refresh_token)
    if token and not token.refresh_token_revoked:
        return token
Parameters:

refresh_token – The refresh token issued to the client

Returns:

token

revoke_old_credential(credential)[source]

The authorization server MAY revoke the old refresh token after issuing a new refresh token to the client. Developers MUST implement this method in subclass:

def revoke_old_credential(self, credential):
    credential.revoked = True
    credential.save()
Parameters:

credential – Token object

authenticate_user(credential)[source]

Authenticate the user related to this credential. Developers MUST implement this method in subclass:

def authenticate_user(self, credential):
    return User.query.get(credential.user_id)
Parameters:

credential – Token object

Returns:

user

class kadi.lib.oauth.core.RevocationEndpoint(server)[source]

Bases: RevocationEndpoint

OAuth2 token revocation endpoint.

CLIENT_AUTH_METHODS = ['client_secret_post']

Allowed client authenticate methods

query_token(token_string, token_type_hint)[source]

Get the token from database/storage by the given token string. Developers should implement this method:

def query_token(self, token_string, token_type_hint):
    if token_type_hint == 'access_token':
        return Token.query_by_access_token(token_string)
    if token_type_hint == 'refresh_token':
        return Token.query_by_refresh_token(token_string)
    return Token.query_by_access_token(token_string) or                     Token.query_by_refresh_token(token_string)
revoke_token(token, request)[source]

Mark token as revoked. Since token MUST be unique, it would be dangerous to delete it. Consider this situation:

  1. Jane obtained a token XYZ

  2. Jane revoked (deleted) token XYZ

  3. Bob generated a new token XYZ

  4. Jane can use XYZ to access Bob’s resource

It would be secure to mark a token as revoked:

def revoke_token(self, token, request):
    hint = request.form.get('token_type_hint')
    if hint == 'access_token':
        token.access_token_revoked = True
    else:
        token.access_token_revoked = True
        token.refresh_token_revoked = True
    token.save()
kadi.lib.oauth.core.create_oauth2_client_token(*, name, access_token, refresh_token=None, user=None, expires_at=None, expires_in=None)[source]

Create a new OAuth2 client token.

Parameters:
  • name – See OAuth2ClientToken.name.

  • access_token – See OAuth2ClientToken.access_token.

  • refresh_token – (optional) See OAuth2ClientToken.refresh_token.

  • user – (optional) The user the client token should belong to. Defaults to the current user.

  • expires_at – (optional) The expiration date and time of the access token as a Unix timestamp. Will be prioritized if expires_in is also given.

  • expires_in – (optional) The lifetime of the access token in seconds.

Returns:

The created OAuth2 client token.

kadi.lib.oauth.core.update_oauth2_client_token(oauth2_client_token, expires_at=None, expires_in=None, **kwargs)[source]

Update an existing OAuth2 client token.

Parameters:
class kadi.lib.oauth.models.OAuth2ClientToken(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model to represent OAuth2 client tokens.

Note that this model uses encrypted fields and can potentially raise a KadiDecryptionKeyError when a value cannot be decrypted.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'name']

See SimpleReprMixin.

id

The ID of the client token, auto incremented.

user_id

The ID of the user the client token belongs to.

name

The name of the client token.

Currently always refers to the name of a specific OAuth2 provider.

access_token

The actual access token value, stored encrypted.

refresh_token

The optional refresh token value, stored encrypted.

expires_at

The optional expiration date and time of the access token.

property is_expired

Check if the access token is expired.

classmethod create(*, user, name, access_token, refresh_token=None, expires_at=None)[source]

Create a new OAuth2 client token and add it to the database session.

Parameters:
  • user – The user the client token should belong to.

  • name – The name of the client token.

  • access_token – The actual access token value.

  • refresh_token – (optional) The refresh token value.

  • expires_at – (optional) The expiration date and time of the access token.

Returns:

The new OAuth2ClientToken object.

to_authlib_token()[source]

Convert the client token to a format usable by an Authlib client.

Returns:

A dictionary representation of the client token.

class kadi.lib.oauth.models.OAuth2ServerClient(**kwargs)[source]

Bases: SimpleReprMixin, SimpleTimestampMixin, OAuth2ClientMixin, Model

Model to represent registered OAuth2 clients/applications.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'client_id', 'client_name']

See SimpleReprMixin.

id

The ID of the client, auto incremented.

user_id

The ID of the user who created the client.

client_id

The OAuth2 client ID.

client_secret

The OAuth2 client secret.

Note that only a hash of the actual client secret value is stored.

property client_metadata

Get the additional metadata of this client.

property scope

Get the scope of this client.

static new_client_secret()[source]

Create a new random client secret.

Returns:

The generated client secret.

static hash_client_secret(client_secret)[source]

Create a secure hash of a client secret.

Parameters:

client_secret – The client secret to hash.

Returns:

The calculated hash as a hexadecimal value.

classmethod create(*, user, client_name, client_uri, redirect_uris, scope=None, client_secret=None)[source]

Create a new OAuth2 client and add it to the database session.

Parameters:
  • user – The user the client should belong to.

  • client_name – The name of the client. Will be stored as part of the client metadata.

  • client_uri – The website of the client. Will be stored as part of the client metadata.

  • redirect_uris – A list of allowed redirect URIs. Will be stored as part of the client metadata.

  • scope – (optional) The scope of the client as a single string defining a list of space-delimited scope values. Will be stored as part of the client metadata.

  • client_secret – (optional) The client secret, which will be hashed before persisting. Defaults to a client secret created by new_client_secret().

Returns:

The new OAuth2ServerClient object.

set_client_metadata(value)[source]

Set the additional metadata of this client.

Parameters:

value – The metadata as a JSON serializable dictionary.

update_client_metadata(**kwargs)[source]

Update the additional metadata of this client.

Parameters:

**kwargs – JSON serializable keyword arguments to update the metadata with.

check_client_secret(client_secret)[source]

Compare the client secret of this client with a given client secret.

Parameters:

client_secret – The client secret to compare with, which will be hashed before comparing.

client_id_issued_at
client_secret_expires_at
created_at

The date and time an object has been created at.

Always uses the current UTC time.

last_modified

The date and time an object was last modified.

Always uses the current UTC time as initial value. After calling register_timestamp_listener() for an inheriting mixin class, this timestamp can automatically get updated by implementing “_before_flush_timestamp” as a class method.

class kadi.lib.oauth.models.OAuth2ServerToken(**kwargs)[source]

Bases: SimpleReprMixin, AccessTokenMixin, OAuth2TokenMixin, Model

Model to represent OAuth2 server tokens.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'client_id']

See SimpleReprMixin.

id

The ID of the server token, auto incremented.

client_id

The client ID of the client the server token belongs to.

access_token

The actual access token value.

Note that only a hash of the actual access token value is stored.

refresh_token

The actual refresh token value.

Note that only a hash of the actual refresh token value is stored.

property is_expired

Check if the access token is expired.

access_token_revoked_at
expires_in
issued_at
static new_access_token(include_prefix=True)[source]

Create a new random access token value.

Parameters:

include_prefix – (optional) Whether to include a prefix before the actual access token value to distinguish it with other types of access tokens.

Returns:

The generated access token value.

refresh_token_revoked_at
scope

The optional scope of the access token.

Represented as a single string defining a list of space-delimited scope values.

token_type
user

The user relationship of the access token.

A corresponding relationship should also be defined in the user table.

user_id

The ID of the user the access token belongs to.

static new_refresh_token()[source]

Create a new random refresh token value.

Returns:

The generated refresh token value.

static hash_token(token)[source]

Create a secure hash of an access or refresh token value.

Parameters:

token – The token value to hash.

Returns:

The calculated hash as a hexadecimal value.

classmethod get_by_access_token(token)[source]

Get a server token using an access token value.

Parameters:

token – The access token value to search for.

Returns:

The server token or None.

classmethod get_by_refresh_token(token)[source]

Get a server token using a refresh token value.

Parameters:

token – The refresh token value to search for.

Returns:

The server token or None.

classmethod create(*, user, client, expires_in, access_token=None, refresh_token=None, scope=None)[source]

Create a new OAuth2 server token and add it to the database session.

Parameters:
  • user – The user the server token should belong to.

  • client – The client the server token should belong to.

  • expires_in – The expiration time of the access token in seconds.

  • access_token – (optional) The actual access token value, which will be hashed before persisting. Defaults to an access token value created by new_access_token().

  • refresh_token – (optional) The actual refresh token value, which will be hashed before persisting. Defaults to a refresh token value created by new_refresh_token().

  • scope – (optional) The scope of the server token.

Returns:

The new OAuth2ServerToken object.

class kadi.lib.oauth.models.OAuth2ServerAuthCode(**kwargs)[source]

Bases: SimpleReprMixin, OAuth2AuthorizationCodeMixin, Model

Model to represent OAuth2 authorization codes.

Required for the implementation of the OAuth2 authorization code grant.

auth_time
code
code_challenge
code_challenge_method
nonce
redirect_uri
response_type
class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'client_id']

See SimpleReprMixin.

id

The ID of the authorization code, auto incremented.

user_id

The ID of the user the authorization code belongs to.

client_id

The client ID of the client the authorization code belongs to.

scope

The optional scope of the authorization code.

classmethod create(*, user, client, code, redirect_uri, scope=None, code_challenge=None, code_challenge_method=None)[source]

Create a new OAuth2 authorization code and add it to the database session.

Parameters:
  • user – The user the authorization code should belong to.

  • client – The client the authorization code should belong to.

  • code – The actual authorization code value.

  • redirect_uri – The allowed redirect URI of the authorization code.

  • scope – (optional) The scope of the authorization code.

  • code_challenge – (optional) The code challenge of the authorization code used for PKCE.

  • code_challenge_method – (optional) The code challenge method of the authorization code used for PKCE.

Returns:

The new OAuth2ServerAuthCode object.

is_expired()[source]

Check if the authorization code is expired.

Returns:

True if the authorization code is expired, False otherwise.

class kadi.lib.oauth.schemas.OAuth2ServerClientSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent OAuth2 clients.

See OAuth2ServerClient.

class kadi.lib.oauth.schemas.OAuth2ServerTokenSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent OAuth2 server tokens.

See also OAuth2ServerToken.

kadi.lib.oauth.utils.get_oauth2_client_token(name, user=None, refresh=False)[source]

Get an OAuth2 client token of a user by its name.

Note that if either the access token or refresh token cannot be decrypted or if refresh is True while the access token is expired and cannot be refreshed, the client token will be deleted automatically.

Note that this function may issue a database commit.

Parameters:
  • name – The name of the client token.

  • user – (optional) The user the client token belongs to. Defaults to the current user.

  • refresh – (optional) Flag indicating whether the underlying access token should be refreshed if it is expired. This requires that the OAuth2 provider used to create the token is registered with the application and that a valid refresh token is stored as well.

Returns:

The OAuth2 client token or None if no client token could be retrieved or refreshed.

kadi.lib.oauth.utils.has_oauth2_providers()[source]

Check if at least one OAuth2 provider is registered.

Uses the kadi.plugins.spec.kadi_get_oauth2_providers() plugin hook to check for potential OAuth2 providers.

Returns:

True if at least one OAuth2 provider is registered, False otherwise.

kadi.lib.oauth.utils.get_oauth2_providers(user=None)[source]

Get a list of registered OAuth2 providers.

Uses the kadi.plugins.spec.kadi_get_oauth2_providers() plugin hook to collect potential OAuth2 providers.

Note that this function may issue one or more database commits.

Parameters:

user – (optional) The user who should be checked for whether they are connected with an OAuth2 provider, in which case "is_connected" will be set to True for the respective provider. Defaults to the current user.

Returns:

A list of provider dictionaries in the following form, sorted by whether the provider is connected first and the name of the provider second:

[
    {
        "name": "example",
        "title": "Example provider",
        "website": "https://example.com",
        "description": "An example OAuth2 provider.",
        "is_connected": True,
    },
]

kadi.lib.oauth.utils.get_oauth2_provider(provider, user=None)[source]

Get a specific, registered OAuth2 provider.

Note that this function may issue one or more database commits.

Parameters:
Returns:

The publication provider in a format as described in get_oauth2_providers() or None if no provider with the given name could be found.

kadi.lib.oauth.utils.new_oauth2_access_token(*args, include_prefix=True, **kwargs)[source]

Create a new random access token value for use in OAuth2 server tokens.

Parameters:

include_prefix – (optional) Whether to include a prefix before the actual access token value to distinguish it with other types of access tokens.

Returns:

The generated access token value.

kadi.lib.oauth.utils.new_oauth2_refresh_token(*args, **kwargs)[source]

Create a new random refresh token value for use in OAuth2 server tokens.

Returns:

The generated refresh token value.

kadi.lib.oauth.utils.clean_auth_codes(inside_task=False)[source]

Clean all expired OAuth2 authorization codes.

Note that this function issues a database commit.

Parameters:

inside_task – (optional) A flag indicating whether the function is executed in a task. In that case, additional information will be logged.

Permissions

kadi.lib.permissions.core.has_permission(subject, action, object_name, object_id, check_groups=True, check_defaults=True)[source]

Check if a user or group has permission to perform a specific action.

Checks all permissions grouped by the roles of the given subject.

Parameters:
  • subject – The User or Group.

  • action – The action to check for.

  • object_name – The type of object.

  • object_id – The ID of a specific object or None for a global permission.

  • check_groups – (optional) Flag indicating whether the groups of a user should be checked as well for their permissions.

  • check_defaults – (optional) Flag indicating whether the default permissions of any object should be checked as well.

Returns:

True if permission is granted, False otherwise or if the object instance to check does not exist.

kadi.lib.permissions.core.get_permitted_objects(subject, action, object_name, check_groups=True, check_defaults=True)[source]

Get all objects a user or group has a specific permission for.

Checks all permissions grouped by the roles of the given subject.

Parameters:
  • subject – The User or Group.

  • action – The action to check for.

  • object_name – The type of object.

  • check_groups – (optional) Flag indicating whether the groups of a user should be checked as well for their permissions.

  • check_defaults – (optional) Flag indicating whether the default permissions of the objects should be checked as well.

Returns:

The permitted objects as query or None if the object type does not exist.

kadi.lib.permissions.core.add_role(subject, object_name, object_id, role_name, update_timestamp=True)[source]

Add an existing role to a user or group.

Parameters:
  • subject – The User or Group.

  • object_name – The type of object the role refers to.

  • object_id – The ID of the object.

  • role_name – The name of the role.

  • update_timestamp – (optional) Flag indicating whether the timestamp of the underlying object should be updated or not. The object needs to implement BaseTimestampMixin in that case.

Returns:

True if the role was added successfully, False if the subject already has a role related to the given object.

Raises:

ValueError – If no object or role with the given arguments exists or when trying to add a role to the object that is being referred to by that role.

kadi.lib.permissions.core.remove_role(subject, object_name, object_id, update_timestamp=True)[source]

Remove an existing role of a user or group.

Parameters:
  • subject – The User or Group.

  • object_name – The type of object the role refers to.

  • object_id – The ID of the object.

  • update_timestamp – (optional) Flag indicating whether the timestamp of the underlying object should be updated or not. The object needs to implement BaseTimestampMixin in that case.

Returns:

True if the role was removed successfully, False if there was no role to remove.

Raises:

ValueError – If no object with the given arguments exists.

kadi.lib.permissions.core.set_system_role(user, system_role)[source]

Set an existing system role for a given user.

Parameters:
  • user – The user to set the system role for.

  • system_role – The name of the system role to set as defined in kadi.lib.constants.SYSTEM_ROLES.

Returns:

True if the system role was set successfully, False otherwise or if the given system role does not exist.

kadi.lib.permissions.core.setup_permissions(object_name, object_id)[source]

Setup the default permissions of an object.

The default actions and roles have to be specified in a Meta.permissions attribute in each model.

Example:

class Foo:
    class Meta:
        permissions = {
            "actions": [
                ("read", "Read this object."),
                ("update", "Edit this object."),
            ],
            "roles": [("admin", ["read", "update"])],
        }
Parameters:
  • object_name – The type of object the permissions refer to.

  • object_id – The ID of the object.

Raises:

ValueError – If no object with the given arguments exists.

kadi.lib.permissions.core.delete_permissions(object_name, object_id)[source]

Delete all permissions of an object.

Parameters:
  • object_name – The type of object the permissions refer to.

  • object_id – The ID of the object.

kadi.lib.permissions.core.create_role_rule(object_name, object_id, role_name, rule_type, condition, update_timestamp=True)[source]

Create a new role rule.

Parameters:
  • object_name – The type of object the role refers to.

  • object_id – The ID of the object.

  • role_name – The name of the role.

  • rule_type – The type of the role rule.

  • condition – The condition of the role rule.

  • update_timestamp – (optional) Flag indicating whether the timestamp of the underlying object should be updated or not. The object needs to implement BaseTimestampMixin in that case.

Returns:

The created role rule or None if the role rule could not be created.

kadi.lib.permissions.core.remove_role_rule(role_rule, update_timestamp=True)[source]

Remove an existing role rule.

Parameters:
  • role_role – The role rule to remove.

  • update_timestamp – (optional) Flag indicating whether the timestamp of the underlying object should be updated or not. The object needs to implement BaseTimestampMixin in that case.

kadi.lib.permissions.core.apply_role_rule(role_rule, user=None)[source]

Apply a given role rule.

Parameters:
  • role_rule – The role rule to apply.

  • user – (optional) A specific user to apply the role rule to. If not given, all existing users are considered.

class kadi.lib.permissions.models.Permission(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model representing fine-grained permissions.

Each permission is associated with a specific type of object, a related action and optionally an ID referring to a specific object instance.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'action', 'object', 'object_id']

See SimpleReprMixin.

id

The ID of the permission, auto incremented.

action

The action the permission refers to with respect to its object type.

object

The type of object the permission refers to.

Currently always refers to a specific model, in which case the object type is equal to that model’s table name.

object_id

The ID of an object the permission refers to.

If not set, the permission counts for all object instances of its type.

classmethod create(*, action, object, object_id=None)[source]

Create a new permission and add it to the database session.

Parameters:
  • action – The action the permission refers to.

  • object – The object the permission refers to.

  • object_id – (optional) The ID of an object.

Returns:

The new Permission object.

class kadi.lib.permissions.models.Role(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model representing roles.

A role is a grouping of multiple permissions. There are two kinds of roles specified through this model:

  • Roles belonging to a specific object instance. Both its object and object_id are set in this case and all permissions that belong to this role have to refer to the same object instance.

  • Global system roles. Both the object and object_id are not set in this case and the permissions that belong to this role can refer to multiple object types and instances (usually to all instances of a specific object type).

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'name', 'object', 'object_id']

See SimpleReprMixin.

id

The ID of the role, auto incremented.

name

The name of the role.

object

The type of object the role refers to.

Currently always refers to a specific model, in which case the object type is equal to that model’s table name. If not set, object_id has to be None as well.

object_id

The ID of an object the role refers to.

If not set, the object has to be None as well.

classmethod create(*, name, object=None, object_id=None)[source]

Create a new role and add it to the database session.

Parameters:
  • name – The name of the role.

  • object – (optional) The object the role refers to.

  • object_id – (optional) The ID of an object.

Returns:

The new Role object.

class kadi.lib.permissions.models.RoleRuleType[source]

Bases: StringEnum

String enum containing all possible type values for role rules.

class kadi.lib.permissions.models.RoleRule(**kwargs)[source]

Bases: SimpleReprMixin, SimpleTimestampMixin, Model

Model to represent role rules.

Role rules can be used to automate permission management by automatically granting users or groups roles for different resources based on different conditions.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'role_id', 'type', 'condition']

See SimpleReprMixin.

created_at

The date and time an object has been created at.

Always uses the current UTC time.

last_modified

The date and time an object was last modified.

Always uses the current UTC time as initial value. After calling register_timestamp_listener() for an inheriting mixin class, this timestamp can automatically get updated by implementing “_before_flush_timestamp” as a class method.

id

The ID of the role rule, auto incremented.

role_id

The ID of the role the role rule refers to.

type

The type of the role rule.

Currently only "username".

condition

The condition of the role rule, depending on its type.

For each of the role rule types, the data consists of:

  • "username": An object containing the type of a user’s identity and a pattern to check the corresponding username with.

classmethod create(*, role, type, condition)[source]

Create a new role rule and add it to the database session.

Parameters:
  • role – The role the role rule refers to.

  • type – The type of the role rule.

  • condition – The condition of the role rule.

Returns:

The new RoleRule object.

class kadi.lib.permissions.schemas.PermissionSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent permissions.

See Permission.

class kadi.lib.permissions.schemas.RoleSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent roles.

See Role.

class kadi.lib.permissions.schemas.RoleRuleSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent role rules.

See RoleRule.

class kadi.lib.permissions.schemas.UserRoleSchema(obj=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent user roles.

Parameters:

obj – (optional) An object that the current user role refers to.

dump_from_iterable(iterable)[source]

Serialize an iterable containing user roles.

Parameters:

iterable – An iterable yielding tuples each containing a user and a corresponding role.

Returns:

The serialized output.

class kadi.lib.permissions.schemas.GroupRoleSchema(obj=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent group roles.

Parameters:

obj – (optional) An object that the current group role refers to.

dump_from_iterable(iterable)[source]

Serialize an iterable containing group roles.

Parameters:

iterable – An iterable yielding tuples each containing a group and a corresponding role.

Returns:

The serialized output.

kadi.lib.permissions.tasks.start_apply_role_rules_task(role_rule=None, user=None)[source]

Apply a specific or all existing role rules in a background task.

Parameters:
  • role_rule – (optional) A specific role rule to apply.

  • user – (optional) A specific user to apply the role rule(s) to. If not given, all existing users are considered.

Returns:

True if the task was started successfully, False otherwise.

kadi.lib.permissions.utils.permission_required(action, object_name, object_id_identifier, status_code=403)[source]

Decorator to add access restrictions based on permissions to an endpoint.

If the current user is not authenticated, the decorator will behave the same as Flask-Login’s login_required decorator. If the object or object instance to check do not exist, the request will automatically get aborted with a 404 status code.

Uses kadi.lib.permissions.core.has_permission() to check for access permissions.

Parameters:
kadi.lib.permissions.utils.initialize_system_role(role_name)[source]

Initialize a system role with corresponding global permissions.

Will create the given system role as defined in kadi.lib.constants.SYSTEM_ROLES as well as all permissions for the global actions of the corresponding resources, which have to be specified in the Meta.permissions attribute in each corresponding model.

Example:

class Foo:
    class Meta:
        permissions = {
            "global_actions": [
                ("create", "Create objects."),
                ("read", "Read all objects."),
            ],
        }
Parameters:

role_name – The name of the system role to initialize.

Returns:

The created role object or None if the role already exists.

Raises:

ValueError – If the given role is not a valid system role or if any of the specified global actions is invalid.

kadi.lib.permissions.utils.get_user_roles(object_name, object_id=None)[source]

Get all users and roles for a specific object or object type.

Note that inactive users will be filtered out.

Parameters:
  • object_name – The type of the object.

  • object_id – (optional) The ID of a specific object.

Returns:

The users and corresponding roles of the object(s) as query.

kadi.lib.permissions.utils.get_group_roles(object_name, object_id=None)[source]

Get all groups and roles for a specific object or object type.

Note that inactive groups will be filtered out.

Parameters:
  • object_name – The type of the object.

  • object_id – (optional) The ID of a specific object.

Returns:

The groups and corresponding roles of the object(s) as query.

kadi.lib.permissions.utils.get_object_roles(object_name)[source]

Get all possible roles and corresponding permissions of an object type.

Parameters:

object_name – The type of the object.

Returns:

A list of dictionaries in the following form:

[
    {
        "name": "admin",
        "permissions": [
            {
                "action": "read,
                "description": "Read this resource.",
            }
        ]
    }
]

kadi.lib.permissions.utils.get_action_description(action, object_name)[source]

Get the description of an action corresponding to a specific permission.

Parameters:
  • action – The name of the action.

  • object_name – The type of the object the action belongs to.

Returns:

The description or None if no suitable action or no model corresponding to the object type could be found.

kadi.lib.permissions.utils.create_username_role_rule(object_name, object_id, role_name, identity_type, pattern)[source]

Create a role rule with conditions to check the values of usernames.

The conditions of username rules consist of an identity type (identity_type) and a pattern (pattern). The former specifies the type of identities to check the usernames of, while the letter specifies the possible values of the usernames. The pattern may include one or more wildcards using "*", which match a sequence of zero or more characters.

Parameters:
Returns:

See kadi.lib.permissions.core.create_role_rule().

kadi.lib.permissions.utils.get_role_rules(object_name, object_id, rule_type=None)[source]

Get all existing role rules corresponding to roles of a specific object.

Parameters:
  • object_name – The type of object the role rules refer to through their corresponding roles.

  • object_id – The ID of the object the role rules refer to through their corresponding roles.

  • rule_type – (optional) A type to limit the role rules with.

Returns:

The filtered role rules as query.

Publication

kadi.lib.publication.get_publication_providers(resource, user=None)[source]

Get a list of registered publication providers.

Uses the kadi.plugins.spec.kadi_get_publication_providers() plugin hook to collect potential publication providers combined with the information from kadi.lib.oauth.utils.get_oauth2_providers().

Note that this function may issue one or more database commits.

Parameters:
  • resource – The resource to eventually publish, an instance of Record or Collection.

  • user – (optional) The user who should be checked for whether they are connected with the OAuth2 provider the publication provider uses, in which case "is_connected" will be set to True for the respective provider. Defaults to the current user.

Returns:

A list of provider dictionaries in the following form, sorted by name:

[
    {
        "name": "example",
        "description": "An example publication provider.",
        "title": "Example provider",
        "website": "https://example.com",
        "is_connected": True,
    },
]

kadi.lib.publication.get_publication_provider(provider, resource, user=None)[source]

Get a specific, registered publication provider.

Note that this function may issue one or more database commits.

Parameters:
Returns:

The publication provider in a format as described in get_publication_providers() or None if no provider with the given name could be found.

kadi.lib.publication.publish_resource(provider, resource, form_data=None, user=None, task=None)[source]

Publish a resource using a given provider.

Uses the kadi.plugins.spec.kadi_publish_resource() plugin hook.

Note that this function issues one or more database commits.

Parameters:
  • provider – The unique name of the publication provider.

  • resource – The resource to publish, an instance of Record or Collection.

  • form_data – (optional) Form data as dictionary to customize the publication process.

  • user – (optional) The user who started the publication process. Defaults to the current user.

  • task – (optional) A Task object that that may be provided if this function is executed in a background task.

Returns:

A tuple consisting of a flag indicating whether the operation succeeded and a (HTML) template further describing the result in a user-readable manner, depending on the provider.

Resources

Convenience function to link two resources together.

For ease of use in API endpoints. Uses kadi.lib.resources.utils.add_link().

Note that this function may issue a database commit.

Parameters:
Returns:

A JSON response depending on the success of the operation.

Convenience function to remove the link between two resources.

For ease of use in API endpoints. Uses kadi.lib.resources.utils.remove_link().

Note that this function may issue a database commit.

Parameters:
Returns:

A JSON response depending on the success of the operation.

kadi.lib.resources.api.add_role(subject, resource, role_name, user=None)[source]

Convenience function to add an existing role to a user or group.

For ease of use in API endpoints. Uses kadi.lib.permissions.core.add_role().

Note that this function may issue a database commit.

Parameters:
Returns:

A JSON response depending on the success of the operation.

kadi.lib.resources.api.remove_role(subject, resource)[source]

Convenience function to remove an existing role of a user or group.

For ease of use in API endpoints. Uses kadi.lib.permissions.core.remove_role().

Note that this function may issue a database commit.

Parameters:
Returns:

A JSON response depending on the success of the operation.

kadi.lib.resources.api.change_role(subject, resource, role_name)[source]

Convenience function to change an existing role of a user or group.

For ease of use in API endpoints. If the given subject is the creator of the given resource, the role will not be changed. Uses kadi.lib.permissions.core.remove_role() and kadi.lib.permissions.core.add_role().

Note that this function may issue a database commit or rollback.

Parameters:
Returns:

A JSON response depending on the success of the operation.

kadi.lib.resources.api.toggle_favorite_resource(resource, user=None)[source]

Toggle the favorite state of a resource.

Uses toggle_favorite() with the type and ID of the given resource.

Note that this function issues a database commit.

Parameters:
  • resource – The resource whose favorite state should be toggled. An instance of Record, Collection, Template or Group.

  • user – (optional) The user the favorite resource belongs to. Defaults to the current user.

Returns:

A JSON response indicating the success of the operation.

kadi.lib.resources.api.get_selected_resources(model, page=1, filter_term='', exclude=None, actions=None, filters=None, user=None)[source]

Convenience function to search resources for use in dynamic selections.

For ease of use in API endpoints. Used in conjunction with “Select2” to search resources via dyamic selection fields. Only the resources the given user has read permission for are returned.

Parameters:
  • model – The resource model to search, one of Record, Collection, Template or Group.

  • page – (optional) The current page.

  • filter_term – (optional) A (case insensitive) term to filter the resources by their title or identifier.

  • exclude – (optional) A list of resource IDs to exclude in the results. Defaults to an empty list.

  • actions – (optional) Further actions to check the access permissions for.

  • filters – (optional) Additional filter expressions to apply to the respective resource query.

  • user – (optional) The user performing the search. Defaults to the current user.

Returns:

A JSON response containing the results in the following form, assuming the search results consist of a single Record:

{
    "results": [
        {
            "id": 1,
            "text": "@sample-record-1",
            "body": "<optional HTML body>",
        }
    ],
    "pagination": {"more": false},
}

kadi.lib.resources.api.get_resource_user_roles(resource, page=1, per_page=10, filter_term='', exclude=None)[source]

Get the paginated user roles of a resource.

Parameters:
  • resource – The resource to get the user roles of. An instance of Record, Collection, Template or Group.

  • page – (optional) The current page.

  • per_page – (optional) Items per page.

  • filter_term – (optional) A (case insensitive) term to filter the users by their username or display name.

  • exclude – (optional) A list of user IDs to exclude in the results.

Returns:

A tuple containing a list of deserialized user roles and the total amount of user roles.

kadi.lib.resources.api.get_resource_group_roles(resource, page=1, per_page=10, filter_term='', user=None)[source]

Get the paginated group roles of a resource.

This includes the special case of the given user not having read access to a group (any more) but wanting to change/remove permissions of the group, if the permissions of the user allow them to. Since such groups should still be listed, they are included using a limited subset of group attributes.

Parameters:
  • resource – The resource to get the group roles of. An instance of Record, Collection or Template.

  • page – (optional) The current page.

  • per_page – (optional) Items per page.

  • filter_term – (optional) A query to filter the groups by their title or identifier.

  • user – (optional) The user to check for any permissions regarding the resulting groups. Defaults to the current user.

Returns:

A tuple containing a list of deserialized group roles and the total amount of user roles.

kadi.lib.resources.api.get_internal_resource_export(resource, export_type, export_func, export_filter=None, preview=False, download=False)[source]

Get the exported data of a resource for direct preview or download.

Only used internally, as the preview functionality of exported data is only useful in a browser context.

Parameters:
  • resource – The resource to export. An instance of Record or Collection.

  • export_type – A valid export type for the resource as defined in kadi.lib.constants.EXPORT_TYPES.

  • export_func – The export function corresponding to the resource to export.

  • export_filter – (optional) A dictionary specifying various export filters, which is passed to the given export function.

  • preview – (optional) Whether the exported data should be sent directly to the browser for preview instead of returning a URL. Only relevant for certain export types.

  • download – (optional) Whether the exported data should be downloaded as an attachment instead of just previewed.

Returns:

The exported data as a corresponding response object, depending on the given arguments.

kadi.lib.resources.core.create_resource(model, tags=None, creator=None, **kwargs)[source]

Convenience function to create a new resource.

This will also create all default permissions of the resource.

Note that this function issues a database commit or rollback.

Parameters:
  • model – The model that represents the type of the new resource. One of Record, Collection, Template or Group.

  • tags – (optional) A list of tags to tag the resource with if it inherits from TaggingMixin.

  • creator – (optional) The creator of the resource. Defaults to the current user.

  • **kwargs – Keyword arguments that will be used to intialize the data of the new resource.

Returns:

The created resource or None if the resource could not be created.

kadi.lib.resources.core.update_resource(resource, tags=None, user=None, **kwargs)[source]

Convenience function to update an existing resource.

Note that this function may issue a database commit or rollback.

Parameters:
  • resource – The resource to update. An instance of Record, Collection, Template or Group.

  • tags – (optional) A list of tags to tag the resource with if it inherits from TaggingMixin.

  • user – (optional) The user who triggered the update. Defaults to the current user.

  • **kwargs – Keyword arguments that will be passed to kadi.lib.db.update_object().

Returns:

True if the resource was updated successfully, False otherwise.

kadi.lib.resources.core.delete_resource(resource, user=None)[source]

Convenience function to delete an existing resource.

This will perform a soft deletion, i.e. only the resource’s state will be changed.

Note that this function issues a database commit.

Parameters:
  • resource – The resource to delete. An instance of Record, Collection, Template or Group.

  • user – (optional) The user who triggered the deletion. Defaults to the current user.

kadi.lib.resources.core.restore_resource(resource, user=None)[source]

Convenience function to restore a deleted resource.

Note that this function issues a database commit.

Parameters:
  • resource – The resource to restore. An instance of Record, Collection, Template or Group.

  • user – (optional) The user who triggered the restoration. Defaults to the current user.

kadi.lib.resources.core.purge_resource(resource)[source]

Convenience function to purge an existing resource.

This will completely delete the resource from the database.

Note that this function issues a database commit.

Parameters:

resource – The resource to purge. An instance of Record, Collection, Template or Group.

class kadi.lib.resources.forms.TagsField(*args, **kwargs)[source]

Bases: DynamicMultiSelectField

Custom dynamic multi select field for tagging resources.

Tags must not be empty, are automatically converted to lowercase and whitespaces are stripped and normalized. Additionally, the result will be sorted and duplicate tags will be filtered out.

Parameters:

max_len – (optional) The maximum length of each tag.

process_formdata(valuelist)[source]

Process data received over the wire from a form.

This will be called during form construction with data supplied through the formdata argument.

Parameters:

valuelist – A list of strings to process.

class kadi.lib.resources.forms.RolesField(*args, **kwargs)[source]

Bases: JSONField

Custom field to process and validate user and group roles of resources.

The instance variable initial can be used to set initial values to prefill the field data with.

Parameters:

roles – A list of roles, each item consisting of another list containing the actual role value and title to be displayed, similar to the choices in select fields.

process_formdata(valuelist)[source]

Process data received over the wire from a form.

This will be called during form construction with data supplied through the formdata argument.

Parameters:

valuelist – A list of strings to process.

to_dict()[source]

Convert this field into a dictionary representation.

set_initial_data(data=None, resource=None, user=None, keep_user_roles=False)[source]

Set the initial data of this field.

Can be used to prefill the dynamic selections of this field’s corresponding widget in regards to users and groups.

Parameters:
  • data – (optional) The form data to use for prefilling. Defaults to the submitted data of the current field instance.

  • resource – (optional) An existing resource, which can be used to set the initial data instead of the given form data. One of Record, Collection or Template.

  • user – (optional) A user that will be used for checking various access permissions when setting the data. Defaults to the current user.

  • keep_user_roles – (optional) Flag indicating whether to keep any roles of the given user.

class kadi.lib.resources.schemas.BasicResourceSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent the basic attributes of resources.

Currently, these resources may refer to instances of Record, Collection, Template or Group.

class kadi.lib.resources.schemas.DeletedResourceSchema(*args, _internal=None, **kwargs)[source]

Bases: BasicResourceSchema

Schema to represent the basic attributes of deleted resources.

class kadi.lib.resources.schemas.ResourceRolesSchema(roles, **kwargs)[source]

Bases: KadiSchema

Schema to represent user and group roles of different resources.

Mainly useful in combination with kadi.lib.resources.views.update_roles().

Parameters:

roles – A list of valid role values.

kadi.lib.resources.tasks.start_publish_resource_task(provider, resource, form_data=None, user=None, force_locale=True)[source]

Publish a resource using a given provider in a background task.

The created task will be kept in the database and the user who started the task will get notified about its current status as well.

Note that this function issues one or more database commits.

Parameters:
  • provider – The unique name of the publication provider.

  • resource – The resource to publish. An instance of Record or Collection.

  • form_data – (optional) Form data as dictionary to customize the publication process.

  • user – (optional) The user who started the task. Defaults to the current user.

  • force_locale – (optional) Flag indicating whether the current locale as returned by kadi.lib.web.get_locale() should be used inside the task. If False, the default locale will be used instead.

Returns:

A tuple containing a flag whether a previous publishing task was already started by the given user (in which case no new task will be started) and either the new task object or None, depending on whether the task was started successfully.

kadi.lib.resources.utils.get_filtered_resources(model, visibility=None, user_ids=None, user=None)[source]

Convenience function to get filtered resources of a specific model.

Parameters:
  • model – The model to filter. One of Record, Collection, Template or Group.

  • visibility – (optional) A visibility value to filter the resources with.

  • user_ids – (optional) A list of user IDs to filter the creators of the resources with.

  • user – (optional) The user to check for any permissions regarding the filtered resources. Defaults to the current user.

Returns:

The filtered resources as query.

kadi.lib.resources.utils.search_resources(model, search_query=None, page=1, per_page=10, sort='_score', filter_ids=None, extra_es_query=None)[source]

Convenience function to query the search index of a specific model.

Uses SearchableMixin.search() for the given model.

Parameters:
  • model – The model to search. One of Record, Collection, Template or Group.

  • search_query – (optional) The search query string.

  • page – (optional) The current page.

  • per_page – (optional) The amount of search results per page.

  • sort – (optional) The name of a field to sort on. One of "_score", "last_modified", "-last_modified", "created_at", "-created_at", "title", "-title", "identifier" or "-identifier". Falls back to "-last_modified" if no search query is given.

  • filter_ids – (optional) A list of resource IDs to restrict the search results to.

  • extra_es_query – (optional) An additional Elasticsearch DSL query object to combine with the given search query, if applicable.

Returns:

A tuple containing a list of the search results and the total amount of hits.

Convenience function to link two resources together.

Note that only the link-permission of the given resource is checked.

Parameters:
  • relationship – The many-relationship to append the resource to.

  • resource – The resource to link. An instance of Record or Collection.

  • user – (optional) The user performing the link operation. Defaults to the current user.

Returns:

True if the link was established successfully, False if the link already exists.

Raises:

KadiPermissionError – If the user performing the operation does not have the necessary permissions.

Convenience function to remove the link between two resources.

Note that only the link-permission of the given resource is checked.

Parameters:
  • relationship – The many-relationship to remove the resource from.

  • resource – The resource to remove. An instance of Record or Collection.

  • user – (optional) The user performing the link operation. Defaults to the current user.

Returns:

True if the link was removed successfully, False if the link does not exist.

Raises:

KadiPermissionError – If the user performing the operation does not have the necessary permissions.

kadi.lib.resources.utils.get_linked_resources(model, relationship, actions=None, user=None)[source]

Convenience function to get all linked resources that a user can access.

In this context having access to a resource means having read permission for that resource.

Parameters:
  • model – The model of which to get the links from. One of Record or Collection.

  • relationship – The many-relationship that represents the linked resources to get.

  • actions – (optional) Further actions to check the access permissions for.

  • user – (optional) The user who will be checked for access permissions. Defaults to the current user.

Returns:

The resulting query of the linked resources.

kadi.lib.resources.utils.clean_resources(inside_task=False)[source]

Clean all expired, deleted resources.

Note that this function may issue one or more database commits.

Parameters:

inside_task – (optional) A flag indicating whether the function is executed in a task. In that case, additional information will be logged.

Convenience function to link multiple resources together.

For ease of use in view functions. Uses kadi.lib.resources.utils.add_link() but silently ignores any errors.

Parameters:
kadi.lib.resources.views.update_roles(resource, roles, user=None)[source]

Convenience function to update roles of users and groups.

For ease of use in view functions. Uses kadi.lib.permissions.core.remove_role() and kadi.lib.permissions.core.add_role(), but silently ignores any errors.

Parameters:
  • resource – The resource the roles refer to, an instance of Record, Collection, Template or Group.

  • roles – A list of dictionaries containing the type, ID and role name of each subject whose role should be updated, which needs to correspond to the structure of ResourceRolesSchema.

  • user – (optional) The user performing the operation. Defaults to the current user.

Revisions

kadi.lib.revisions.core.create_revision(obj, user=None)[source]

Create a new revision of an object.

If none of the revisioned values changed, no new revision will be created. See also kadi.lib.revisions.core.setup_revisions().

Note that this function acquires a lock on the given object.

Parameters:
  • obj – The object to create a new revision for.

  • user – (optional) The user who triggered the revision.

Returns:

True if a new revision was created, False otherwise.

kadi.lib.revisions.core.delete_revisions(obj)[source]

Delete all revisions of an object.

Parameters:

obj – The object to delete the revisions of.

kadi.lib.revisions.core.setup_revisions()[source]

Setup revisioning for all models that support it.

The columns to store revisions of have to be specified in a Meta.revision attribute in each model. It should be a list of strings specifying the attribute names.

Example:

class Foo:
    class Meta:
        revision = ["bar", "baz[foo, bar]"]

The columns can either be simple columns, like the first value in the list, or relationships like the second value. For the latter, all columns of the relationship that should be included in the revision need to be specified in square brackets, separated by commas.

For each model, a new model class for the revisions will be created automatically, linked to the original model class and to Revision. The class of the revisioned model will also be stored on each new revision model as model_class. Additionally, the revision model class will be stored on the original model as revision_class as well as a convenience property to retrieve the revisions in descending order of their timestamp as ordered_revisions.

class kadi.lib.revisions.models.Revision(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model to represent general revision metadata.

The actual revision models are created dynamically instead and linked to this model. See kadi.lib.revisions.core.setup_revisions().

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'timestamp']

See SimpleReprMixin.

id

The ID of the revision, auto incremented.

user_id

The optional ID of the user who triggered the revision.

May be omitted if there is no user that can clearly be associated with a certain revision, e.g. when automatically triggering a revision after deleting a resource that was referenced in the revisioned resource.

timestamp

The timestamp of the revision.

classmethod create(*, user=None)[source]

Create a new revision and add it to the database session.

Parameters:

user – (optional) The user who triggered the revision.

Returns:

The new Revision object.

class kadi.lib.revisions.schemas.RevisionSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent general revisions.

See Revision.

class kadi.lib.revisions.schemas.ObjectRevisionSchema(schema, compared_revision=None, api_endpoint=None, view_endpoint=None, endpoint_args=None, view_object_url=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent specific object revisions.

Parameters:
  • schema – The schema to represent the object revisions with.

  • compared_revision – (optional) Another revision object to compare the object revisions with. By default, the comparison always uses the previous object revision, if applicable.

  • api_endpoint – (optional) An API endpoint to retrieve the current object revision.

  • view_endpoint – (optional) An endpoint to view the current object revision. Only relevant for internal use.

  • endpoint_args – (optional) Additional keyword arguments to append to the API and/or view endpoints when building the corresponding URL.

  • view_object_url – (optional) A URL to view the actual object the current revision refers to. Only relevant for internal use.

kadi.lib.revisions.utils.get_revision_columns(model)[source]

Parse the list of revisioned columns for a specific model.

See also kadi.lib.revisions.core.setup_revisions().

Parameters:

model – The model to get the columns from.

Returns:

A tuple containing a list of the simple columns (i.e. no relationships) as string and a list of relationships. The second list itself is made up of tuples consisting of the name of the relationship and a list of colums of the relationship to revision as strings, similar to the first list.

Schemas

class kadi.lib.schemas.KadiSchema(*args, _internal=None, **kwargs)[source]

Bases: Schema

Base class for all schemas.

Parameters:

_internal – (optional) Flag indicating whether additional data that’s only relevant for internal use should be included when serializing objects. If not set, the value returned by kadi.lib.api.utils.is_internal_api_request() will be taken instead. Note that this flag will generally not get passed automatically to any nested schemas.

load_or_400(data=None)[source]

Try to deserialize the given input.

Will try to deserialize/load the given input data using the schemas load method. If the validation fails, automatically abort the current request with status code 400 and a corresponding error response as JSON.

Parameters:

data – (optional) The input to deserialize. Defaults to the JSON body of the current request.

Returns:

The deserialized input.

class kadi.lib.schemas.FilteredString(*args, allow_ws_only=False, filters=None, **kwargs)[source]

Bases: String

Custom string field that allows for additional filtering and validation.

Parameters:
  • allow_ws_only – (optional) Flag indicating whether strings that are empty or only contain whitespace will be considered valid.

  • filters – (optional) A list of filter or conversion functions that will be applied when deserializing the field data.

class kadi.lib.schemas.SortedPluck(nested: SchemaABC | type | str | Callable[[], SchemaABC], field_name: str, **kwargs)[source]

Bases: Pluck

Pluck field that sorts its serialized output in case many is set.

class kadi.lib.schemas.ValidateUUID(version=4)[source]

Bases: object

Validate a UUID of a specific version in a schema field.

Parameters:

version – (optional) The UUID version.

kadi.lib.schemas.validate_identifier(value)[source]

Validate an identifier in a schema field.

Uses kadi.lib.validation.validate_identifier().

Parameters:

value – The field value.

kadi.lib.schemas.validate_mimetype(value)[source]

Validate a MIME type in a schema field.

Uses kadi.lib.validation.validate_mimetype().

Parameters:

value – The field value.

kadi.lib.schemas.validate_iri(value)[source]

Validate an IRI in a schema field.

Uses kadi.lib.validation.validate_iri().

Parameters:

value – The field value.

kadi.lib.schemas.check_duplicate_identifier(model, identifier, exclude=None)[source]

Check for a duplicate identifier in a schema.

Parameters:
  • model – The model class to check the identifier of.

  • identifier – The identifier to check.

  • exclude – (optional) An instance of the model that should be excluded in the check.

Search

class kadi.lib.search.core.MappingMixin[source]

Bases: object

Mixin for custom search mappings.

class Analyzers[source]

Bases: object

Container to store common analyzers.

classmethod get_attributes()[source]

Get a list of all attributes from a mapping class.

classmethod create_document(obj)[source]

Create a new document to be indexed in ElasticSearch

Parameters:

obj – The object to be indexed.

Returns:

The created document.

class kadi.lib.search.core.SearchableMixin[source]

Bases: object

Mixin for SQLALchemy models to add support for searching.

The columns to index have to be specified in a mapping class, which has to be configured with its fully qualified name using Meta.search_mapping.

Example:

class Foo:
    class Meta:
        search_mapping = "kadi.modules.record.mapping.RecordMapping"

After calling register_search_listeners(), the search index will automatically get updated whenever an object is created or deleted or if any of the indexed columns (or the state column, if present) are updated using add_to_index() and remove_from_index().

classmethod get_mapping_class()[source]

Convenience method to get the mapping class of a model.

classmethod search(query=None, sort='_score', filter_ids=None, start=0, end=10)[source]

Query the search index corresponding to this model.

Uses search_index(), but returns the actual results instead of the raw search response.

Parameters:
Returns:

A tuple containing a list of the search results and the total amount of hits.

Raises:

elasticsearch.exceptions.ConnectionError – If no connection could be established to Elasticsearch.

classmethod register_search_listeners()[source]

Register listeners to automatically update the search index.

Uses SQLAlchemy’s before_flush, after_commit and after_rollback events and propagates to all inheriting models.

kadi.lib.search.core.create_index(model, force=False)[source]

Create a new search index if it does not exist yet.

The name of the index will be in the form of "<tablename>_<timestamp>", where <tablename> depends on the given model. An alias <tablename> pointing to the actual index will also be created automatically if it does not exist yet.

Parameters:
  • model – The model to create the index of. See also SearchableMixin.

  • force – (optional) Flag indicating whether a new index should be created even if one already exists. Note that if an alias already exists it will not be updated automatically to point to the new index.

Returns:

The name of the newly created or existing index or None if no new index could be created.

kadi.lib.search.core.add_to_index(obj, index=None)[source]

Add an object to its corresponding search index.

Parameters:
  • obj – The object to index. See also SearchableMixin.

  • index – (optional) The name of an index that should be used instead of the alias corresponding to the given object. See also create_index().

Returns:

True if the object was indexed successfully, False otherwise.

kadi.lib.search.core.remove_from_index(obj, index=None)[source]

Remove an object from its corresponding search index.

Parameters:
  • obj – The object to remove from the index. See also SearchableMixin.

  • index – (optional) The name of an index that should be used instead of the alias corresponding to the given object. See also create_index().

Returns:

True if the object was removed successfully, False otherwise.

kadi.lib.search.core.search_index(index, query=None, sort='_score', filter_ids=None, start=0, end=10)[source]

Query a specific search index.

Parameters:
  • index – The name of the search index.

  • query – (optional) The search query in form of an Elasticsearch DSL query object.

  • sort – (optional) The name of a field or a list of multiple fields to sort on.

  • filter_ids – (optional) A list of IDs to restrict the search results to.

  • start – (optional) The start index of the results to return.

  • end – (optional) The end index of the results to return.

Returns:

A response object as returned by the Elasticsearch DSL or None if the request returned an error. Note that only the metadata will be returned as part of the search results, without any field data.

Raises:

elasticsearch.exceptions.ConnectionError – If no connection could be established to Elasticsearch.

class kadi.lib.search.elasticsearch.Elasticsearch(app=None)[source]

Bases: object

Elasticsearch client for use in a Flask application.

Wraps the official client for ease of use in a Flask application. Requires an application context, as it uses the application’s configuration value ELASTICSEARCH_HOSTS to specifiy one or more Elasticsearch nodes to connect to and optionally ELASTICSEARCH_CONFIG for any further configuration.

Parameters:

app – (optional) The application object.

init_app(app)[source]

Initialize the application’s configuration.

Will initialize ELASTICSEARCH_HOSTS to "http://localhost:9200", ELASTICSEARCH_CONFIG to {} and ELASTICSEARCH_ENABLE_FALLBACK to False in the application’s configuration by default.

Parameters:

app – The application object.

class kadi.lib.search.models.SavedSearch(**kwargs)[source]

Bases: SimpleReprMixin, SimpleTimestampMixin, Model

Model representing saved searches.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'name', 'object']

See SimpleReprMixin.

check_constraints = {'name': {'length': {'max': 150}}, 'query_string': {'length': {'max': 4096}}}

See kadi.lib.db.generate_check_constraints().

id

The ID of the saved search, auto incremented.

user_id

The ID of the user the saved search belongs to.

name

The name of the saved search.

Restricted to a maximum length of 150 characters.

created_at

The date and time an object has been created at.

Always uses the current UTC time.

last_modified

The date and time an object was last modified.

Always uses the current UTC time as initial value. After calling register_timestamp_listener() for an inheriting mixin class, this timestamp can automatically get updated by implementing “_before_flush_timestamp” as a class method.

object

The type of object the saved search refers to.

Currently always refers to a specific searchable model via its table name.

query_string

The query string representing the saved search.

This simply corresponds to the raw URL query parameter string used when searching the corresponding object. May be stored with or without a leading question mark.

Restricted to a maximum length of 4096 characters.

property qparams

Get a dictionary representation of the query string of this saved search.

Corresponds to the results of Python’s urllib.parse.parse_qs.

classmethod create(*, user, name, object, query_string)[source]

Create a new saved search and add it to the database session.

Parameters:
  • user – The user the saved search belongs to.

  • name – The name of the saved search.

  • object – The object the saved search refers to.

  • query_string – The query string of the saved search.

Returns:

The new SavedSearch object.

class kadi.lib.search.schemas.SavedSearchSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent saved searches.

See SavedSearch.

Security

kadi.lib.security.random_alnum(num_chars=16)[source]

Generate a secure random alphanumeric string.

Parameters:

num_chars – (optional) The number of chars to generate.

Returns:

The generated string.

kadi.lib.security.random_bytes(num_bytes=24, hexadecimal=True)[source]

Generate a secure random byte sequence.

Parameters:
  • length – (optional) The number of bytes to generate.

  • hexadecimal – (optional) Whether to return the bytes in a hexadecimal string representation.

Returns:

The generated byte sequence or hexadecimal string.

kadi.lib.security.hash_value(value, alg='sha256', hexadecimal=True)[source]

Create a secure hash of a value.

Parameters:
  • value – The value to hash, either a bytes-like object or a string.

  • alg – (optional) The hash algorithm to use, according to the algorithms available in Python’s “hashlib” module.

  • hexadecimal – (optional) Whether to return the hash in a hexadecimal string representation.

Returns:

The calculated hash as a byte sequence or hexadecimal string or None if the given algorithm is not available.

kadi.lib.security.encode_jwt(payload, expires_in=None)[source]

Encode a given payload inside a JSON web token.

Parameters:
  • payload – The payload to encode as dictionary, which needs to be JSON serializable.

  • expires_in – (optional) The time in seconds that the token should expire in.

Returns:

The encoded token as string.

kadi.lib.security.decode_jwt(token)[source]

Decode a given JSON web token.

Parameters:

token – The token to decode as string.

Returns:

The decoded payload dictionary or None if the token is invalid or expired.

Storage

class kadi.lib.storage.core.BaseStorage(storage_type, storage_name=None, max_size=None)[source]

Bases: ABC

Base class for all storage providers.

Parameters:
  • storage_type – The unique type of the storage.

  • storage_name – (optional) A user-readable name of the storage. Defaults to the given storage type.

  • max_size – (optional) The maximum file size for the storage to accept when saving files.

kadi.lib.storage.core.get_storages()[source]

Get all registered storages.

Returns:

The storages.

kadi.lib.storage.core.get_storage(storage_type)[source]

Get a registered storage for a given storage type.

Parameters:

storage_type – The storage type.

Returns:

The storage or None if no storage could be found.

class kadi.lib.storage.local.LocalStorage(root_directory, max_size=None, buffer_size=1048576, dir_len=2, num_dirs=3)[source]

Bases: BaseStorage

Storage provider that uses the local file system.

Parameters:
  • root_directory – The directory the storage operates in. The path must be an absolute path.

  • max_size – (optional) See BaseStorage.

  • buffer_size – (optional) The buffer size in bytes to use in memory when reading files.

  • dir_len – (optional) Length of each directory for file paths generated via create_filepath().

  • num_dirs – (optional) Number of directories for file paths generated via create_filepath().

Raises:

ValueError – If the given root directory is not an absolute path.

static filepath_from_name(filename, dir_len=2, num_dirs=3)[source]

Create a path from a filename.

Splits up a filename such as "abcdefg" into the file path "ab/cd/ef/g", assuming default argument values. The generated paths are useful to e.g. avoid storing lots of files in the same directory.

Parameters:
  • filename – The name of the file.

  • dir_len – (optional) Length of each directory.

  • num_dirs – (optional) Number of directories.

Returns:

The file path or None if the length of the given filename is smaller than or equals dir_len * num_dirs.

property root_directory

Get the root directory.

exists(filepath)[source]

Check if a file exists.

Parameters:

filepath – The local storage path of the file.

Returns:

True if the file exists, False otherwise.

open(filepath, mode='rb', encoding=None)[source]

Open a file in a specific mode.

Parameters:
  • filepath – The local storage path of the file.

  • mode – (optional) The file mode to open the file with.

  • encoding – (optional) The encoding of the file to use in text mode.

Returns:

The open file object.

close(file)[source]

Close an open file.

Parameters:

file – The file to close.

save(dst, file_or_src, append=False)[source]

Save a file or file-like object in a specific location.

Parameters:
  • dst – The local destination storage path of the new file.

  • file_or_src – A file-like object or binary stream to save or the name of an existing file to copy instead.

  • append – (optional) Flag to indicate if an existing file should be overwritten (default) or appended to.

Raises:

KadiFilesizeExceededError – If the maximum file size the storage was configured with would be exceeded when saving the file.

move(src, dst)[source]

Move a file to a specific location.

Files can only be moved within this storage.

Parameters:
  • src – The local source storage path of the file.

  • dst – The local destination storage path of the file.

Raises:

KadiFilesizeExceededError – If the maximum file size the storage was configured with would be exceeded when moving the file.

delete(filepath)[source]

Delete a file if it exists.

Will also remove all empty parent directories of the file, even if it does not exist, up to the root directory of the storage.

Parameters:

filepath – The local storage path of the file.

ensure_filepath_exists(filepath)[source]

Ensures that the directory structure in the path exists.

If the path is non existent, the complete structure is created.

Parameters:

filepath – The local storage path of the file.

get_mimetype(filepath)[source]

Get the MIME type of a file.

Will determine the MIME type based on the given file’s content.

Parameters:

filepath – The local storage path of the file.

Returns:

The MIME type of the file.

get_size(filepath)[source]

Get the size of a file.

Parameters:

filepath – The local storage path of the file.

Returns:

The size of the file in bytes.

validate_size(filepath, size, op='==')[source]

Validate the size of a file.

Parameters:
  • filepath – The local storage path of the file.

  • size – The size to compare the file with.

  • op – (optional) The operator to use for comparison. See op in kadi.lib.utils.compare() for possible values.

Raises:

KadiFilesizeMismatchError – If the validation failed.

get_checksum(filepath)[source]

Get the MD5 checksum of a file.

Parameters:

filepath – The local storage path of the file.

Returns:

The MD5 checksum as string in hex representation.

validate_checksum(filepath, expected, actual=None)[source]

Validate the checksum of a file.

Parameters:
  • filepath – The local storage path of the file.

  • expected – The excepted checksum as string in hex representation.

  • actual – (Optional) The actual checksum calculated during the upload.

Raises:

KadiChecksumMismatchError – If the checksums did not match.

create_filepath(file_identifier)[source]

Create a path from a file identifier suitable for storing files.

Uses filepath_from_name() with the given file_identifier in combination with the specified dir_len and num_dirs of the storage.

Parameters:

file_identifier – An identifier of a file suitable for an actual file name. This should generally be a unique, internal identifier related to the file, e.g. a UUIDv4 like in File.id.

Returns:

The created file path or None if the given file identifier is too short.

kadi.lib.storage.local.create_default_local_storage(root_directory=None, max_size=None)[source]

Create a default local storage.

Useful to create a general local storage with potentially different settings than the registered local storage obtained via kadi.lib.storage.core.get_storage(), as well as for cases where only local storages are relevant.

Parameters:
  • root_directory – (optional) Root directory of storage. If None, the STORAGE_PATH from the application’s configuration is used.

  • max_size – (optional) See BaseStorage.

Returns:

The storage.

kadi.lib.storage.local.create_chunk_storage()[source]

Create a local storage for storing uploaded chunks.

Returns:

The storage.

kadi.lib.storage.misc.create_misc_storage(max_size=None)[source]

Create a local storage that can be used for miscellaneous uploads.

Will use the local path set in MISC_UPLOADS_PATH in the application’s configuration as root directory for the storage and two directories of length 2 for all generated file paths via LocalStorage.create_filepath().

Parameters:

max_size – (optional) See BaseStorage.

Returns:

The storage.

kadi.lib.storage.misc.save_as_thumbnail(image_identifier, file_object, max_resolution=(512, 512))[source]

Save an image file as JPEG thumbnail.

Uses the local storage as returned by create_misc_storage() to store the thumbnails with a maximum size given by IMAGES_MAX_SIZE as defined in the application’s configuration.

Parameters:
  • image_identifier – An identifier of the image suitable for an actual file name using LocalStorage.create_filepath().

  • file_object – The binary image file object. The image must be of one of the image types specified in kadi.lib.constants.IMAGE_MIMETYPES.

  • max_resolution – (optional) The maximum resolution of the thumbnail in pixels.

Returns:

True if the thumbnail was saved successfully, False otherwise. Note that the original image file may be saved regardless of whether the thumbnail could be generated from it or not.

kadi.lib.storage.misc.delete_thumbnail(image_identifier)[source]

Delete a thumbnail.

This is the inverse operation of save_as_thumbnail().

Parameters:

image_identifier – See save_as_thumbnail().

Returns:

True if the thumbnail was deleted successfully, False otherwise.

class kadi.lib.storage.schemas.StorageSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent storages.

See BaseStorage.

Tags

class kadi.lib.tags.core.TaggingMixin[source]

Bases: object

Mixin for SQLALchemy models to add support for tagging.

The model needs a many-to-many tags relationship connecting itself with the Tag model.

set_tags(names)[source]

Set one or more tags.

Will create a new tag object for each tag name that does not yet exist in the database and add it to the relationship. Existing tags from the relationship that are not in the given list are removed.

Parameters:

names – A list of tag names.

Returns:

True if the tags were set successfully, False otherwise.

class kadi.lib.tags.models.Tag(**kwargs)[source]

Bases: SimpleReprMixin, Model

Model to represent tags.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'name']

See SimpleReprMixin.

check_constraints = {'name': {'length': {'max': 50}}}

See kadi.lib.db.generate_check_constraints().

id

The ID of the tag, auto incremented.

name

The unique name of the tag.

Restricted to a maximum length of 50 characters.

classmethod create(*, name)[source]

Create a new tag and add it to the database session.

Parameters:

name – The name of the tag.

Returns:

The new Tag object.

classmethod get_or_create(name)[source]

Return an existing tag or create one if it does not exist yet.

See create() for an explanation of the parameters.

Returns:

The new or existing Tag object.

class kadi.lib.tags.schemas.TagSchema(*args, _internal=None, **kwargs)[source]

Bases: KadiSchema

Schema to represent tags.

See Tag.

Tasks

kadi.lib.tasks.core.launch_task(name, args=(), kwargs=None, user=None, keep=False, notify=False, notification_data=None)[source]

Launch a new Celery task by name.

Note that this function issues one or more database commits if keep is True.

Parameters:
  • name – The name of the task.

  • args – (optional) Positional arguments to pass to the task as tuple. All arguments need to be JSON serializable.

  • kwargs – (optional) Keyword arguments to pass to the task as dictionary. All arguments need to be JSON serializable.

  • user – (optional) The user who started the task.

  • keep – (optional) Flag indicating whether the task should be kept in the database until their expiration date (via the periodic cleanup task). See also Task.

  • notify – (optional) Flag indicating whether the user who started the task should be notified about its status, in which case a new instance of Notification of type "task_status" will be created for that user. The data of this notification consists of a dictionary, containing the ID of the task as "task_id". This requires that a valid user is passed and keep must be True as well.

  • notification_data – (optional) Additional, JSON serializable data which is passed to the data dictionary of the Notification as "task_meta". Requires notify to be True. See also kadi.lib.notifications.core.create_notification_data().

Returns:

A boolean indicating whether the task was launched successfully or not if keep is False. A new Task object or None if keep is True.

class kadi.lib.tasks.models.TaskState[source]

Bases: StringEnum

String enum containing all possible state values for tasks.

class kadi.lib.tasks.models.Task(**kwargs)[source]

Bases: SimpleReprMixin, SimpleTimestampMixin, Model

Model to represent tasks.

class Meta[source]

Bases: object

Container to store meta class attributes.

representation = ['id', 'user_id', 'name', 'state']

See SimpleReprMixin.

check_constraints = {'progress': {'range': {'max': 100, 'min': 0}}, 'state': {'values': ['pending', 'running', 'revoked', 'success', 'failure']}}

See kadi.lib.db.generate_check_constraints().

id

The ID of the task, auto incremented.

user_id

The optional ID of the user who started the task.

name

The name of the task.

arguments

The arguments of the task.

Stored in the following form as JSON:

{
    "args": ["value_1"],
    "kwargs": {"arg_2": "value_2"},
}
progress

The progress of the task.

Needs to be an integer value between 0 and 100.

created_at

The date and time an object has been created at.

Always uses the current UTC time.

last_modified

The date and time an object was last modified.

Always uses the current UTC time as initial value. After calling register_timestamp_listener() for an inheriting mixin class, this timestamp can automatically get updated by implementing “_before_flush_timestamp” as a class method.

result

The optional result of the task, depending on the type of task.

state

The state of the task.

One of "pending", "running", "revoked", "success" or "failure".

property is_revoked

Check if a task is revoked.

Will always refresh the task object to get up to date values, as revoking usually happens outside the current database session context (e.g. in another process).

property pretty_state

Return the state of a task in a human-readable and translated format.

classmethod create(*, creator, name, args=None, kwargs=None, state='pending')[source]

Create a new task and add it to the database session.

Parameters:
  • creator – The user who is starting the task.

  • name – The name of the task.

  • args – (optional) The positional arguments of the task as list.

  • kwargs – (optional) The keyword arguments of the task as dictionary.

  • state – (optional) The state of the task.

Returns:

The new Task object.

revoke()[source]

Revoke a task if it is still pending or running.

update_progress(percent)[source]

Update a tasks progress.

Parameters:

percent – The progress in percent, which needs to be an integer or float value between 0 and 100.

kadi.lib.tasks.utils.clean_tasks(inside_task=False)[source]

Clean all expired, finished tasks.

Note that this function issues a database commit.

Parameters:

inside_task – (optional) A flag indicating whether the function is executed in a task. In that case, additional information will be logged.

Utils

class kadi.lib.utils.SimpleReprMixin[source]

Bases: object

Mixin to add a simple implementation of __repr__ to a class.

The provided implementation uses all instance or class attributes specified in the Meta.representation attribute of the inheriting class. It should be a list of strings specifying the attributes to use in the representation.

Example:

class Foo:
    class Meta:
        representation = ["bar", "baz"]

    bar = 1

    baz = 2
class kadi.lib.utils.StringEnum[source]

Bases: object

Custom enum-like class that uses regular strings as values.

An inheriting class needs to specify a __values__ attribute for all possible enum string values. Each value will be added as a class attribute using its respective value as key in uppercase.

Example:

class Foo:
    __values__ = ["bar"]
kadi.lib.utils.named_tuple(tuple_name, **kwargs)[source]

Convenience function to build a namedtuple from keyword arguments.

Parameters:
  • tuple_name – The name of the tuple.

  • **kwargs – The keys and values of the tuple.

Returns:

The namedtuple instance.

kadi.lib.utils.compare(left, op, right)[source]

Compare two values with a given operator.

Parameters:
  • left – The left value.

  • op – One of "==", "!=", ">", "<", ">=" or "<=".

  • right – The right value.

Returns:

The boolean result of the comparison.

kadi.lib.utils.rgetattr(obj, name, default=None)[source]

Get a nested attribute of an object.

Parameters:
  • obj – The object to get the attribute from.

  • name – The name of the attribute in the form of "foo.bar.baz".

  • default – (optional) The default value to return if the attribute could not be found.

Returns:

The attribute or the default value if it could not be found.

kadi.lib.utils.get_class_by_name(name)[source]

Get a class given its name.

Parameters:

name – The complete name of the class in the form of "foo.bar.Baz".

Returns:

The class or None if it could not be found.

kadi.lib.utils.utcnow()[source]

Create a timezone aware datetime object of the current time in UTC.

Returns:

A datetime object as specified in Python’s datetime module.

kadi.lib.utils.compact_json(data, ensure_ascii=False, sort_keys=True)[source]

Serialize data to a compact JSON formatted string.

Uses the JSON encoder provided by Flask, which can deal with some additional types.

Parameters:
  • data – The data to serialize.

  • ensure_ascii – (optional) Whether to escape non-ASCII characters.

  • sort_keys – (optional) Whether to sort the output of dictionaries by key.

Returns:

The JSON formatted string.

kadi.lib.utils.formatted_json(data, ensure_ascii=False, sort_keys=True)[source]

Serialize data to a user-readable JSON formatted string.

Uses the JSON encoder provided by Flask, which can deal with some additional types.

Parameters:
  • data – The data to serialize.

  • ensure_ascii – (optional) Whether to escape non-ASCII characters.

  • sort_keys – (optional) Whether to sort the output of dictionaries by key.

Returns:

The JSON formatted string.

kadi.lib.utils.is_special_float(value)[source]

Check if a float value is a special value, i.e. nan or inf.

Parameters:

value – The float value to check.

Returns:

True if the value is a special float value, False otherwise.

kadi.lib.utils.is_iterable(value, include_string=False)[source]

Check if a value is an iterable.

Parameters:
  • value – The value to check.

  • include_string – (optional) Flag indicating whether a string value should be treated as a valid iterable or not.

Returns:

True if the value is iterable, False otherwise.

kadi.lib.utils.is_quoted(value)[source]

Check if a string value is quoted, i.e. surrounded by double quotes.

Returns:

True if the value is quoted, False otherwise.

kadi.lib.utils.find_dict_in_list(dict_list, key, value)[source]

Find a dictionary with a specific key and value in a list.

Parameters:
  • dict_list – A list of dictionaries to search.

  • key – The key to search for.

  • value – The value to search for.

Returns:

The dictionary or None if it was not found.

kadi.lib.utils.flatten_list(values)[source]

Flattens a list.

Flattens a list containing single values or nested lists. Multiple layers of nested lists are not supported.

Parameters:

values – List containing single values or nested lists.

Returns:

The flattened list.

kadi.lib.utils.as_list(value)[source]

Wrap a value inside a list if the given value is not a list already.

Parameters:

value – The value to potentially wrap.

Returns:

The original or wrapped value. If the given value is None, the value will always be returned as is.

kadi.lib.utils.has_capabilities(*capabilities)[source]

Check if the current Kadi instance has all given capabilities.

Parameters:

capabilities – One or more capabilities to check.

Returns:

True if all given capabilities are available, False otherwise.

Validation

kadi.lib.validation.validator(exception_class)[source]

Decorator to wrap a validation function.

Handles errors of type KadiValidationError and reraises another customizable exception using the same message.

Parameters:

exception_class – The exception to raise in case of validation failure.

kadi.lib.validation.validate_uuid(uuid_string, version=4)[source]

Validate a string against a specific UUID version.

Parameters:
  • uuid_string – The UUID string.

  • version – (optional) The UUID version.

Raises:

KadiValidationError – If the validation fails.

kadi.lib.validation.validate_identifier(value)[source]

Validate the format of an identifier.

Identifiers can be used to give resources a human-readable, unique identification. An identifier is restricted to lowercase alphanumeric characters, hyphens and underscores.

Parameters:

value – The identifier string.

Raises:

KadiValidationError – If the validation fails.

kadi.lib.validation.validate_mimetype(value)[source]

Validate the format of a MIME type.

A MIME type has to start with at least one alphabetical character, followed by a forward slash, followed by lowercase alphanumeric characters or the special characters "-", "+" or ".".

Parameters:

value – The MIME type string.

Raises:

KadiValidationError – If the validation fails.

kadi.lib.validation.validate_username(value)[source]

Validate the format of a local username.

Local usernames are restricted to lowercase alphanumeric characters with single hyphens or underscores in between.

Parameters:

value – The username string.

Raises:

KadiValidationError – If the validation fails.

kadi.lib.validation.validate_iri(value)[source]

Validate an IRI according to RFC3987.

Parameters:

value – The IRI string.

Raises:

KadiValidationError – If the validation fails.

Web

class kadi.lib.web.IdentifierConverter(map: Map, *args: Any, **kwargs: Any)[source]

Bases: BaseConverter

Custom URL converter for identifiers.

Automatically uses the same conversions that are applied when creating or updating an identifier. See also kadi.lib.validation.validate_identifier().

kadi.lib.web.flash_danger(message)[source]

Flash a danger message to the next request.

Uses flash() with a fixed "danger" category.

Parameters:

message – The message to be flashed.

kadi.lib.web.flash_info(message)[source]

Flash an info message to the next request.

Uses flash() with a fixed "info" category.

Parameters:

message – The message to be flashed.

kadi.lib.web.flash_success(message)[source]

Flash a success message to the next request.

Uses flash() with a fixed "success" category.

Parameters:

message – The message to be flashed.

kadi.lib.web.flash_warning(message)[source]

Flash a warning message to the next request.

Uses flash() with a fixed "warning" category.

Parameters:

message – The message to be flashed.

kadi.lib.web.get_locale()[source]

Get the current locale.

The locale specified via a query parameter of the current request will take precedence, followed by the locale cookie as configured by LOCALE_COOKIE_NAME in the application’s configuration and finally the default locale.

Returns:

The current locale. If no valid locale could be found, the default locale will be returned.

kadi.lib.web.get_preferred_locale()[source]

Get the preferred locale of the current user’s client.

Returns:

The preferred locale. If no matching locale could be found, the default locale will be returned.

kadi.lib.web.download_bytes(data, download_name, mimetype=None, as_attachment=True)[source]

Send a file-like binary object to a client as a file.

Parameters:
  • data – The data object to send.

  • download_name – The default name the browser should use when downloading the file.

  • mimetype – (optional) The MIME type of the file. Defaults to a MIME type based on the given download_name or the default MIME type as defined in kadi.lib.constants.MIMETYPE_BINARY if it cannot be guessed.

  • as_attachment – (optional) Flag indicating whether the file should be displayed in the browser instead of being downloaded. Should only be disabled for trusted data or data that is safe for displaying.

Returns:

The response object.

kadi.lib.web.download_stream(data, download_name, mimetype=None, as_attachment=True, content_length=None)[source]

Send an iterable object or generator producing binary data to a client as a file.

Useful for cases where download_bytes() cannot be used, as a raw response object is used here instead. Note that the resulting response will never be cached.

Parameters:
Returns:

The response object.

kadi.lib.web.get_apidoc_meta(func)[source]

Get the API documentation meta dictionary of a view function.

If not present yet, a corresponding dictionary will be created first as an attribute of the given view function.

Parameters:

func – The view function.

Returns:

The newly created or existing meta dictionary.

kadi.lib.web.paginated(page_max=None, per_page_max=100)[source]

Decorator to parse paginated query parameters.

Convenience decorator to get and parse the query parameters "page" and "per_page" from the current request. The former defaults to 1 while the latter defaults to 10 if no valid integer values were found. Both parameters will be injected into the decorated function as keyword arguments page and per_page.

The query parameters are also used when generating the API documentation.

Parameters:
  • page_max – (optional) The maximum possible value of the "page" parameter.

  • per_page_max – (optional) The maximum possible value of the "per_page" parameter.

kadi.lib.web.qparam(name, location=None, multiple=False, default='', parse=None, description='')[source]

Decorator to parse a query parameter.

Convenience decorator to retrieve and parse a specified query parameter from the current request. The decorator can be applied multiple times. Each parameter will be injected into the decorated function as part a dictionary inside the keyword argument qparams. The dictionary maps each given parameter name to its respective value.

The query parameter is also used when generating the API documentation.

Parameters:
  • name – The name of both the query parameter and the dictionary key that is injected into the decorated function.

  • location – (optional) The name of the query parameter to use instead of name.

  • multiple – (optional) Flag indicating whether the query parameter can be specified multiple times and should be retrieved as list value.

  • default – (optional) The default value or a callable returning a default value to use in case the query parameter is missing and multiple is False, otherwise the default value will always be an empty list.

  • parse – (optional) A callable or list of callables to parse the parameter value if it is not missing. Each callable must take and return a single parameter value. If parsing fails with a ValueError, the default value is taken instead if multiple is False, otherwise each invalid value is removed from the resulting list.

  • description – (optional) A description of the query parameter, which is only used when generating the API documentation. Supports reST syntax.

kadi.lib.web.url_for(endpoint, _ignore_version=False, **values)[source]

Generate an URL based on a given endpoint.

Wraps Flask’s url_for function with additional support for generating the correct URLs when using API versioning. Additionally, generated URLs are always external, i.e. absolute.

Parameters:
  • endpoint – The endpoint (name of the function) of the URL.

  • _ignore_version – (optional) Flag indicating whether the API version should be ignored when building the URL in API requests.

  • **values – The variable arguments of the URL rule.

Returns:

The generated URL string.

kadi.lib.web.static_url(filename)[source]

Generate a static URL for a given filename.

Will make use of the MANIFEST_MAPPING if it is defined in the application’s configuration and if an entry exists for the given filename.

Parameters:

filename – The name of the file to include in the URL.

Returns:

The generated URL string.

kadi.lib.web.make_next_url(next_url)[source]

Create a URL to redirect a user to after login.

Parameters:

next_url – A URL to redirect to, which will be included as a next query parameter in the generated URL.

Returns:

The generated URL.

kadi.lib.web.get_next_url(fallback=None)[source]

Get the validated target URL to redirect a user to after login.

The target URL has to be specified as a next query parameter in the current request and needs to redirect to an internal page.

Parameters:

fallback – (optional) The fallback URL to use in case the target URL was invalid or could not be found. Defaults to the index page.

Returns:

The validated target URL.

kadi.lib.web.get_error_message(status_code)[source]

Get an error message corresponding to an HTTP status code.

Parameters:

status_code – The HTTP status code.

Returns:

The error message.

kadi.lib.web.get_error_description(status_code)[source]

Get an error description corresponding to an HTTP status code.

Parameters:

status_code – The HTTP status code.

Returns:

The error description.

kadi.lib.web.html_error_response(status_code, message=None, description=None)[source]

Return an HTML error response to a client.

Parameters:
  • status_code – The HTTP status code of the response.

  • message – (optional) The error message. Defaults to the result of get_error_message() using the given status code.

  • description – (optional) The error description. Defaults to the result of get_error_description() using the given status code.

Returns:

The HTML response.