コード例 #1
0
ファイル: traversal.py プロジェクト: nazrulworld/guillotina
async def apply_rendering(view, request, view_result):
    for ct in get_acceptable_content_types(request):
        renderer = query_multi_adapter(
            (view, request), IRenderer, name=ct)
        if renderer is not None:
            break
    else:
        # default to application/json
        renderer = query_multi_adapter(
            (view, request), IRenderer, name='application/json')
    return await renderer(view_result)
コード例 #2
0
ファイル: content.py プロジェクト: nazrulworld/guillotina
def get_object_url(ob: IResource,
                   request: IRequest=None,
                   **kwargs) -> typing.Optional[str]:
    '''
    Generate full url of object.

    :param ob: object to get url for
    :param request: relative path to object you want to retrieve
    '''
    if request is None:
        request = get_current_request()
    url_adapter = query_multi_adapter((ob, request), IAbsoluteURL)
    if url_adapter is not None:
        return url_adapter(**kwargs)
    return None
コード例 #3
0
ファイル: __init__.py プロジェクト: nazrulworld/guillotina
    def get_service_definition(self, resource, tail):
        if tail and len(tail) > 0:
            # convert match lookups
            view_name = routes.path_to_view_name(tail)
        elif not tail:
            view_name = ''
        else:
            return None

        request = get_mocked_request()
        method = (self.options.get('method') or 'get').upper()
        method = app_settings['http_methods'][method]
        # container registry lookup
        try:
            view = query_multi_adapter(
                (resource, request), method, name=view_name)
            return view.__route__.service_configuration
        except AttributeError:
            pass
コード例 #4
0
    async def real_resolve(self, request: IRequest) -> Optional[MatchInfo]:
        """Main function to resolve a request."""
        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, asyncio.CancelledError):
            # 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")

        request.resource = resource
        request.tail = tail

        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")
        authenticated = await authenticate_request(request)
        # Add anonymous participation
        if authenticated is None:
            authenticated = AnonymousUser()
            set_authenticated_user(authenticated)
        request.record("authentication")

        policy = get_security_policy(authenticated)

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

        # 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 policy.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 {auth}".format(
                            content=resource, auth=authenticated.id),
                        request=request,
                    )
                    raise HTTPUnauthorized(
                        content={
                            "reason":
                            "You are not authorized to access content",
                            "content": str(resource),
                            "auth": authenticated.id,
                        })

        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))
            raise HTTPNotFound(
                content={"reason": "object and/or route not found"})

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

        ViewClass = view.__class__
        view_permission = get_view_permission(ViewClass)
        if view_permission is None:
            # use default view permission
            view_permission = app_settings["default_permission"]
        if not policy.check_permission(view_permission, view):
            if IOPTIONS != method:
                raise HTTPUnauthorized(
                    content={
                        "reason": "You are not authorized to view",
                        "content": str(resource),
                        "auth": authenticated.id,
                    })

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

        await notify(ObjectLoadedEvent(resource))

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

        request.record("authorization")

        return MatchInfo(resource, request, view)
コード例 #5
0
async def move(context, request):
    try:
        data = await request.json()
    except Exception:
        data = {}
    destination = data.get('destination')
    if destination is None:
        destination_ob = context.__parent__
    else:
        try:
            destination_ob = await navigate_to(request.container, destination)
        except KeyError:
            destination_ob = None

    if destination_ob is None:
        raise PreconditionFailed(context, 'Could not find destination object')
    old_id = context.id
    if 'new_id' in data:
        new_id = data['new_id']
        context.id = context.__name__ = new_id
    else:
        new_id = context.id

    security = IInteraction(request)
    if not security.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 PreconditionFailed(
            context, f'Destination already has object with the id {new_id}')

    original_parent = context.__parent__

    txn = get_transaction(request)
    cache_keys = txn._cache.get_cache_keys(context, 'deleted')

    data['id'] = new_id
    await notify(
        BeforeObjectMovedEvent(context,
                               original_parent,
                               old_id,
                               destination_ob,
                               new_id,
                               payload=data))

    context.__parent__ = destination_ob
    context._p_register()

    await notify(
        ObjectMovedEvent(context,
                         original_parent,
                         old_id,
                         destination_ob,
                         new_id,
                         payload=data))

    cache_keys += txn._cache.get_cache_keys(context, 'added')
    await txn._cache.delete_all(cache_keys)

    absolute_url = query_multi_adapter((context, request), IAbsoluteURL)
    return {'@url': absolute_url()}
