예제 #1
0
async def themecss(context, request):

    registry = await get_registry()
    settings = registry.for_interface(ICustomTheme)
    resp = Response(status=200)
    resp.content_type = "text/css"
    disposition = 'filename="style.css"'
    resp.headers["CONTENT-DISPOSITION"] = disposition
    resp.content_length = len(settings["css"])
    await resp.prepare(request)
    await resp.write(settings["css"].encode(), eof=True)
    return resp
예제 #2
0
async def default_delete(context, request):
    data = await request.json()
    behavior = data.get('behavior', None)
    factory = get_cached_factory(context.type_name)
    behavior_class = resolve_dotted_name(behavior)
    if behavior_class is not None:
        if behavior_class in factory.behaviors:
            return Response(status=201)
    if behavior not in context.__behaviors__:
        return Response(status=201)
    context.remove_behavior(behavior)
    return {}
예제 #3
0
async def delete_behavior(context, behavior):
    factory = get_cached_factory(context.type_name)
    behavior_class = resolve_dotted_name(behavior)
    if behavior_class is not None:
        if behavior_class in factory.behaviors:
            return Response(content={
                'reason':
                'Behaviors defined on this type must be present and cannot be dynamically removed'
            },
                            status=412)
    if behavior not in context.__behaviors__:
        return Response(content={'reason': 'Not in behaviors'}, status=412)
    context.remove_behavior(behavior)
    return {}
예제 #4
0
async def delete_behavior(context, behavior):
    factory = get_cached_factory(context.type_name)
    behavior_class = resolve_dotted_name(behavior)
    if behavior_class is not None:
        if behavior_class in factory.behaviors:
            return Response(content={
                'reason': 'Not not remove this type of behavior'
            }, status=412)
    if behavior not in context.__behaviors__:
        return Response(content={
            'reason': 'Not in behaviors'
        }, status=412)
    context.remove_behavior(behavior)
    return {}
예제 #5
0
async def default_patch(context, request):
    data = await request.json()
    behavior = data.get('behavior', None)
    try:
        behavior_class = resolve_dotted_name(behavior)
    except ModuleNotFoundError:
        behavior_class = None
    if behavior_class is None:
        return Response(status=404)
    factory = get_cached_factory(context.type_name)
    if behavior_class in factory.behaviors:
        return Response(status=201)
    if behavior in context.__behaviors__:
        return Response(status=201)
    context.add_behavior(behavior)
    return {}
예제 #6
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)
예제 #7
0
    async def __call__(self):
        """ data input : { 'interface': 'INTERFACE' }"""
        if not hasattr(self.request, 'container_settings'):
            return ErrorResponse('BadRequest',
                                 _("Not in a container request"),
                                 status=412)

        data = await self.request.json()
        interface = data.get('interface', None)
        initial_values = data.get('initial_values', {})
        if interface is None:
            return ErrorResponse('InvalidRequest',
                                 'Non existent Interface',
                                 status=412)

        registry = self.request.container_settings
        iObject = import_class(interface)
        registry.register_interface(iObject)
        config = registry.for_interface(iObject)

        # Initialize values
        # If its defined on the guillotina.schema default will not be overwritten
        #  you will need to PATCH
        for key, field in get_fields(iObject).items():
            if key in initial_values and getattr(config, key,
                                                 _marker) == _marker:
                # We don't have a value
                config[key] = initial_values[key]

        return Response(status=201)
예제 #8
0
 async def __call__(self):
     if app_settings.get("graphql", {}).get("enable_playground") is True:
         return Response(
             content=PLAYGROUND_HTML,
             headers={"content-type": "text/html"},
         )
     raise HTTPNotFound()
