134 lines
5.1 KiB
Python
134 lines
5.1 KiB
Python
import logging
|
|
|
|
from fastapi_pagination import add_pagination
|
|
|
|
from dump_things_service.abstract_config import (
|
|
Configuration,
|
|
TokenConfig,
|
|
)
|
|
from dump_things_service.collection import create_collection
|
|
from dump_things_service.instance_state import InstanceState
|
|
|
|
|
|
logger = logging.getLogger('dump_things_service')
|
|
|
|
|
|
def manifest_configuration(
|
|
configuration: Configuration,
|
|
instance_state: InstanceState,
|
|
):
|
|
"""Interpret the configuration and instantiate respective objects
|
|
|
|
For every collection in the configuration this method will:
|
|
|
|
- create a `ModelStore`-instance with correct `Backend`-instances and
|
|
check for compatibility with existing data
|
|
- create schema-related objects
|
|
- add schema class-specific http-endpoints to:
|
|
-- validate records
|
|
-- create records in the user's inbox
|
|
-- create records in the curated area
|
|
-- create records in a specific incoming area
|
|
|
|
Objects and endpoints that belong to a non-existing configuration are
|
|
deleted.
|
|
|
|
If objects for a collection do already exist, they are kept unmodified
|
|
and are not validated. That means changes of existing configuration objects
|
|
are not possible. To modify a collection or token configuration, the
|
|
configuration has to be deleted and created in the new state.
|
|
|
|
If case of an error in the configuration, no objects will be create for
|
|
the respective collection or token.
|
|
|
|
Tokens can be updated. Collections can not be updated, to modify the
|
|
configuration of a collection, the collection must be deleted and
|
|
recreated with the modified configuration. Deleting a collection will
|
|
not delete the data of the collection. If the collection is recreated with
|
|
the same backend- and directory-configuration, the data will be accessible
|
|
in the new collection as well. It is, however, not recommended to update
|
|
the schema of a collection. This will most likely break the service on this
|
|
collection.
|
|
|
|
When collections are deleted, some tokens might still refer to them, this
|
|
is silently ignored. This supports to delete a collection and delete or
|
|
modify the token later.
|
|
|
|
Default-tokens are not validated when a new collection is created. This
|
|
allows to first create a collection and then the default token. The cost
|
|
is that a "default-token unknown" error might be created when accessing
|
|
a collection.
|
|
"""
|
|
|
|
# Determine the changes in collections.
|
|
existing_collections = set(instance_state.collections)
|
|
configured_collections = set(configuration.collections)
|
|
new_collection_names = configured_collections - existing_collections
|
|
deleted_collection_names = existing_collections - configured_collections
|
|
|
|
# Delete collection objects of collections that are no longer in the
|
|
# configuration (we do not delete the collection from token-objects here
|
|
# because token-objects are all re-created below).
|
|
for collection_name in deleted_collection_names:
|
|
delete_collection(instance_state, collection_name)
|
|
|
|
# Create the internal representation objects for collections that have been
|
|
# added to the configuration.
|
|
for collection_name in new_collection_names:
|
|
create_collection(
|
|
instance_state,
|
|
configuration,
|
|
collection_name,
|
|
)
|
|
|
|
# Delete all token objects and recreate the tokens. This ensures that
|
|
# modified token scope and permissions are set for all tokens.
|
|
for token_name in list(instance_state.tokens):
|
|
delete_token(instance_state, token_name)
|
|
|
|
for token_name, token_configuration in configuration.tokens.items():
|
|
create_token(
|
|
instance_state,
|
|
token_name,
|
|
token_configuration,
|
|
)
|
|
|
|
if new_collection_names or deleted_collection_names:
|
|
instance_state.fastapi_app.openapi_schema = None
|
|
instance_state.fastapi_app.setup()
|
|
add_pagination(instance_state.fastapi_app)
|
|
|
|
# We do not create any incoming areas for configuration-file tokens
|
|
# here. The reason is that the configuration does not fully determine
|
|
# the possible incoming areas because incoming areas come from
|
|
# authentication sources and the configuration-file authentication source
|
|
# is just one possible authentication source. Other authentication sources
|
|
# have unknown means to create incoming area labels.
|
|
# Incoming areas are therefore create when a write request for a token
|
|
# is authorized.
|
|
|
|
|
|
def create_token(
|
|
instance_state: InstanceState,
|
|
token_name: str,
|
|
token_configuration: TokenConfig,
|
|
):
|
|
instance_state.tokens[token_name] = token_configuration
|
|
|
|
|
|
def delete_token(
|
|
instance_state: InstanceState,
|
|
token_name: str,
|
|
):
|
|
instance_state.tokens.pop(token_name)
|
|
|
|
|
|
def delete_collection(
|
|
instance_state: InstanceState,
|
|
collection_name: str,
|
|
):
|
|
instance_state.collections.pop(collection_name)
|
|
# TODO: remove all collection-related information from
|
|
# instance_state. Maybe all collection-specific information
|
|
# should go into the instance_state.collection[x]-object!?
|
|
# That would allow to remove it easily.
|