async def reindex(self, obj):
        index_manager = find_index_manager(obj)
        if index_manager is None:
            index_manager = get_adapter(self.request.container, IIndexManager)
        self.work_index_name = await index_manager.get_index_name()

        await notify(IndexProgress(
            self.request, self.context, 0, self.processed))
        await self.process_object(obj)
        await self.flush()
        if len(self.sub_indexes) > 0:
            # could cause sub indexes to need to be run through as well.
            for ob in self.sub_indexes:
                im = get_adapter(ob, IIndexManager)
                reindexer = Reindexer(
                    self.utility, ob, response=self.response, force=self.force,
                    log_details=self.log_details,
                    memory_tracking=self.memory_tracking,
                    request=self.request, bulk_size=self.bulk_size,
                    full=self.full, reindex_security=self.reindex_security,
                    mapping_only=self.mapping_only, index_manager=im)
                reindexer.processed = self.processed
                reindexer.work_index_name = await im.get_index_name()
                await reindexer.process_folder(ob)
                await reindexer.flush()
                self.processed = reindexer.processed

        await notify(IndexProgress(
            self.request, self.context, self.processed,
            self.processed, completed=True
        ))
Exemplo n.º 2
0
    def __init__(self, manager, request=None, loop=None):
        self._txn_time = None
        self._tid = None
        self.status = Status.ACTIVE

        # Transaction Manager
        self._manager = manager

        # List of objects added
        # needs to be ordered because content inserted after other might
        # reference each other
        self.added = OrderedDict()
        self.modified = {}
        self.deleted = {}

        # OIDS to invalidate
        self._objects_to_invalidate = []

        # List of (hook, args, kws) tuples added by addBeforeCommitHook().
        self._before_commit = []

        # List of (hook, args, kws) tuples added by addAfterCommitHook().
        self._after_commit = []

        logger.debug("new transaction")

        # Connection to DB
        self._db_conn = None
        # Transaction on DB
        self._db_txn = None
        # Lock on the transaction
        # some databases need to lock during queries
        # this provides a lock for each transaction
        # which would correspond with one connection
        self._lock = asyncio.Lock(loop=loop)

        # we *not* follow naming standards of using "_request" here so
        # get_current_request can magically find us here...
        self.request = request
        self._strategy = get_adapter(
            self,
            ITransactionStrategy,
            name=manager._storage._transaction_strategy)
        self._cache = get_adapter(self,
                                  IStorageCache,
                                  name=manager._storage._cache_strategy)

        self._query_count_start = self._query_count_end = 0
Exemplo n.º 3
0
    async def __call__(self):
        if self.key is _marker:
            # No option to write the root of registry
            return ErrorResponse('InvalidRequest', 'Needs the registry key')

        data = await self.request.json()
        if 'value' in data:
            value = data['value']
        else:
            value = data

        assert '.' in self.key, 'Registry key must be dotted.iface.name.fieldname'  # noqa
        iface, name = self.key.rsplit('.', 1)
        iface = resolve_dotted_name(iface)
        field = iface[name]

        try:
            new_value = get_adapter((field),
                                    IJSONToValue,
                                    args=[value, self.context])
        except ComponentLookupError:
            return ErrorResponse('DeserializationError',
                                 'Cannot deserialize type {}'.format(
                                     str(self.field)),
                                 status=501)

        try:
            self.request.container_settings[self.key] = new_value
        except DeserializationError as e:
            return ErrorResponse('DeserializationError',
                                 str(e),
                                 exc=e,
                                 status=400)

        return Response(response='', status=204)
async def test_removes_orphans(es_requester):
    async with es_requester as requester:
        container, request, txn, tm = await setup_txn_on_container(requester)
        search = get_utility(ICatalogUtility)
        await search.index(
            container, {'foobar': {
                'title': 'foobar',
                'type_name': 'Item'
            }})
        # foobar here is an orphaned object because it doesn't reference
        # an object

        im = get_adapter(container, IIndexManager)
        index_name = await im.get_index_name()  # alias

        doc = await search.conn.get(index=index_name,
                                    doc_type=DOC_TYPE,
                                    id='foobar')
        assert doc['found']

        migrator = Migrator(search, container, force=True)
        await migrator.run_migration()

        async def _test():
            with pytest.raises(aioelasticsearch.exceptions.NotFoundError):
                await search.conn.get(index=index_name,
                                      doc_type=DOC_TYPE,
                                      id='foobar')

            assert len(migrator.orphaned) == 1
            assert migrator.orphaned[0] == 'foobar'

        await run_with_retries(_test, requester)
async def test_delete_in_both_during_migration(es_requester):
    async with es_requester as requester:
        container, request, txn, tm = await setup_txn_on_container(requester)
        search = get_utility(ICatalogUtility)
        migrator = Migrator(search, container, force=True, request=request)
        im = get_adapter(container, IIndexManager)
        index_name = await im.get_index_name()
        next_index_name = await migrator.setup_next_index()

        resp, _ = await requester('POST',
                                  '/db/guillotina',
                                  data=json.dumps({
                                      '@type': 'Folder',
                                      'title': 'Foobar1',
                                      'id': 'foobar'
                                  }))
        await requester('DELETE', '/db/guillotina/foobar')

        async def _test():
            with pytest.raises(aioelasticsearch.exceptions.NotFoundError):
                await search.conn.get(index=next_index_name,
                                      doc_type='_all',
                                      id=resp['@uid'])
            with pytest.raises(aioelasticsearch.exceptions.NotFoundError):
                await search.conn.get(index=index_name,
                                      doc_type='_all',
                                      id=resp['@uid'])

        await run_with_retries(_test, requester)
