Exemple #1
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)
Exemple #2
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)
    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'})

        container = await create_content(data['@type'],
                                         id=data['id'],
                                         title=data['title'],
                                         description=data['description'])

        # Special case we don't want the parent pointer
        container.__name__ = data['id']

        await self.context.async_set(data['id'], container)
        await container.install()

        self.request._container_id = container.__name__
        self.request.container = container

        user = get_authenticated_user_id(self.request)

        # Local Roles assign owner as the creator user
        roleperm = IPrincipalRoleManager(container)
        roleperm.assign_role_to_principal('guillotina.Owner', user)

        await notify(
            ObjectAddedEvent(container,
                             self.context,
                             container.__name__,
                             payload=data))

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

        return Response(content=resp, headers=headers)
Exemple #4
0
    async def tus_patch(self, *args, **kwargs):
        await self.dm.load()
        to_upload = None
        if "CONTENT-LENGTH" in self.request.headers:
            # header is optional, we'll be okay with unknown lengths...
            to_upload = int(self.request.headers["CONTENT-LENGTH"])

        if "UPLOAD-LENGTH" in self.request.headers:
            if self.dm.get("deferred_length"):
                size = int(self.request.headers["UPLOAD-LENGTH"])
                await self.dm.update(size=size)

        if "UPLOAD-OFFSET" in self.request.headers:
            offset = int(self.request.headers["UPLOAD-OFFSET"])
        else:
            raise HTTPPreconditionFailed(
                content={"reason": "No upload-offset header"})

        ob_offset = self.dm.get("offset")
        if offset != ob_offset:
            raise HTTPConflict(
                content={
                    "reason":
                    f"Current upload offset({offset}) does not match "
                    f"object offset {ob_offset}"
                })

        read_bytes = await self.file_storage_manager.append(
            self.dm, self._iterate_request_data(), offset)

        if to_upload and read_bytes != to_upload:  # pragma: no cover
            # check length matches if provided
            raise HTTPPreconditionFailed(
                content={
                    "reason": "Upload size does not match what was provided"
                })
        await self.dm.update(offset=offset + read_bytes)

        headers = {
            "Upload-Offset":
            str(self.dm.get_offset()),
            "Tus-Resumable":
            "1.0.0",
            "Access-Control-Expose-Headers":
            ",".join(["Upload-Offset", "Tus-Resumable",
                      "Tus-Upload-Finished"]),
        }

        if self.dm.get("size") is not None and self.dm.get_offset(
        ) >= self.dm.get("size"):
            await self.file_storage_manager.finish(self.dm)
            await self.dm.finish()
            headers["Tus-Upload-Finished"] = "1"
        else:
            await self.dm.save()

        return Response(headers=headers)
Exemple #5
0
    async def tus_patch(self, *args, **kwargs):
        await self.dm.load()
        to_upload = None
        if 'CONTENT-LENGTH' in self.request.headers:
            # header is optional, we'll be okay with unknown lengths...
            to_upload = int(self.request.headers['CONTENT-LENGTH'])

        if 'UPLOAD-LENGTH' in self.request.headers:
            if self.dm.get('deferred_length'):
                size = int(self.request.headers['UPLOAD-LENGTH'])
                await self.dm.update(size=size)

        if 'UPLOAD-OFFSET' in self.request.headers:
            offset = int(self.request.headers['UPLOAD-OFFSET'])
        else:
            raise HTTPPreconditionFailed(
                content={'reason': 'No upload-offset header'})

        ob_offset = self.dm.get('offset')
        if offset != ob_offset:
            raise HTTPConflict(
                content={
                    'reason':
                    f'Current upload offset({offset}) does not match '
                    f'object offset {ob_offset}'
                })

        read_bytes = await self.file_storage_manager.append(
            self.dm, self._iterate_request_data(), offset)

        if to_upload and read_bytes != to_upload:
            # check length matches if provided
            raise HTTPPreconditionFailed(
                content={
                    'reason': 'Upload size does not match what was provided'
                })
        await self.dm.update(offset=offset + read_bytes)

        headers = {
            'Upload-Offset':
            str(self.dm.get_offset()),
            'Tus-Resumable':
            '1.0.0',
            'Access-Control-Expose-Headers':
            ','.join(['Upload-Offset', 'Tus-Resumable', 'Tus-Upload-Finished'])
        }

        if self.dm.get('size') is not None and self.dm.get_offset(
        ) >= self.dm.get('size'):
            await self.file_storage_manager.finish(self.dm)
            await self.dm.finish()
            headers['Tus-Upload-Finished'] = '1'
        else:
            await self.dm.save()

        return Response(headers=headers)