예제 #9
0
    async def __call__(self):
        """ data input : { 'interface': 'INTERFACE' }"""
        registry = await get_registry()
        if registry is None:
            return ErrorResponse("BadRequest",
                                 _("Not in a container request"),
                                 status=412)

        data = await self.request.json()
        interface = data.get("interface", None)
        initial_values = data.get("initial_values", {})
        if interface is None:
            return ErrorResponse("InvalidRequest",
                                 "Non existent Interface",
                                 status=412)

        iObject = import_class(interface)
        registry.register_interface(iObject)
        config = registry.for_interface(iObject)

        # Initialize values
        # If its defined on the guillotina.schema default will not be overwritten
        #  you will need to PATCH
        for key, field in get_fields(iObject).items():
            if key in initial_values and getattr(config, key,
                                                 _marker) == _marker:
                # We don't have a value
                config[key] = initial_values[key]

        await notify(
            RegistryEditedEvent(self.context, registry,
                                {interface: initial_values}))

        return Response(status=201)
예제 #10
0
 async def tus_options(self, *args, **kwargs):
     resp = Response(headers={
         'Tus-Resumable': '1.0.0',
         'Tus-Version': '1.0.0',
         'Tus-Extension': 'creation-defer-length'
     })
     return resp
예제 #11
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)
예제 #12
0
async def add_comment(context, request):
    payload = await request.json()
    bhr = ICMSBehavior(context)
    if not bhr.allow_discussion:
        raise HTTPUnauthorized(content={"text": "Not available option"})
    await bhr.load()

    if bhr.comments is None:
        bhr.comments = {}

    user_id = get_authenticated_user_id()
    comment_uuid = uuid.uuid4().hex
    bhr.comments[comment_uuid] = {
        "@parent": None,
        "author_name": None,
        "author_username": user_id,
        "creation_date": datetime.now().isoformat(),
        "in_reply_to": None,
        "is_deletable": True,
        "is_editable": True,
        "modification_date": datetime.now().isoformat(),
        "text": {
            "data": payload.get("text", ""),
            "mime-type": "text/plain"
        },
        "user_notification": None,
    }

    bhr.register()

    url = getMultiAdapter((context, request), IAbsoluteURL)()
    headers = {"Location": url + "/@comments/" + comment_uuid}
    return Response(status=204, headers=headers)
예제 #13
0
async def delete_comment(context, request):
    comment_id = request.matchdict["comment_id"]
    bhr = ICMSBehavior(context)
    if not bhr.allow_discussion:
        raise HTTPUnauthorized(content={"text": "Not available option"})
    await bhr.load()

    if comment_id not in bhr.comments:
        raise ErrorResponse("InvalidComment",
                            "This comment does not exist",
                            status=412)

    user_id = get_authenticated_user_id()
    comment = bhr.comments[comment_id]

    # TODO: We need ?
    policy = get_security_policy()
    if user_id != comment["author_username"] or not policy.check_permission(
            "guillotina.DeleteAllComments", context):
        raise HTTPUnauthorized(
            content={"text": "Not the author or permission"})

    list_to_delete = [comment_id]
    delete_from_list(bhr.comments, list_to_delete)
    for comment in list_to_delete:
        del bhr.comments[comment]

    bhr.register()

    return Response(status=204)
예제 #14
0
async def modify_comment(context, request):
    payload = await request.json()
    comment_id = request.matchdict["comment_id"]
    bhr = ICMSBehavior(context)
    if not bhr.allow_discussion:
        raise HTTPUnauthorized(content={"text": "Not available option"})
    await bhr.load()

    if comment_id not in bhr.comments:
        raise ErrorResponse("InvalidComment",
                            "This comment does not exist",
                            status=412)

    user_id = get_authenticated_user_id()
    comment = bhr.comments[comment_id]

    # TODO: We need ?
    if user_id != comment["author_username"]:
        raise HTTPUnauthorized(content={"text": "Not the author"})

    comment["text"]["data"] = payload.get("text", "")
    comment["modification_date"] = datetime.now().isoformat()

    bhr.register()

    url = getMultiAdapter((context, request), IAbsoluteURL)()
    headers = {"Location": url + "/@comments/" + comment_id}
    return Response(status=204, headers=headers)