async def test_search_works_on_new_docs_during_migration(es_requester):
    async with es_requester as requester:
        await add_content(requester, 2)
        container, request, txn, tm = await setup_txn_on_container(requester)
        search = get_utility(ICatalogUtility)
        migrator = Migrator(search, container, force=True, request=request)
        im = get_adapter(container, IIndexManager)
        index_name = await im.get_index_name()
        next_index_name = await migrator.setup_next_index()

        resp, _ = await requester('POST',
                                  '/db/guillotina',
                                  data=json.dumps({'@type': 'Item'}))

        async def _test():
            result1 = await search.conn.get(index=next_index_name,
                                            doc_type='_all',
                                            id=resp['@uid'])
            assert result1 is not None
            result2 = await search.conn.get(index=index_name,
                                            doc_type='_all',
                                            id=resp['@uid'])
            assert result2 is not None

        await run_with_retries(_test, requester)
Exemplo n.º 7
0
    def initialize(
        self, read_only, cache=None, strategy=None,
    ):
        self._read_only = read_only
        self._txn_time = None
        self._tid = None
        self.status = Status.ACTIVE
        self.user = None

        # List of objects added
        # needs to be ordered because content inserted after other might
        # reference each other
        self.added = OrderedDict()
        self.added_children = {}
        self.modified = {}
        self.deleted = {}

        # List of (hook, args, kws) tuples added by addBeforeCommitHook().
        self._before_commit = []

        # List of (hook, args, kws) tuples added by addAfterCommitHook().
        self._after_commit = []

        self._cache = cache or query_adapter(self, ITransactionCache, name=app_settings["cache"]["strategy"])
        self._strategy = strategy or get_adapter(
            self, ITransactionStrategy, name=self._manager._storage._transaction_strategy
        )
        self._query_count_start = self._query_count_end = 0
Exemplo n.º 8
0
async def iter_databases(root=None):
    if root is None:
        root = get_utility(IApplication, name='root')

    loaded = []

    for _, db in root:
        if IDatabase.providedBy(db):
            yield db
            loaded.append(db.id)

    last_checked = None

    while last_checked is None or set(last_checked) != set(loaded):
        # we need to continue checking until we're sure there aren't any
        # new storage objects that have been added since we started
        last_checked = loaded[:]

        # from all dynamic storages
        for _, config in list_or_dict_items(app_settings['storages']):
            ctype = config.get('type', config['storage'])
            factory = get_adapter(root, IDatabaseManager, name=ctype, args=[config])
            for db_name in await factory.get_names():
                if db_name in loaded:
                    continue
                db = await factory.get_database(db_name)
                loaded.append(db.id)
                yield db
async def test_update(es_requester):
    async with es_requester as requester:
        container, request, txn, tm = await setup_txn_on_container(requester
                                                                   )  # noqa
        search = get_utility(ICatalogUtility)
        current_count = await search.get_doc_count(container)
        await search.index(
            container, {'foobar': {
                'title': 'foobar',
                'type_name': 'Item'
            }})
        await search.refresh(container)
        assert await search.get_doc_count(container) == current_count + 1
        await search.update(
            container,
            {'foobar': {
                'title': 'foobar-updated',
                'type_name': 'Item'
            }})
        await search.refresh(container)
        im = get_adapter(container, IIndexManager)
        doc = await search.conn.get(index=await im.get_index_name(),
                                    doc_type=DOC_TYPE,
                                    id='foobar')
        assert doc['_source']['title'] == 'foobar-updated'
Exemplo n.º 10
0
async def init_index(context, subscriber):
    try:
        im = get_adapter(context, IIndexManager)
        utility = query_utility(ICatalogUtility)

        if utility is None:
            return
        index_name = await im.get_index_name()
        real_index_name = await im.get_real_index_name()

        conn = utility.get_connection()

        await utility.create_index(real_index_name, im)
        await conn.indices.put_alias(name=index_name, index=real_index_name)
        await conn.indices.close(real_index_name)

        await conn.indices.open(real_index_name)

        await conn.cluster.health(wait_for_status="yellow")
        alsoProvides(context, IIndexActive)

        execute.add_future(
            "cleanup-" + context.uuid,
            _teardown_failed_request_with_index,
            scope="failure",
            args=[im],
        )
    except Exception:
        logger.error("Error creating index for content", exc_info=True)
        raise
Exemplo n.º 11
0
async def init_index(context, subscriber):
    try:
        im = get_adapter(context, IIndexManager)
        utility = get_utility(ICatalogUtility)

        index_name = await im.get_index_name()
        real_index_name = await im.get_real_index_name()

        await utility.create_index(real_index_name, im)
        await utility.conn.indices.put_alias(
            name=index_name, index=real_index_name)

        await utility.conn.cluster.health(
            wait_for_status='yellow')

        alsoProvides(context, IIndexActive)

        request = get_current_request()
        request.add_future(
            'cleanup-' + context.uuid,
            _teardown_failed_request_with_index, scope='failure',
            args=[im])
    except Exception:
        logger.error('Error creating index for content', exc_info=True)
        raise