コード例 #6
0
    async def __call__(self):
        """To create a content."""
        data = await self.get_data()
        type_ = data.get('@type', None)
        id_ = data.get('id', None)
        behaviors = data.get('@behaviors', None)

        if not type_:
            raise ErrorResponse('RequiredParam',
                                _("Property '@type' is required"),
                                reason=error_reasons.REQUIRED_PARAM_MISSING,
                                status=412)

        # Generate a temporary id if the id is not given
        new_id = None
        if not id_:
            generator = query_adapter(self.request, IIDGenerator)
            if generator is not None:
                new_id = generator(data)
        else:
            if not isinstance(id_, str) or not valid_id(id_):
                raise ErrorResponse('PreconditionFailed',
                                    str('Invalid id'),
                                    status=412,
                                    reason=error_reasons.INVALID_ID)
            new_id = id_

        user = get_authenticated_user_id(self.request)

        options = {'creators': (user, ), 'contributors': (user, )}
        if 'uid' in data:
            options['_p_oid'] = data.pop('uid')

        # Create object
        try:
            obj = await create_content_in_container(self.context, type_,
                                                    new_id, **options)
        except ValueError as e:
            return ErrorResponse('CreatingObject', str(e), status=412)

        for behavior in behaviors or ():
            obj.add_behavior(behavior)

        # Update fields
        deserializer = query_multi_adapter((obj, self.request),
                                           IResourceDeserializeFromJson)
        if deserializer is None:
            return ErrorResponse('DeserializationError',
                                 'Cannot deserialize type {}'.format(
                                     obj.type_name),
                                 status=412,
                                 reason=error_reasons.DESERIALIZATION_FAILED)

        await deserializer(data, validate_all=True, create=True)

        # Local Roles assign owner as the creator user
        get_owner = get_utility(IGetOwner)
        roleperm = IPrincipalRoleManager(obj)
        owner = await get_owner(obj, user)
        if owner is not None:
            roleperm.assign_role_to_principal('guillotina.Owner', owner)

        data['id'] = obj.id
        await notify(ObjectAddedEvent(obj, self.context, obj.id, payload=data))

        absolute_url = query_multi_adapter((obj, self.request), IAbsoluteURL)

        headers = {
            'Access-Control-Expose-Headers': 'Location',
            'Location': absolute_url()
        }

        serializer = query_multi_adapter((obj, self.request),
                                         IResourceSerializeToJsonSummary)
        response = await serializer()
        return Response(content=response, status=201, headers=headers)
コード例 #7
0
async def test_view_registered_for_sub_path_matching(dummy_guillotina,
                                                     dummy_request):
    view = query_multi_adapter((dummy_guillotina.root, dummy_request),
                               name='@match//')
    assert view is not None
コード例 #8
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, task_vars.container.get(), 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_security_policy()
        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()
コード例 #9
0
ファイル: ws.py プロジェクト: terapyon/guillotina
    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()
コード例 #10
0
    async def __call__(self):
        """To create a content."""
        data = await self.get_data()
        type_ = data.get("@type", None)
        id_ = data.get("id", None)
        behaviors = data.get("@behaviors", None)

        if not type_:
            raise ErrorResponse(
                "RequiredParam",
                _("Property '@type' is required"),
                reason=error_reasons.REQUIRED_PARAM_MISSING,
                status=412,
            )

        id_checker = get_adapter(self.context, IIDChecker)
        # Generate a temporary id if the id is not given
        new_id = None
        if not id_:
            generator = query_adapter(self.request, IIDGenerator)
            if generator is not None:
                new_id = await apply_coroutine(generator, data)
                if isinstance(new_id, str) and not await id_checker(new_id, type_):
                    raise ErrorResponse(
                        "PreconditionFailed",
                        "Invalid id: {}".format(new_id),
                        status=412,
                        reason=error_reasons.INVALID_ID,
                    )
        else:
            if not isinstance(id_, str) or not await id_checker(id_, type_):
                raise ErrorResponse(
                    "PreconditionFailed",
                    "Invalid id: {}".format(id_),
                    status=412,
                    reason=error_reasons.INVALID_ID,
                )
            new_id = id_

        user = get_authenticated_user_id()

        options = {"creators": (user,), "contributors": (user,)}
        if "uid" in data:
            options["__uuid__"] = data.pop("uid")

        # Create object
        try:
            obj = await create_content_in_container(
                self.context, type_, new_id, check_constraints=True, **options
            )
        except ValueError as e:
            return ErrorResponse("CreatingObject", str(e), status=412)

        for behavior in behaviors or ():
            obj.add_behavior(behavior)

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

        await deserializer(data, validate_all=True, create=True)

        # Local Roles assign owner as the creator user
        get_owner = get_utility(IGetOwner)
        roleperm = IPrincipalRoleManager(obj)
        owner = await get_owner(obj, user)
        if owner is not None:
            roleperm.assign_role_to_principal("guillotina.Owner", owner)

        data["id"] = obj.id
        await notify(ObjectAddedEvent(obj, self.context, obj.id, payload=data))

        headers = {"Access-Control-Expose-Headers": "Location", "Location": get_object_url(obj, self.request)}

        serializer = query_multi_adapter((obj, self.request), IResourceSerializeToJsonSummary)
        response = await serializer()
        return Response(content=response, status=201, headers=headers)
コード例 #11
0
ファイル: test__api.py プロジェクト: www3838438/guillotina
 def _callFUT(self, *args, **kw):
     from guillotina.component import query_multi_adapter
     return query_multi_adapter(*args, **kw)
コード例 #12
0
ファイル: ws.py プロジェクト: nazrulworld/guillotina
    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()
コード例 #13
0
ファイル: traversal.py プロジェクト: nazrulworld/guillotina
    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)