Пример #1
0
    async def handler(self, request):
        """Main handler function for aiohttp."""
        if request.method in WRITING_VERBS:
            try:
                async with locked(self.resource):
                    request._db_write_enabled = True
                    txn = request.conn.transaction_manager.begin(request)
                    # We try to avoid collisions on the same instance of
                    # plone.server
                    view_result = await self.view()
                    if isinstance(view_result, ErrorResponse) or \
                            isinstance(view_result, UnauthorizedResponse):
                        # If we don't throw an exception and return an specific
                        # ErrorReponse just abort
                        await abort(txn, request)
                    else:
                        await commit(txn, request)

            except Unauthorized as e:
                await abort(txn, request)
                view_result = generate_unauthorized_response(e, request)
            except ConflictError as e:
                view_result = generate_error_response(
                    e, request, 'ConflictDB', 409)
            except Exception as e:
                await abort(txn, request)
                view_result = generate_error_response(
                    e, request, 'ServiceError')
        else:
            try:
                view_result = await self.view()
            except Unauthorized as e:
                view_result = generate_unauthorized_response(e, request)
            except Exception as e:
                view_result = generate_error_response(e, request, 'ViewError')

        # If we want to close the connection after the request
        if SHARED_CONNECTION is False and hasattr(request, 'conn'):
            request.conn.close()

        futures_to_wait = request._futures.values()
        if futures_to_wait:
            await asyncio.gather(futures_to_wait)

        # Make sure its a Response object to send to renderer
        if not isinstance(view_result, Response):
            view_result = Response(view_result)
        elif view_result is None:
            # Always provide some response to work with
            view_result = Response({})

        # Apply cors if its needed
        cors_headers = apply_cors(request)
        cors_headers.update(view_result.headers)
        view_result.headers = cors_headers

        return await self.rendered(view_result)
Пример #2
0
    async def __call__(self):
        headers = {}
        allowed_headers = ['Content-Type'
                           ] + app_settings['cors']['allow_headers']
        headers['Access-Control-Allow-Headers'] = ','.join(allowed_headers)
        headers['Access-Control-Allow-Methods'] = ','.join(
            app_settings['cors']['allow_methods'])
        headers['Access-Control-Max-Age'] = str(
            app_settings['cors']['max_age'])
        headers['Access-Control-Allow-Origin'] = ','.join(
            app_settings['cors']['allow_origin'])
        headers['Access-Control-Allow-Credentials'] = 'True'
        headers['Access-Control-Expose-Headers'] = \
            ', '.join(app_settings['cors']['allow_headers'])

        oauth_utility = getUtility(IOAuth)
        if 'client_id' in self.request.GET:
            client_id = self.request.GET['client_id']
        else:
            client_id = oauth_utility._client_id

        if hasattr(self.request, '_site_id'):
            scope = self.request._site_id
        else:
            scope = self.request.GET['scope']

        result = await oauth_utility.auth_code([scope], client_id)
        resp = {'auth_code': result}
        return Response(response=resp, headers=headers, status=200)
Пример #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(iface)
        field = iface[name]

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

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

        return Response(response={}, status=204)
Пример #4
0
 async def tus_options(self):
     resp = Response(headers=multidict.MultiDict({
         'Tus-Resumable': '1.0.0',
         'Tus-Version': '1.0.0',
         'Tus-Max-Size': '1073741824',
         'Tus-Extension': 'creation,expiration'
     }))
     return resp
Пример #5
0
 async def __call__(self):
     """Apply CORS on the OPTIONS view."""
     headers = await self.preflight()
     resp = await self.render()
     if isinstance(resp, Response):
         headers.update(resp.headers)
         resp.headers = headers
         return resp
     return Response(response=resp, headers=headers, status=200)
Пример #6
0
    async def tus_create(self):

        # This only happens in tus-java-client, redirect this POST to a PATCH
        if self.request.headers.get('X-HTTP-Method-Override') == 'PATCH':
            return await self.tus_patch()

        file = self.field.get(self.context)
        if file is None:
            file = S3File(contentType=self.request.content_type)
            self.field.set(self.context, file)
        if 'CONTENT-LENGTH' in self.request.headers:
            file._current_upload = int(self.request.headers['CONTENT-LENGTH'])
        else:
            file._current_upload = 0

        if 'UPLOAD-LENGTH' in self.request.headers:
            file._size = int(self.request.headers['UPLOAD-LENGTH'])
        else:
            raise AttributeError('We need upload-length header')

        if 'UPLOAD-MD5' in self.request.headers:
            file._md5hash = self.request.headers['UPLOAD-MD5']

        if 'UPLOAD-EXTENSION' in self.request.headers:
            file._extension = self.request.headers['UPLOAD-EXTENSION']

        if 'TUS-RESUMABLE' not in self.request.headers:
            raise AttributeError('Its a TUS needs a TUS version')

        if 'UPLOAD-METADATA' not in self.request.headers:
            file.filename = uuid.uuid4().hex
        else:
            filename = self.request.headers['UPLOAD-METADATA']
            file.filename = base64.b64decode(
                filename.split()[1]).decode('utf-8')

        await file.initUpload(self.context)
        if file.size < MIN_UPLOAD_SIZE:
            file._one_tus_shoot = True
        else:
            file._one_tus_shoot = False
        # Location will need to be adapted on aiohttp 1.1.x
        resp = Response(
            headers=multidict.MultiDict({
                'Location':
                IAbsoluteURL(self.context, self.request)() + '/@tusupload/' +
                self.field.__name__,  # noqa
                'Tus-Resumable':
                '1.0.0',
                'Access-Control-Expose-Headers':
                'Location,Tus-Resumable'
            }),
            status=201)
        return resp