async def test_delete_in_both_during_migration(es_requester):
    async with es_requester as requester:
        container, request, txn, tm = await setup_txn_on_container(requester)
        search = get_utility(ICatalogUtility)
        migrator = Migrator(search, container, force=True)
        im = get_adapter(container, IIndexManager)
        index_name = await im.get_index_name()
        next_index_name = await migrator.setup_next_index()

        resp, _ = await requester(
            "POST",
            "/db/guillotina",
            data=json.dumps({
                "@type": "Folder",
                "title": "Foobar1",
                "id": "foobar"
            }),
        )
        await requester("DELETE", "/db/guillotina/foobar")

        async def _test():
            with pytest.raises(aioelasticsearch.exceptions.NotFoundError):
                await search.get_connection().get(index=next_index_name,
                                                  doc_type="_all",
                                                  id=resp["@uid"])
            with pytest.raises(aioelasticsearch.exceptions.NotFoundError):
                await search.get_connection().get(index=index_name,
                                                  doc_type="_all",
                                                  id=resp["@uid"])

        await run_with_retries(_test, requester)
Exemplo n.º 13
0
    async def __call__(self):
        data = await self.request.json()
        if "@type" not in data or data["@type"] not in app_settings[
                "container_types"]:
            raise HTTPNotFound(
                content={
                    "message": "can not create this type %s" % data["@type"]
                })

        if "id" not in data:
            raise HTTPPreconditionFailed(content={"message": "We need an id"})

        if not data.get("title"):
            data["title"] = data["id"]

        if "description" not in data:
            data["description"] = ""

        value = await self.context.async_contains(data["id"])

        if value:
            # Already exist
            raise HTTPConflict(
                content={"message": "Container with id already exists"})

        install_addons = data.pop("@addons", None) or []
        for addon in install_addons:
            # validate addon list
            if addon not in app_settings["available_addons"]:
                return ErrorResponse(
                    "RequiredParam",
                    "Property '@addons' must refer to a valid addon",
                    status=412,
                    reason=error_reasons.INVALID_ID,
                )

        owner_id = get_authenticated_user_id()

        container = await create_container(self.context,
                                           data.pop("id"),
                                           container_type=data.pop("@type"),
                                           owner_id=owner_id,
                                           **data)
        task_vars.container.set(container)

        annotations_container = get_adapter(container, IAnnotations)
        task_vars.registry.set(
            await annotations_container.async_get(REGISTRY_DATA_KEY))

        for addon in install_addons:
            await addons.install(container, addon)

        resp = {
            "@type": container.type_name,
            "id": container.id,
            "title": data["title"]
        }
        headers = {"Location": posixpath.join(self.request.path, container.id)}

        return Response(content=resp, headers=headers)
Exemplo n.º 14
0
def field_converter(field, value, context):
    field.field.__name__ = field.__name__
    if isinstance(value, dict) and "op" in value:
        if not isinstance(value, dict):
            raise ValueDeserializationError(field, value, "Not an object")
        operation_name = value.get("op", "undefined")
        if operation_name == "multi":
            operation = query_adapter(field,
                                      field.operation_type,
                                      name=operation_name)
            if operation is None:
                raise ValueDeserializationError(
                    field, value, f'"{operation_name}" not a valid operation')
            value = operation(context, value.get("value"))
        else:
            bound_field = field.field.bind(context)
            operation = query_adapter(bound_field,
                                      field.operation_type,
                                      name=operation_name)
            if operation is None:
                raise ValueDeserializationError(
                    field, value, f'"{operation_name}" not a valid operation')
            value = operation(context, value.get("value"))
    elif isinstance(value, (dict, list)):
        value = get_adapter(field.field, IJSONToValue, args=[value, context])
    return value
Exemplo n.º 15
0
 async def apply_authorization(self, request: IRequest):
     # User participation
     participation = get_adapter(request, IParticipation)
     # Lets extract the user from the request
     await participation()
     if participation.principal is not None:
         request.security.add(participation)
Exemplo n.º 16
0
async def iter_databases(root=None):
    if root is None:
        root = get_utility(IApplication, name='root')

    loaded = []

    for _, db in root:
        if IDatabase.providedBy(db):
            yield db
            loaded.append(db.id)

    last_checked = None

    while last_checked is None or set(last_checked) != set(loaded):
        # we need to continue checking until we're sure there aren't any
        # new storage objects that have been added since we started
        last_checked = loaded[:]

        # from all dynamic storages
        for _, config in list_or_dict_items(app_settings['storages']):
            ctype = config.get('type', config['storage'])
            factory = get_adapter(root, IDatabaseManager, name=ctype, args=[config])
            for db_name in await factory.get_names():
                if db_name in loaded:
                    continue
                db = await factory.get_database(db_name)
                loaded.append(db.id)
                yield db
Exemplo n.º 17
0
async def test_get_security_data(dummy_request):
    request = dummy_request  # noqa
    ob = test_utils.create_content()
    adapter = get_adapter(ob, ISecurityInfo)
    data = adapter()
    assert 'access_users' in data
    assert 'access_roles' in data