예제 #15
0
파일: content.py 프로젝트: qemm/guillotina
    async def __call__(self):
        data = await self.get_data()

        behaviors = data.get("@behaviors", None)
        for behavior in behaviors or ():
            try:
                self.context.add_behavior(behavior)
            except (TypeError, ComponentLookupError):
                return HTTPPreconditionFailed(
                    content={"message": f"{behavior} is not a valid behavior", "behavior": behavior}
                )

        deserializer = query_multi_adapter((self.context, self.request), IResourceDeserializeFromJson)
        if deserializer is None:
            raise ErrorResponse(
                "DeserializationError",
                "Cannot deserialize type {}".format(self.context.type_name),
                status=412,
                reason=error_reasons.DESERIALIZATION_FAILED,
            )

        await notify(BeforeObjectModifiedEvent(self.context, payload=data))

        await deserializer(data)

        await notify(ObjectModifiedEvent(self.context, payload=data))

        return Response(status=204)
예제 #16
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)

        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)
예제 #17
0
 async def tus_options(self, *args, **kwargs):
     resp = Response(
         headers={
             "Tus-Resumable": "1.0.0",
             "Tus-Version": "1.0.0",
             "Tus-Extension": "creation-defer-length",
         })
     return resp
예제 #18
0
async def default_patch(context, request):
    data = await request.json()
    behavior = data.get("behavior", None)
    try:
        behavior_class = resolve_dotted_name(behavior)
    except ModuleNotFoundError:
        behavior_class = None
    if behavior_class is None:
        return Response(content={"reason": "Could not find behavior"},
                        status=404)
    factory = get_cached_factory(context.type_name)
    if behavior_class in factory.behaviors:
        return Response(content={"reason": "Already in behaviors"}, status=412)
    if behavior in context.__behaviors__:
        return Response(content={"reason": "Already in behaviors"}, status=412)
    context.add_behavior(behavior)
    return {}
예제 #19
0
async def test_raise_response(container_requester):
    async with container_requester as requester:
        with mock.patch("guillotina.asgi.Guillotina.request_handler") as handle_mock:  # noqa
            f = asyncio.Future()
            f.set_result(None)
            handle_mock.return_value = f
            handle_mock.side_effect = Response(status=200)
            _, status = await requester("GET", "/db")
            assert status == 200
예제 #20
0
 async def __call__(self):
     """Apply CORS on the OPTIONS view."""
     headers = await self.preflight()
     resp = await self.render()
     if IResponse.providedBy(resp):
         headers.update(resp.headers)
         resp.headers = headers
         return resp
     return Response(content=resp, headers=headers)
예제 #21
0
파일: api.py 프로젝트: ebrehault/nexus
async def run_editor(context, request):
    editor_view = await get_object_by_path('/abfab/editor/editor.svelte')
    return Response(content=wrap_component(request, editor_view,
                                           './@edit-data', 'text'),
                    status=200,
                    headers={
                        'Cross-Origin-Opener-Policy': 'same-origin',
                        'Cross-Origin-Embedder-Policy': 'require-corp',
                    })
예제 #22
0
파일: files.py 프로젝트: sunbit/guillotina
    async def serve_file(self, fi):
        filepath = str(fi.file_path.absolute())
        filename = fi.file_path.name
        with open(filepath, "rb") as f:
            resp = Response(status=200)
            resp.content_type, _ = mimetypes.guess_type(filename)

            disposition = 'filename="{}"'.format(filename)
            if "text" not in (resp.content_type or ""):
                disposition = "attachment; " + disposition

            resp.headers["CONTENT-DISPOSITION"] = disposition

            data = f.read()
            resp.content_length = len(data)
            await resp.prepare(self.request)
            await resp.write(data, eof=True)
            return resp
예제 #23
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)
예제 #24
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)
예제 #25
0
 async def tus_head(self, *args, **kwargs):
     await self.dm.load()
     head_response = {
         'Upload-Offset': str(self.dm.get_offset()),
         'Tus-Resumable': '1.0.0',
         'Access-Control-Expose-Headers': 'Upload-Offset,Tus-Resumable'
     }
     if self.dm.get('size'):
         head_response['Upload-Length'] = str(self.dm.get('size'))
     return Response(headers=head_response)