Пример #7
0
 async def tus_head(self):
     file = self.field.get(self.context)
     if file is None:
         raise KeyError('No file on this context')
     head_response = {
         'Upload-Offset': str(file.actualSize()),
         'Tus-Resumable': '1.0.0',
         'Access-Control-Expose-Headers': 'Upload-Offset,Upload-Length,Tus-Resumable'
     }
     if file.size:
         head_response['Upload-Length'] = str(file._size)
     resp = Response(headers=multidict.MultiDict(head_response))
     return resp
Пример #8
0
 async def __call__(self):
     user = get_authenticated_user(self.request)
     serializer = queryMultiAdapter((user, self.request),
                                    IResourceSerializeToJson)
     if serializer:
         data = serializer()
     else:
         data = {}
     data.update({
         'id': user.id,
         'roles': user._roles,
         'groups': getattr(user, '_groups', [])
     })
     return Response(data)
Пример #9
0
    async def tus_patch(self):
        file = self.field.get(self.context)
        if 'CONTENT-LENGTH' in self.request.headers:
            to_upload = int(self.request.headers['CONTENT-LENGTH'])
        else:
            raise AttributeError('No content-length header')

        if 'UPLOAD-OFFSET' in self.request.headers:
            file._current_upload = int(self.request.headers['UPLOAD-OFFSET'])
        else:
            raise AttributeError('No upload-offset header')

        try:
            data = await self.request.content.readexactly(to_upload)
        except asyncio.IncompleteReadError as e:
            data = e.partial
        if file.one_tus_shoot:
            # One time shoot
            if file._block > 1:
                raise AttributeError('You should push 5Mb blocks AWS')
            await file.oneShotUpload(self.context, data)
            expiration = datetime.now() + timedelta(days=365)
        else:
            count = 0
            while data:
                resp = await file.appendData(data)
                count += 1

                try:
                    data = await self.request.content.readexactly(CHUNK_SIZE
                                                                  )  # noqa
                except asyncio.IncompleteReadError as e:
                    data = e.partial

            expiration = file._resumable_uri_date + timedelta(days=7)
        if file._size <= file._current_upload:
            await file.finishUpload(self.context)
        resp = Response(headers=multidict.MultiDict({
            'Upload-Offset':
            str(file.actualSize()),
            'Tus-Resumable':
            '1.0.0',
            'Upload-Expires':
            expiration.isoformat(),
            'Access-Control-Expose-Headers':
            'Upload-Offset,Upload-Expires,Tus-Resumable'
        }))
        return resp
Пример #10
0
    async def __call__(self):
        data = await self.request.json()
        if '@type' not in data and data['@type'] != 'Site':
            return ErrorResponse('NotAllowed',
                                 'can not create this type %s' % data['@type'],
                                 status=401)

        if 'title' not in data and not data['title']:
            return ErrorResponse('NotAllowed', 'We need a title', status=401)

        if 'id' not in data:
            return ErrorResponse('NotAllowed', 'We need an id', status=401)

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

        if data['id'] in self.context:
            # Already exist
            return ErrorResponse('NotAllowed', 'Duplicate id', status=401)

        site = create_content('Site',
                              id=data['id'],
                              title=data['title'],
                              description=data['description'])

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

        self.context[data['id']] = site

        site.install()

        self.request._site_id = site.__name__

        user = get_authenticated_user_id(self.request)

        # Local Roles assign owner as the creator user
        roleperm = IPrincipalRoleManager(site)
        roleperm.assignRoleToPrincipal('plone.Owner', user)

        await notify(ObjectFinallyCreatedEvent(site))
        # await notify(ObjectAddedEvent(site, self.context, site.__name__))

        resp = {'@type': 'Site', 'id': data['id'], 'title': data['title']}
        headers = {'Location': self.request.path + data['id']}

        return Response(response=resp, headers=headers)