Exemplo n.º 18
0
async def test_get_security_data(dummy_guillotina):
    ob = test_utils.create_content()
    adapter = get_adapter(ob, ISecurityInfo)
    data = adapter()
    assert "id" in data
    assert "access_users" in data
    assert "access_roles" in data
Exemplo n.º 19
0
    async def __call__(self):
        data = await self.request.json()
        if '@type' not in data or data['@type'] not in app_settings['container_types']:
            raise HTTPNotFound(content={
                'message': 'can not create this type %s' % data['@type']
            })

        if 'id' not in data:
            raise HTTPPreconditionFailed(content={
                'message': 'We need an id'
            })

        if not data.get('title'):
            data['title'] = data['id']

        if 'description' not in data:
            data['description'] = ''

        value = await self.context.async_contains(data['id'])

        if value:
            # Already exist
            raise HTTPConflict(content={
                'message': 'Container with id already exists'
            })

        install_addons = data.pop('@addons', None) or []
        for addon in install_addons:
            # validate addon list
            if addon not in app_settings['available_addons']:
                return ErrorResponse(
                    'RequiredParam',
                    "Property '@addons' must refer to a valid addon",
                    status=412, reason=error_reasons.INVALID_ID)

        owner_id = get_authenticated_user_id(self.request)

        container = await create_container(
            self.context, data.pop('id'),
            container_type=data.pop('@type'),
            owner_id=owner_id, **data)
        self.request._container_id = container.__name__
        self.request.container = container

        annotations_container = get_adapter(container, IAnnotations)
        self.request.container_settings = await annotations_container.async_get(REGISTRY_DATA_KEY)

        for addon in install_addons:
            await addons.install(container, addon)

        resp = {
            '@type': container.type_name,
            'id': container.id,
            'title': data['title']
        }
        headers = {
            'Location': posixpath.join(self.request.path, container.id)
        }

        return Response(content=resp, headers=headers)
Exemplo n.º 20
0
async def get_index_for(context, container=None):
    im = find_index_manager(parent=context)
    if im is None:
        if container is None:
            container = get_current_container()
        im = get_adapter(container, IIndexManager)
    return await im.get_index_name()
Exemplo n.º 21
0
    async def __call__(self):
        data = await self.request.json()
        if '@type' not in data or data['@type'] not in app_settings[
                'container_types']:
            raise HTTPNotFound(
                content={
                    'message': 'can not create this type %s' % data['@type']
                })

        if 'id' not in data:
            raise HTTPPreconditionFailed(content={'message': 'We need an id'})

        if not data.get('title'):
            data['title'] = data['id']

        if 'description' not in data:
            data['description'] = ''

        value = await self.context.async_contains(data['id'])

        if value:
            # Already exist
            raise HTTPConflict(
                content={'message': 'Container with id already exists'})

        install_addons = data.pop('@addons', None) or []
        for addon in install_addons:
            # validate addon list
            if addon not in app_settings['available_addons']:
                return ErrorResponse(
                    'RequiredParam',
                    "Property '@addons' must refer to a valid addon",
                    status=412,
                    reason=error_reasons.INVALID_ID)

        owner_id = get_authenticated_user_id(self.request)

        container = await create_container(self.context,
                                           data.pop('id'),
                                           container_type=data.pop('@type'),
                                           owner_id=owner_id,
                                           **data)
        self.request._container_id = container.__name__
        self.request.container = container

        annotations_container = get_adapter(container, IAnnotations)
        self.request.container_settings = await annotations_container.async_get(
            REGISTRY_DATA_KEY)

        for addon in install_addons:
            await addons.install(container, addon)

        resp = {
            '@type': container.type_name,
            'id': container.id,
            'title': data['title']
        }
        headers = {'Location': posixpath.join(self.request.path, container.id)}

        return Response(content=resp, headers=headers)
Exemplo n.º 22
0
 async def get_doc_count(self, container=None, index_name=None):
     if index_name is None:
         index_manager = get_adapter(container, IIndexManager)
         index_name = await index_manager.get_real_index_name()
     conn = self.get_connection()
     result = await conn.count(index=index_name)
     return result["count"]
Exemplo n.º 23
0
 async def apply_authorization(self, request: IRequest):
     # User participation
     participation = get_adapter(request, IParticipation)
     # Lets extract the user from the request
     await participation()
     if participation.principal is not None:
         request.security.add(participation)
Exemplo n.º 24
0
def _validate_field(field, context, value):
    if 'key' not in value or 'value' not in value:
        raise ValueDeserializationError(
            field, value, f'Invalid data')

    from guillotina.behaviors.dynamic import find_field

    field = find_field(context, value['key'])
    # now, verify value...
    if not field:
        raise ValueDeserializationError(
            field, value, f'Dynamic field not found')
    field_type = field.get('type', 'unknown')
    try:
        valid_type = namedtuple(
            'temp_assign_type', [field_type])
        ob = valid_type({field_type: None})
        bound_field = IDynamicType[field_type].bind(ob)
        # validate and convert
        real_value = get_adapter(
            bound_field, IJSONToValue, args=[value['value'], ob])
        bound_field.validate(real_value)
        value['value'] = real_value
    except (KeyError, ComponentLookupError):
        raise ValueDeserializationError(
            field, value, f'Invalid type {field_type}')