예제 #26
0
 async def tus_head(self, *args, **kwargs):
     await self.dm.load()
     head_response = {
         "Upload-Offset": str(self.dm.get_offset()),
         "Tus-Resumable": "1.0.0",
         "Access-Control-Expose-Headers": "Upload-Offset,Tus-Resumable,Upload-Length",
     }
     if self.dm.get("size"):
         head_response["Upload-Length"] = str(self.dm.get("size"))
     else:
         head_response["Upload-Length"] = "0"
     return Response(headers=head_response)
예제 #27
0
    async def handler(self, request):
        """Main handler function"""
        request._view_error = False
        await notify(BeforeRenderViewEvent(request, self.view))
        request.record("viewrender")

        try:
            # We try to avoid collisions on the same instance of
            # guillotina
            view_result = await self.view()
            if app_settings["check_writable_request"](request):
                await commit(warn=False)
            else:
                await abort()
        except (ConflictError, TIDConflictError):
            await abort()
            # bubble this error up
            raise
        except response.Response as exc:
            await abort()
            view_result = exc
            request._view_error = True
        except Exception:
            await abort()
            raise

        request.record("viewrendered")

        resp = view_result
        if resp is None:
            resp = Response(status=200)
        if not IResponse.providedBy(resp) or not resp.prepared:
            resp = await apply_rendering(self.view, self.request, resp)
            request.record("renderer")
            resp = await apply_cors(request, resp)

        if not request._view_error:
            task = request.execute_futures()
        else:
            task = request.execute_futures("failure")

        if task is not None:
            await self.wait(request, resp, task)

        self.debug(request, resp)

        request.record("finish")

        del self.view
        del self.resource
        request.clear_futures()
        return resp
예제 #28
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, name = self.key.rsplit(".", 1)
        iface = resolve_dotted_name(iface_name)

        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:
            registry = await get_registry()
            registry[self.key] = new_value
        except (DeserializationError, ValueDeserializationError) as e:
            return ErrorResponse("DeserializationError",
                                 str(e),
                                 exc=e,
                                 status=412)

        await notify(
            RegistryEditedEvent(self.context, registry,
                                {iface_name: {
                                    name: value
                                }}))

        return Response(status=204)
예제 #29
0
    async def __call__(self):
        registry = await get_registry()
        settings = registry.for_interface(IImagingSettings)
        scale_name = self.request.matchdict["scale"]
        allowed_sizes = settings["allowed_sizes"]
        if scale_name not in allowed_sizes:
            raise HTTPNotFound(
                content={"reason": f"{scale_name} is not supported"})
        file = self.field.get(self.field.context or self.context)
        if file is None:
            raise HTTPNotFound(
                content={
                    "message": "File or custom filename required to download"
                })

        adapter = get_multi_adapter((self.context, self.request, self.field),
                                    IFileManager)
        data = b""
        async for chunk in adapter.iter_data():
            data += chunk

        width, _, height = allowed_sizes[scale_name].partition(":")

        result, format_, size = scaleImage(
            data,
            int(width),
            int(height),
            quality=settings["quality"],
            direction="thumbnail",
        )

        cors_renderer = app_settings["cors_renderer"](self.request)
        headers = await cors_renderer.get_headers()
        headers.update({
            "CONTENT-DISPOSITION":
            'attachment; filename="{}"'.format(file.filename)
        })

        download_resp = Response(
            status=200,
            headers=headers,
            content_type=f"image/{format_}",
            content_length=len(result),
        )
        await download_resp.prepare(self.request)

        await download_resp.write(result)
        await download_resp.write(eof=True)
        return download_resp
예제 #30
0
    async def __call__(self, value) -> Response:
        """
        Value can be:
        - Guillotina response object
        - serializable value
        """
        if IResponse.providedBy(value):
            resp = cast(Response, value)
            if resp.content is not None:
                resp.set_body(self.get_body(resp.content), self.content_type)
            return resp

        return Response(body=self.get_body(value) or b"",
                        status=200,
                        content_type=self.content_type)