Пример #11
0
    async def __call__(self):
        data = await self.get_data()
        behaviors = data.get('@behaviors', None)
        for behavior in behaviors or ():
            self.context.add_behavior(behavior)

        deserializer = queryMultiAdapter((self.context, self.request),
                                         IResourceDeserializeFromJson)
        if deserializer is None:
            return ErrorResponse('DeserializationError',
                                 'Cannot deserialize type {}'.format(
                                     self.context.portal_type),
                                 status=501)

        try:
            await deserializer(data)
        except DeserializationError as e:
            return ErrorResponse('DeserializationError', str(e), status=400)

        await notify(ObjectFinallyModifiedEvent(self.context))

        return Response(response={}, status=204)
Пример #12
0
    async def __call__(self):
        """ data input : { 'interface': 'INTERFACE' }"""
        if not hasattr(self.request, 'site_settings'):
            return ErrorResponse('BadRequest', _("Not in a site request"))
        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')

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

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

        return Response(response={}, status=201)
Пример #13
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_:
            return ErrorResponse('RequiredParam',
                                 _("Property '@type' is required"))

        # Generate a temporary id if the id is not given
        if not id_:
            new_id = None
        else:
            new_id = id_

        user = get_authenticated_user_id(self.request)
        # Create object
        try:
            obj = create_content_in_container(self.context,
                                              type_,
                                              new_id,
                                              id=new_id,
                                              creators=(user, ),
                                              contributors=(user, ))
        except PreconditionFailed as e:
            return ErrorResponse('PreconditionFailed', str(e), status=412)
        except ConflictIdOnContainer as e:
            return ErrorResponse('ConflictId', str(e), status=409)
        except ValueError as e:
            return ErrorResponse('CreatingObject', str(e), status=400)

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

        # Update fields
        deserializer = queryMultiAdapter((obj, self.request),
                                         IResourceDeserializeFromJson)
        if deserializer is None:
            return ErrorResponse('DeserializationError',
                                 'Cannot deserialize type {}'.format(
                                     obj.portal_type),
                                 status=501)

        try:
            await deserializer(data, validate_all=True)
        except DeserializationError as e:
            return ErrorResponse('DeserializationError',
                                 str(e),
                                 exc=e,
                                 status=400)

        # Local Roles assign owner as the creator user
        roleperm = IPrincipalRoleManager(obj)
        roleperm.assignRoleToPrincipal('plone.Owner', user)

        await notify(ObjectFinallyCreatedEvent(obj))

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

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

        serializer = queryMultiAdapter((obj, self.request),
                                       IResourceSerializeToJson)
        return Response(response=serializer(), headers=headers, status=201)
Пример #14
0
 async def __call__(self):
     return Response({'foo': 'bar'})
Пример #15
0
 async def __call__(self):
     data = await self.request.json()
     mailer = queryUtility(IMailer)
     await mailer.send(**data)
     return Response(response={'messages_sent': 1}, status=200)
Пример #16
0
    async def tus_patch(self):
        file = self.field.get(self.context)
        if 'CONTENT-LENGTH' in self.request.headers:
            to_upload = int(self.request.headers['CONTENT-LENGTH'])
        else:
            raise AttributeError('No content-length header')

        if 'UPLOAD-OFFSET' in self.request.headers:
            file._current_upload = int(self.request.headers['UPLOAD-OFFSET'])
        else:
            raise AttributeError('No upload-offset header')
        try:
            data = await self.request.content.readexactly(to_upload)
        except asyncio.IncompleteReadError as e:
            data = e.partial
        count = 0
        while data:
            old_current_upload = file._current_upload
            resp = await file.appendData(data)
            # The amount of bytes that are readed
            if resp.status in [200, 201]:
                # If we finish the current upload is the size of the file
                readed_bytes = file._current_upload - old_current_upload
            else:
                # When it comes from gcloud the current_upload is one number less
                readed_bytes = file._current_upload - old_current_upload + 1

            # Cut the data so there is only the needed data
            data = data[readed_bytes:]

            bytes_to_read = len(data)

            if resp.status in [200, 201]:
                # If we are finished lets close it
                await file.finishUpload(self.context)
                data = None

            if bytes_to_read == 0:
                # We could read all the info
                break

            if bytes_to_read < 262144:
                # There is no enough data to send to gcloud
                break

            if resp.status in [400]:
                # Some error
                break

            if resp.status == 308:
                # We continue resumable
                count = 0
                try:
                    data += await self.request.content.readexactly(bytes_to_read)  # noqa
                except asyncio.IncompleteReadError as e:
                    data += e.partial

            else:
                count += 1
                if count > MAX_RETRIES:
                    raise AttributeError('MAX retries error')
        expiration = file._resumable_uri_date + timedelta(days=7)

        resp = Response(headers=multidict.MultiDict({
            'Upload-Offset': str(file.actualSize()),
            'Tus-Resumable': '1.0.0',
            'Upload-Expires': expiration.isoformat(),
            'Access-Control-Expose-Headers': 'Upload-Offset,Upload-Expires,Tus-Resumable'
        }))
        return resp