Exemplo n.º 25
0
async def test_get_security_data(dummy_request):
    request = dummy_request  # noqa
    ob = test_utils.create_content()
    adapter = get_adapter(ob, ISecurityInfo)
    data = adapter()
    assert 'access_users' in data
    assert 'access_roles' in data
Exemplo n.º 26
0
async def get_database(db_id, root=None) -> IDatabase:
    """
    Get configured database

    :param db_id: configured database id
    """
    if root is None:
        root = get_utility(IApplication, name="root")

    if db_id in root:
        db = root[db_id]
        if IDatabase.providedBy(db):
            return db

    for _, config in list_or_dict_items(app_settings["storages"]):
        ctype = config.get("type", config["storage"])
        factory = get_adapter(root,
                              IDatabaseManager,
                              name=ctype,
                              args=[config])
        databases = await factory.get_names()
        if db_id in databases:
            return await factory.get_database(db_id)

    raise DatabaseNotFound(db_id)
Exemplo n.º 27
0
async def storage_get(context, request):
    storage_id = request.matchdict["storage_id"]
    config = _get_storage_config(storage_id)
    if config is None:
        raise HTTPNotFound(content={"reason": f"Storage {storage_id}"})
    manager = config.get("type", config["storage"])
    factory = get_adapter(context, IDatabaseManager, name=manager, args=[config])
    return {"id": storage_id, "type": config["storage"], "databases": await factory.get_names()}
Exemplo n.º 28
0
async def get_index_for(context, container=None, request=None):
    im = find_index_manager(parent=context)
    if im is None:
        if container is None:
            if request is None:
                request = get_current_request()
            container = request.container
        im = get_adapter(container, IIndexManager)
    return await im.get_index_name()
Exemplo n.º 29
0
async def test_get_internal_dyn_database(db, guillotina_main):
    storages = app_settings["storages"]
    storage_config = storages["db"]
    factory = get_adapter(
        guillotina_main.root, IDatabaseManager, name=storage_config["storage"], args=[storage_config]
    )
    await factory.create("foobar")
    db_obj = await get_database("foobar")
    assert db_obj.id == "foobar"
Exemplo n.º 30
0
async def delete_db(context, request):
    storage_id = request.matchdict["storage_id"]
    config = _get_storage_config(storage_id)
    if config is None:
        raise HTTPNotFound(content={"reason": f"Storage {storage_id}"})
    manager = config.get("type", config["storage"])
    factory = get_adapter(context, IDatabaseManager, name=manager, args=[config])
    assert request.matchdict["db_id"] in await factory.get_names()
    await factory.delete(request.matchdict["db_id"])
Exemplo n.º 31
0
def find_index_manager(content=None, parent=None):
    if parent is None:
        content = getattr(content, '__parent__', None)
    else:
        content = parent
    while content:
        if IIndexActive.providedBy(content):
            return get_adapter(content, IIndexManager)
        content = getattr(content, '__parent__', None)
Exemplo n.º 32
0
    async def handle_ws_request(self, ws, message):
        method = app_settings['http_methods']['GET']
        path = tuple(p for p in message['value'].split('/') if p)

        from guillotina.traversal import traverse
        obj, tail = await traverse(self.request, self.request.container, path)

        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
        elif not tail:
            view_name = ''
        else:
            raise

        permission = get_utility(IPermission, name='guillotina.AccessContent')

        security = get_adapter(self.request, IInteraction)
        allowed = security.check_permission(permission.id, obj)
        if not allowed:
            return ws.send_str(ujson.dumps({'error': 'Not allowed'}))

        try:
            view = query_multi_adapter((obj, self.request),
                                       method,
                                       name=view_name)
        except AttributeError:
            view = None

        try:
            view.__route__.matches(self.request, tail or [])
        except (KeyError, IndexError):
            view = None

        if view is None:
            return ws.send_str(ujson.dumps({'error': 'Not found'}))

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            return ws.send_str(ujson.dumps({'error': 'No view access'}))

        if hasattr(view, 'prepare'):
            view = (await view.prepare()) or view

        view_result = await view()
        if IAioHTTPResponse.providedBy(view_result):
            raise Exception('Do not accept raw aiohttp exceptions in ws')
        else:
            from guillotina.traversal import apply_rendering
            resp = await apply_rendering(view, self.request, view_result)

        # Return the value, body is always encoded
        ws.send_str(resp.body.decode('utf-8'))

        # Wait for possible value
        self.request.execute_futures()
Exemplo n.º 33
0
async def delete_db(context, request):
    storage_id = request.matchdict['storage_id']
    config = _get_storage_config(storage_id)
    if config is None:
        raise HTTPNotFound(text=f'Storage {storage_id}')
    factory = get_adapter(context, IDatabaseManager,
                          name=config['storage'], args=[config])
    assert request.matchdict['db_id'] in await factory.get_names()
    await factory.delete(request.matchdict['db_id'])
Exemplo n.º 34
0
async def test_get_internal_dyn_database(db, guillotina_main):
    storages = app_settings['storages']
    storage_config = storages['db']
    factory = get_adapter(guillotina_main.root, IDatabaseManager,
                          name=storage_config['storage'],
                          args=[storage_config])
    await factory.create('foobar')
    db_obj = await get_database('foobar')
    assert db_obj.id == 'foobar'