async def post_user(context, request):
    data = await request.json()
    try:
        jsonschema.validate(
            data, app_settings['json_schema_definitions']['HydraUser'])
    except (jsonschema.ValidationError,
            jsonschema.SchemaError) as e:
        raise HTTPPreconditionFailed(content={
            'message': e.message
        })

    try:
        data = await utils.create_user(**data)
    except asyncpg.exceptions.UniqueViolationError:
        raise HTTPConflict(content={
            'reason': 'user already exists'
        })
    del data['password']
    data['@id'] = str(request.url.with_path(f'/@users/{data["id"]}'))
    return data
Exemple #7
0
 async def _handle(self, request, retries=0):
     aiotask_context.set('request', request)
     try:
         return await super()._handle(request)
     except (ConflictError, TIDConflictError) as e:
         if app_settings.get('conflict_retry_attempts', 3) > retries:
             label = 'DB Conflict detected'
             if isinstance(e, TIDConflictError):
                 label = 'TID Conflict Error detected'
             tid = getattr(getattr(request, '_txn', None), '_tid', 'not issued')
             logger.debug(
                 f'{label}, retrying request, tid: {tid}, retries: {retries + 1})',
                 exc_info=True)
             request._retry_attempt = retries + 1
             request.clear_futures()
             return await self._handle(request, retries + 1)
         logger.error(
             'Exhausted retry attempts for conflict error on tid: {}'.format(
                 getattr(getattr(request, '_txn', None), '_tid', 'not issued')
             ))
         return HTTPConflict()
Exemple #8
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'
            })

        container = await create_content(
            data['@type'],
            id=data['id'],
            title=data['title'],
            description=data['description'])

        # Special case we don't want the parent pointer
        container.__name__ = data['id']

        await self.context.async_set(data['id'], container)
        await container.install()

        self.request._container_id = container.__name__
        self.request.container = container

        user = get_authenticated_user_id(self.request)

        # Local Roles assign owner as the creator user
        roleperm = IPrincipalRoleManager(container)
        roleperm.assign_role_to_principal('guillotina.Owner', user)

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

        for addon in data.get('@addons') or []:
            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)
            await addons.install(container, addon)

        await notify(ObjectAddedEvent(container, self.context, container.__name__,
                                      payload=data))

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

        return Response(content=resp, headers=headers)
Exemple #9
0
async def move(
    context: IResource,
    destination: Optional[Union[IResource, str]] = None,
    new_id: Optional[str] = None,
    check_permission: bool = True,
) -> None:
    if destination is None:
        destination_ob = context.__parent__
    else:
        if isinstance(destination, str):
            destination_ob = None
            if destination.startswith("/"):
                container = task_vars.container.get()
                if container is not None:
                    try:
                        destination_ob = await navigate_to(container, destination)
                    except KeyError:
                        pass
            else:
                try:
                    destination_ob = await get_object_by_uid(destination)
                except KeyError:
                    pass
        else:
            destination_ob = destination

    if destination_ob is None:
        raise PreconditionFailed(context, "Could not find destination object")
    if destination_ob.__uuid__ == context.__uuid__:
        raise PreconditionFailed(context, "You can not move object to itself")
    if destination_ob.__uuid__ == context.__parent__.__uuid__ and new_id == context.id:
        raise PreconditionFailed(context, "Object already belongs to this parent with same id")

    txn = get_transaction()
    if txn is not None:
        cache_keys = txn._cache.get_cache_keys(context, "deleted")

    old_id = context.id
    if new_id is None:
        new_id = context.id
    else:
        id_checker = get_adapter(context, IIDChecker)
        if not isinstance(new_id, str) or not await id_checker(new_id, context.type_name):
            raise PreconditionFailed(new_id, "Invalid id")

    if check_permission:
        policy = get_security_policy()
        if not policy.check_permission("guillotina.AddContent", destination_ob):
            raise PreconditionFailed(
                context, "You do not have permission to add content to the destination object"
            )

    if await destination_ob.async_contains(new_id):
        raise HTTPConflict(content={"reason": f'Destination already has object with the id "{new_id}"'})

    original_parent = context.__parent__

    await notify(
        BeforeObjectMovedEvent(
            context,
            original_parent,
            old_id,
            destination_ob,
            new_id,
            payload={"id": new_id, "destination": destination},
        )
    )

    if new_id != old_id:
        context.id = context.__name__ = new_id
    context.__parent__ = destination_ob
    context.register()

    await notify(
        ObjectMovedEvent(
            context,
            original_parent,
            old_id,
            destination_ob,
            new_id,
            payload={"id": new_id, "destination": destination},
        )
    )

    if txn is not None:
        cache_keys += txn._cache.get_cache_keys(context, "added")
        await txn._cache.delete_all(cache_keys)