Exemplo n.º 35
0
 async def async_get(self, key, suppress_events=True):
     if key in self._items:
         return self._items[key]
     # check configured storages, see if there is a database registered under this name...
     for _, config in list_or_dict_items(app_settings['storages']):
         manager = config.get('type', config['storage'])
         factory = get_adapter(self, IDatabaseManager,
                               name=manager, args=[config])
         if await factory.exists(key):
             return await factory.get_database(key)
Exemplo n.º 36
0
    def __init__(self, manager, request=None, loop=None):
        self._txn_time = None
        self._tid = None
        self.status = Status.ACTIVE

        # Transaction Manager
        self._manager = manager

        # List of objects added
        # needs to be ordered because content inserted after other might
        # reference each other
        self.added = OrderedDict()
        self.modified = {}
        self.deleted = {}

        # List of (hook, args, kws) tuples added by addBeforeCommitHook().
        self._before_commit = []

        # List of (hook, args, kws) tuples added by addAfterCommitHook().
        self._after_commit = []

        logger.debug("new transaction")

        # Connection to DB
        self._db_conn = None
        # Transaction on DB
        self._db_txn = None
        # Lock on the transaction
        # some databases need to lock during queries
        # this provides a lock for each transaction
        # which would correspond with one connection
        self._lock = asyncio.Lock(loop=loop)

        # we *not* follow naming standards of using "_request" here so
        # get_current_request can magically find us here...
        self.request = request
        self._strategy = get_adapter(self, ITransactionStrategy,
                                     name=manager._storage._transaction_strategy)
        self._cache = get_adapter(self, IStorageCache,
                                  name=manager._storage._cache_strategy)

        self._query_count_start = self._query_count_end = 0
Exemplo n.º 37
0
async def test_storage_exists(db, guillotina_main):
    storages = app_settings['storages']
    storage_config = storages['db']
    factory = get_adapter(guillotina_main.root, IDatabaseManager,
                          name=storage_config['storage'],
                          args=[storage_config])
    assert not await factory.exists('foobar')
    await factory.create('foobar')
    assert await factory.exists('foobar')
    await factory.delete('foobar')
    assert not await factory.exists('foobar')
Exemplo n.º 38
0
async def test_storage_impl(db, guillotina_main):
    storages = app_settings['storages']
    storage_config = storages['db']
    factory = get_adapter(guillotina_main.root, IDatabaseManager,
                          name=storage_config['storage'],
                          args=[storage_config])
    original_size = len(await factory.get_names())
    await factory.create('foobar')
    assert len(await factory.get_names()) == (original_size + 1)
    await factory.delete('foobar')
    assert len(await factory.get_names()) == original_size
Exemplo n.º 39
0
async def delete_db(context, request):
    storage_id = request.matchdict['storage_id']
    config = _get_storage_config(storage_id)
    if config is None:
        raise HTTPNotFound(content={
            'reason': f'Storage {storage_id}'})
    manager = config.get('type', config['storage'])
    factory = get_adapter(context, IDatabaseManager,
                          name=manager, args=[config])
    assert request.matchdict['db_id'] in await factory.get_names()
    await factory.delete(request.matchdict['db_id'])
Exemplo n.º 40
0
 async def get_value(self, field, obj, value):
     if value is None:
         return None
     try:
         value = get_adapter(field, IJSONToValue, args=[value, obj])
         if asyncio.iscoroutine(value):
             value = await value
         field.validate(value)
         return value
     except ComponentLookupError:
         raise ValueDeserializationError(
             field, value, 'Deserializer not found for field')
Exemplo n.º 41
0
def object_converter(field, value, context=None):
    if not isinstance(value, dict):
        raise ValueDeserializationError(field, value, 'Not an object')
    result = {}
    for key, val in value.items():
        if key in field.schema:
            f = field.schema[key]
            if val is not None:
                result[key] = get_adapter(f, IJSONToValue, args=[val, context])
            else:
                result[key] = None
    return result
Exemplo n.º 42
0
    def __init__(self, context, request, field):
        self.context = context
        self.request = request
        self.field = field

        iface = import_class(app_settings['cloud_storage'])
        alsoProvides(field, iface)

        self.file_storage_manager = get_multi_adapter(
            (context, request, field), IFileStorageManager)
        self.dm = get_adapter(
            self.file_storage_manager, IUploadDataManager)
Exemplo n.º 43
0
def schema_compatible(value, schema_or_field, context=None):
    """The schema_compatible function converts any value to guillotina.schema
    compatible data when possible, raising a TypeError for unsupported values.
    This is done by using the ISchemaCompatible converters.
    """
    if value is None:
        return value

    try:
        return get_adapter(schema_or_field, IJSONToValue, args=[value, context])
    except ComponentLookupError:
        raise ValueDeserializationError(
            schema_or_field, value, 'Deserializer not found for field')
Exemplo n.º 44
0
 def get_value(self, value, existing=None, field_type=None):
     if field_type is None:
         if self.field.value_type:
             field_type = self.field.value_type
     if field_type:
         field_type.__name__ = self.field.__name__
         # for sub objects, we need to assign temp object type
         # to work with json schema correctly
         valid_type = namedtuple('temp_assign_type', [self.field.__name__])
         ob = valid_type(**{field_type.__name__: existing})
         value = get_adapter(
             field_type, IJSONToValue, args=[value, ob])
     return value
Exemplo n.º 45
0
async def storage_create_db(context, request):
    storage_id = request.matchdict['storage_id']
    config = _get_storage_config(storage_id)
    if config is None:
        raise HTTPNotFound(content={
            'reason': f'Storage {storage_id}'})
    manager = config.get('type', config['storage'])
    factory = get_adapter(context, IDatabaseManager,
                          name=manager, args=[config])
    data = await request.json()
    name = data['name']
    assert name == re.escape(name)
    await factory.create(data['name'])
Exemplo n.º 46
0
 def __init__(self, manager=None):
     if manager is None:
         manager = MockTransactionManager()
     self._manager = self.manager = manager
     self._tid = 1
     self.modified = {}
     self.request = None
     self._strategy = get_adapter(
         self, ITransactionStrategy,
         name=manager._storage._transaction_strategy)
     self._cache = DummyCache(self)
     self._lock = asyncio.Lock()
     self._status = 'started'
     self._db_conn = None
Exemplo n.º 47
0
async def storage_get(context, request):
    storage_id = request.matchdict['storage_id']
    config = _get_storage_config(storage_id)
    if config is None:
        raise HTTPNotFound(content={
            'reason': f'Storage {storage_id}'
        })
    manager = config.get('type', config['storage'])
    factory = get_adapter(context, IDatabaseManager,
                          name=manager, args=[config])
    return {
        'id': storage_id,
        'type': config['storage'],
        'databases': await factory.get_names()
    }
Exemplo n.º 48
0
def field_converter(field, value, context):
    field.field.__name__ = field.__name__
    if isinstance(value, dict) and 'op' in value:
        if not isinstance(value, dict):
            raise ValueDeserializationError(field, value, 'Not an object')
        operation_name = value.get('op', 'undefined')
        bound_field = field.field.bind(context)
        operation = query_adapter(
            bound_field, field.operation_type, name=operation_name)
        if operation is None:
            raise ValueDeserializationError(
                field, value, f'"{operation_name}" not a valid operation')
        value = operation(context, value.get('value'))
    elif isinstance(value, (dict, list)):
        value = get_adapter(field.field, IJSONToValue, args=[value, context])
    return value
Exemplo n.º 49
0
async def get_database(db_id, root=None):
    if root is None:
        root = get_utility(IApplication, name='root')

    if db_id in root:
        db = root[db_id]
        if IDatabase.providedBy(db):
            return db

    for _, config in list_or_dict_items(app_settings['storages']):
        ctype = config.get('type', config['storage'])
        factory = get_adapter(root, IDatabaseManager, name=ctype, args=[config])
        databases = await factory.get_names()
        if db_id in databases:
            return await factory.get_database(db_id)

    return None
Exemplo n.º 50
0
    async def __call__(self):
        if self.key is _marker:
            # No option to write the root of registry
            return ErrorResponse('InvalidRequest', 'Needs the registry key', status=412)

        data = await self.request.json()
        if 'value' in data:
            value = data['value']
        else:
            value = data

        assert '.' in self.key, 'Registry key must be dotted.iface.name.fieldname'  # noqa
        iface, name = self.key.rsplit('.', 1)
        iface = resolve_dotted_name(iface)

        assert iface is not None, 'Must provide valid registry interface'  # noqa
        try:
            field = iface[name]
        except KeyError:
            return ErrorResponse(
                'DeserializationError',
                'Invalid field name {}'.format(str(name)),
                status=412)

        try:
            new_value = get_adapter((field), IJSONToValue, args=[value, self.context])
        except ComponentLookupError:
            return ErrorResponse(
                'DeserializationError',
                'Cannot deserialize type {}'.format(str(self.field)),
                status=412)

        try:
            self.request.container_settings[self.key] = new_value
        except DeserializationError as e:
            return ErrorResponse(
                'DeserializationError',
                str(e),
                exc=e,
                status=412)

        return Response(status=204)
def test_configuration_machine_allows_overriding():
    from guillotina.configure.config import ConfigurationMachine
    from guillotina.configure import component
    from guillotina.component import adapter, get_adapter
    from zope.interface import implementer, Interface, named

    class IFoo(Interface):
        pass

    @implementer(IFoo)
    class Foo(object):
        pass

    class IBar(Interface):
        pass

    cm = ConfigurationMachine()

    @adapter(IFoo)
    @implementer(IBar)
    @named('bar')
    class _Factory(object):
        def __init__(self, context):
            self.context = context

    class _FactoryOverride(_Factory):
        pass

    component.adapter(cm, (_Factory,))
    cm.execute_actions()
    cm.commit()

    component.adapter(cm, (_FactoryOverride,))
    cm.execute_actions()

    adapter = get_adapter(Foo(), name='bar')
    assert isinstance(adapter, _FactoryOverride)
Exemplo n.º 52
0
    async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]:
        """Main function to resolve a request."""
        security = get_adapter(request, IInteraction)

        if request.method not in app_settings['http_methods']:
            raise HTTPMethodNotAllowed(
                method=request.method,
                allowed_methods=[k for k in app_settings['http_methods'].keys()])
        method = app_settings['http_methods'][request.method]

        try:
            resource, tail = await self.traverse(request)
        except ConflictError:
            # can also happen from connection errors so we bubble this...
            raise
        except Exception as _exc:
            logger.error('Unhandled exception occurred', exc_info=True)
            request.resource = request.tail = None
            request.exc = _exc
            data = {
                'success': False,
                'exception_message': str(_exc),
                'exception_type': getattr(type(_exc), '__name__', str(type(_exc))),  # noqa
            }
            if app_settings.get('debug'):
                data['traceback'] = traceback.format_exc()
            raise HTTPBadRequest(content={
                'reason': data
            })

        request.record('traversed')

        await notify(ObjectLoadedEvent(resource))
        request.resource = resource
        request.tail = tail

        if request.resource is None:
            await notify(TraversalResourceMissEvent(request, tail))
            raise HTTPNotFound(content={
                "reason": 'Resource not found'
            })

        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
        elif not tail:
            view_name = ''

        request.record('beforeauthentication')
        await self.apply_authorization(request)
        request.record('authentication')

        for language in get_acceptable_languages(request):
            translator = query_adapter((resource, request), ILanguage,
                                       name=language)
            if translator is not None:
                resource = translator.translate()
                break

        # Add anonymous participation
        if len(security.participations) == 0:
            security.add(AnonymousParticipation(request))

        # container registry lookup
        try:
            view = query_multi_adapter(
                (resource, request), method, name=view_name)
        except AttributeError:
            view = None

        if view is None and method == IOPTIONS:
            view = DefaultOPTIONS(resource, request)

        # Check security on context to AccessContent unless
        # is view allows explicit or its OPTIONS
        permission = get_utility(IPermission, name='guillotina.AccessContent')
        if not security.check_permission(permission.id, resource):
            # Check if its a CORS call:
            if IOPTIONS != method:
                # Check if the view has permissions explicit
                if view is None or not view.__allow_access__:
                    logger.info(
                        "No access content {content} with {auths}".format(
                            content=resource,
                            auths=str([x.principal.id
                                       for x in security.participations])),
                        request=request)
                    raise HTTPUnauthorized(
                        content={
                            "reason": "You are not authorized to access content",
                            "content": str(resource),
                            "auths": [x.principal.id
                                      for x in security.participations]
                        }
                    )

        if not view and len(tail) > 0:
            # we should have a view in this case because we are matching routes
            await notify(TraversalViewMissEvent(request, tail))
            return None

        request.found_view = view
        request.view_name = view_name
        request.record('viewfound')

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            if IOPTIONS != method:
                raise HTTPUnauthorized(
                    content={
                        "reason": "You are not authorized to view",
                        "content": str(resource),
                        "auths": [x.principal.id
                                  for x in security.participations]
                    }
                )

        try:
            view.__route__.matches(request, tail or [])
        except (KeyError, IndexError):
            await notify(TraversalRouteMissEvent(request, tail))
            return None
        except AttributeError:
            pass

        if hasattr(view, 'prepare'):
            view = (await view.prepare()) or view

        request.record('authorization')

        return MatchInfo(resource, request, view)
Exemplo n.º 53
0
    async def handle_ws_request(self, ws, message):
        method = app_settings['http_methods']['GET']
        try:
            frame_id = message['id']
        except KeyError:
            frame_id = '0'

        parsed = parse.urlparse(message.get('path', message.get('value')))
        path = tuple(p for p in parsed.path.split('/') if p)

        from guillotina.traversal import traverse
        obj, tail = await traverse(self.request, self.request.container, path)

        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
        elif not tail:
            view_name = ''
        else:
            raise

        permission = get_utility(
            IPermission, name='guillotina.AccessContent')

        security = get_adapter(self.request, IInteraction)
        allowed = security.check_permission(permission.id, obj)
        if not allowed:
            return await ws.send_str(ujson.dumps({
                'error': 'Not allowed'
            }))

        try:
            view = query_multi_adapter(
                (obj, self.request), method, name=view_name)
        except AttributeError:
            view = None

        try:
            view.__route__.matches(self.request, tail or [])
        except (KeyError, IndexError):
            view = None

        if view is None:
            return await ws.send_str(ujson.dumps({
                'error': 'Not found',
                'id': frame_id
            }))

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if not security.check_permission(view_permission, view):
            return await ws.send_str(ujson.dumps({
                'error': 'No view access',
                'id': frame_id
            }))

        if hasattr(view, 'prepare'):
            view = (await view.prepare()) or view

        view_result = await view()
        if IAioHTTPResponse.providedBy(view_result):
            raise Exception('Do not accept raw aiohttp exceptions in ws')
        else:
            from guillotina.traversal import apply_rendering
            resp = await apply_rendering(view, self.request, view_result)

        # Return the value, body is always encoded
        response_object = ujson.dumps({
            'data': resp.body.decode('utf-8'),
            'id': frame_id
        })
        await ws.send_str(response_object)

        # Wait for possible value
        self.request.execute_futures()
Exemplo n.º 54
0
 def _callFUT(self, *args, **kw):
     from guillotina.component import get_adapter
     return get_adapter(*args, **kw)