Пример #1
0
async def move_content(context, request):
    results = []
    async for ob in _iter_copyable_content(context, request):
        new_ob = await move(ob, context)
        results.append({
            "source": get_object_url(ob),
            "target": get_object_url(new_ob)
        })
    return results
Пример #2
0
async def test_object_utils(container_requester):
    async with container_requester as requester:
        response, status = await requester(
            'POST',
            '/db/guillotina/',
            data=json.dumps({
                "@type": "Item",
                "title": "Item1",
                "id": "item1"
            }))
        assert status == 201
        request = get_mocked_request(requester.db)
        root = await get_root(request)
        txn = await request._tm.begin(request)
        container = await root.async_get('guillotina')

        ob = await utils.get_object_by_oid(response['@uid'], txn)
        assert ob is not None
        assert ob._p_oid == response['@uid']

        ob2 = await utils.navigate_to(container, 'item1')
        assert ob2._p_oid == ob._p_oid

        url = utils.get_object_url(ob, request)
        assert url.endswith('item1')

        await request._tm.abort(txn=txn)
Пример #3
0
async def test_object_utils(container_requester):
    async with container_requester as requester:
        response, status = await requester("POST",
                                           "/db/guillotina/",
                                           data=json.dumps({
                                               "@type": "Item",
                                               "title": "Item1",
                                               "id": "item1"
                                           }))
        assert status == 201
        request = get_mocked_request(db=requester.db)
        root = await get_root(db=requester.db)
        tm = requester.db.get_transaction_manager()
        txn = await tm.begin()
        container = await root.async_get("guillotina")

        ob = await utils.get_object_by_uid(response["@uid"], txn)
        assert ob is not None
        assert ob.__uuid__ == response["@uid"]

        ob2 = await utils.navigate_to(container, "item1")
        assert ob2.__uuid__ == ob.__uuid__

        url = utils.get_object_url(ob, request)
        assert url.endswith("item1")

        await tm.abort(txn=txn)
Пример #4
0
    async def search(self, container: IContainer,
                     query: ParsedQueryInfo):  # type: ignore
        sql, arguments = self.build_query(container, query,
                                          ['id', 'zoid', 'json'])
        txn = get_transaction()
        if txn is None:
            raise TransactionNotFound()
        conn = await txn.get_connection()

        results = []
        try:
            context_url = get_object_url(container)
        except RequestNotFound:
            context_url = get_content_path(container)
        logger.debug(f'Running search:\n{sql}\n{arguments}')
        for record in await conn.fetch(sql, *arguments):
            data = json.loads(record['json'])
            result = self.load_meatdata(query, data)
            result['@name'] = record['id']
            result['@uid'] = record['zoid']
            result['@id'] = data['@absolute_url'] = context_url + data['path']
            results.append(result)

        # also do count...
        total = len(results)
        if total >= query['size'] or query['_from'] != 0:
            sql, arguments = self.build_count_query(container, query)
            logger.debug(f'Running search:\n{sql}\n{arguments}')
            records = await conn.fetch(sql, *arguments)
            total = records[0]['count']
        return {'member': results, 'items_count': total}
async def check_content_moved(event):
    request = event.request
    try:
        get_current_container()
    except ContainerNotFound:
        return

    storage = utils.get_storage()
    if storage is None:
        return

    tail, _, view = '/'.join(event.tail).partition('/@')
    if view:
        view = '@' + view
    path = os.path.join(
        get_content_path(request.resource), tail)

    query = Query.from_(aliases_table).select(
        aliases_table.zoid
    ).where(
        (aliases_table.path == sqlq(path)) |
        (aliases_table.path == sqlq(path) + '/' + sqlq(view))
    )

    async with storage.pool.acquire() as conn:
        results = await conn.fetch(str(query))

    if len(results) > 0:
        ob = await get_object_by_oid(results[0]['zoid'])
        url = get_object_url(ob)
        if view:
            url += '/' + view
        raise HTTPMovedPermanently(url)
Пример #6
0
async def test_object_utils(container_requester):
    async with container_requester as requester:
        response, status = await requester('POST',
                                           '/db/guillotina/',
                                           data=json.dumps({
                                               "@type": "Item",
                                               "title": "Item1",
                                               "id": "item1"
                                           }))
        assert status == 201
        request = get_mocked_request(requester.db)
        root = await get_root(request)
        txn = await request._tm.begin(request)
        container = await root.async_get('guillotina')

        ob = await utils.get_object_by_oid(response['@uid'], txn)
        assert ob is not None
        assert ob._p_oid == response['@uid']

        ob2 = await utils.navigate_to(container, 'item1')
        assert ob2._p_oid == ob._p_oid

        url = utils.get_object_url(ob, request)
        assert url.endswith('item1')

        await request._tm.abort(txn=txn)
Пример #7
0
async def resolve_uid(context, request):
    uid = request.matchdict['uid']
    ob = await get_object_by_oid(uid)
    if ob is None:
        return HTTPNotFound(content={'reason': f'Could not find uid: {uid}'})
    interaction = IInteraction(request)
    if interaction.check_permission('guillotina.AccessContent', ob):
        return HTTPMovedPermanently(get_object_url(ob, request))
    else:
        # if a user doesn't have access to it, they shouldn't know anything about it
        return HTTPNotFound(content={'reason': f'Could not find uid: {uid}'})
Пример #8
0
async def resolve_uid(context, request):
    uid = request.matchdict["uid"]
    try:
        ob = await get_object_by_uid(uid)
    except KeyError:
        return HTTPNotFound(content={"reason": f"Could not find uid: {uid}"})
    policy = get_security_policy()
    if policy.check_permission("guillotina.AccessContent", ob):
        return HTTPMovedPermanently(get_object_url(ob, request))
    else:
        # if a user doesn't have access to it, they shouldn't know anything about it
        return HTTPNotFound(content={"reason": f"Could not find uid: {uid}"})
Пример #9
0
async def get_all_files(context, request):
    children = []
    async for _, obj in context.async_items():
        children.append({
            "type": obj.type_name,
            "url": get_object_url(obj),
            "path": get_content_path(obj)
        })
        if obj.type_name == 'Directory':
            sub = await get_all_files(obj, request)
            children += sub
    return children
Пример #10
0
    async def _query(self,
                     context: IResource,
                     query: ParsedQueryInfo,
                     unrestricted: bool = False):
        sql, arguments = self.build_query(context,
                                          query, ["id", "zoid", "json"],
                                          unrestricted=unrestricted)
        txn = get_current_transaction()
        conn = await txn.get_connection()
        results = []
        fullobjects = query["fullobjects"]
        container = find_container(context)
        if container is None:
            raise ContainerNotFound()

        try:
            context_url = get_object_url(container)
            request = get_current_request()
        except RequestNotFound:
            context_url = get_content_path(container)
            request = None

        logger.debug(f"Running search:\n{sql}\n{arguments}")

        async with txn.lock:
            records = await conn.fetch(sql, *arguments)
        for record in records:
            data = json.loads(record["json"])
            if fullobjects and request is not None and txn is not None:
                # Get Object
                obj = await txn.get(data["uuid"])
                # Serialize object
                view = DefaultGET(obj, request)
                result = await view()
            else:
                result = self.load_meatdata(query, data)
                result["@name"] = record["id"]
                result["@uid"] = record["zoid"]
                result["@id"] = data[
                    "@absolute_url"] = context_url + data["path"]
            results.append(result)

        # also do count...
        total = len(results)
        if total >= query["size"] or query["_from"] != 0:
            sql, arguments = self.build_count_query(context,
                                                    query,
                                                    unrestricted=unrestricted)
            logger.debug(f"Running search:\n{sql}\n{arguments}")
            async with txn.lock:
                records = await conn.fetch(sql, *arguments)
            total = records[0]["count"]
        return {"items": results, "items_total": total}
Пример #11
0
    async def __call__(self):

        summary = json_compatible({
            "@id":
            get_object_url(self.context, self.request),
            "@name":
            self.context.__name__,
            "@type":
            self.context.type_name,
            "@uid":
            self.context.uuid,
        })
        return summary
Пример #12
0
async def move(context, request):
    try:
        data = await request.json()
    except Exception:
        data = {}

    try:
        await content.move(context, **data)
    except TypeError:
        raise ErrorResponse('RequiredParam',
                            _("Invalid params"),
                            reason=error_reasons.REQUIRED_PARAM_MISSING,
                            status=412)

    return {'@url': get_object_url(context, request)}
Пример #13
0
async def move(context, request):
    try:
        data = await request.json()
    except Exception:
        data = {}

    try:
        await content.move(
            context, destination=data.get("destination"), new_id=data.get("new_id"), check_permission=True
        )
    except TypeError:
        raise ErrorResponse(
            "RequiredParam", _("Invalid params"), reason=error_reasons.REQUIRED_PARAM_MISSING, status=412
        )

    return {"@url": get_object_url(context, request)}
Пример #14
0
async def translate_links(content, container=None) -> str:
    """
    optimized url builder here so we don't pull
    full objects from database however, we lose caching.

    Would be great to move this into an implementation
    that worked with current cache/invalidation strategies
    """

    req = None
    if container is None:
        container = find_container(content)
    container_url = get_object_url(container, req)
    dom = html.fromstring(content)
    contexts = {}

    for node in dom.xpath("//a") + dom.xpath("//img"):
        url = node.get("href", node.get("src", ""))
        if "resolveuid/" not in url:
            continue
        path = []
        _, _, current_uid = url.partition("resolveuid/")
        current_uid = current_uid.split("/")[0].split("?")[0]

        error = False
        while current_uid != container.uuid:
            if current_uid not in contexts:
                # fetch from db
                result = await _get_id(current_uid)
                if result is not None:
                    contexts[current_uid] = result
                else:
                    # could not find, this should not happen
                    error = True
                    break
            path = [contexts[current_uid]["id"]] + path
            current_uid = contexts[current_uid]["parent"]

        if error:
            continue
        url = os.path.join(container_url, "/".join(path))
        attr = node.tag.lower() == "a" and "href" or "src"
        node.attrib[attr] = url

    return html.tostring(dom).decode("utf-8")
Пример #15
0
    async def create(self, payload: dict, in_: IResource = None) -> IResource:
        await self.get_transaction()
        if in_ is None:
            in_ = self.db
        view = get_multi_adapter((in_, self.request), app_settings["http_methods"]["POST"], name="")

        async def json():
            return payload

        self.request.json = json
        resp = await view()
        await self.commit()
        path = resp.headers["Location"]
        if path.startswith("http://") or path.startswith("https://"):
            # strip off container prefix
            container_url = get_object_url(in_, self.request)  # type: ignore
            path = path[len(container_url or "") :]
        return await navigate_to(in_, path.strip("/"))  # type: ignore
Пример #16
0
    async def create(self, payload: dict, in_: IResource=None) -> IResource:
        await self.get_transaction()
        if in_ is None:
            in_ = self.db
        view = get_multi_adapter(
            (in_, self.request), app_settings['http_methods']['POST'], name='')

        async def json():
            return payload

        self.request.json = json
        resp = await view()
        await self.commit()
        path = resp.headers['Location']
        if path.startswith('http://') or path.startswith('https://'):
            # strip off container prefix
            container_url = get_object_url(in_, self.request)  # type: ignore
            path = path[len(container_url or ''):]
        return await navigate_to(in_, path.strip('/'))  # type: ignore
Пример #17
0
async def _iter_copyable_content(context, request):
    policy = get_security_policy()
    data = await request.json()
    if 'source' not in data:
        raise HTTPPreconditionFailed(content={'reason': 'No source'})

    source = data['source']
    if not isinstance(source, list):
        source = [source]

    container = find_container(context)
    container_url = get_object_url(container)
    for item in source:
        if item.startswith(container_url):
            path = item[len(container_url):]
            ob = await navigate_to(container, path.strip('/'))
            if ob is None:
                raise HTTPPreconditionFailed(content={
                    'reason': 'Could not find content',
                    'source': item
                })
        elif '/' in item:
            ob = await navigate_to(container, item.strip('/'))
            if ob is None:
                raise HTTPPreconditionFailed(content={
                    'reason': 'Could not find content',
                    'source': item
                })
        else:
            try:
                ob = await get_object_by_uid(item)
            except KeyError:
                raise HTTPPreconditionFailed(content={
                    'reason': 'Could not find content',
                    'source': item
                })
        if not policy.check_permission('guillotina.DuplicateContent', ob):
            raise HTTPPreconditionFailed(content={
                'reason': 'Invalid permission',
                'source': item
            })
        yield ob
Пример #18
0
async def sharing_get(context, request):
    roleperm = IRolePermissionMap(context)
    prinperm = IPrincipalPermissionMap(context)
    prinrole = IPrincipalRoleMap(context)
    result = {'local': {}, 'inherit': []}
    result['local']['roleperm'] = roleperm._bycol
    result['local']['prinperm'] = prinperm._bycol
    result['local']['prinrole'] = prinrole._bycol
    for obj in iter_parents(context):
        roleperm = IRolePermissionMap(obj, None)
        url = get_object_url(obj, request)
        if roleperm is not None and url is not None:
            prinperm = IPrincipalPermissionMap(obj)
            prinrole = IPrincipalRoleMap(obj)
            result['inherit'].append({
                '@id': url,
                'roleperm': roleperm._bycol,
                'prinperm': prinperm._bycol,
                'prinrole': prinrole._bycol,
            })
    await notify(ObjectPermissionsViewEvent(context))
    return result
Пример #19
0
async def sharing_get(context, request):
    roleperm = IRolePermissionMap(context)
    prinperm = IPrincipalPermissionMap(context)
    prinrole = IPrincipalRoleMap(context)
    result = {"local": {}, "inherit": []}
    result["local"]["roleperm"] = roleperm._bycol
    result["local"]["prinperm"] = prinperm._bycol
    result["local"]["prinrole"] = prinrole._bycol
    for obj in iter_parents(context):
        roleperm = IRolePermissionMap(obj, None)
        url = get_object_url(obj, request)
        if roleperm is not None and url is not None:
            prinperm = IPrincipalPermissionMap(obj)
            prinrole = IPrincipalRoleMap(obj)
            result["inherit"].append({
                "@id": url,
                "roleperm": roleperm._bycol,
                "prinperm": prinperm._bycol,
                "prinrole": prinrole._bycol,
            })
    await notify(ObjectPermissionsViewEvent(context))
    return result
Пример #20
0
 def _get_items_from_result(self, container, request, result):
     items = []
     container_url = get_object_url(container, request)
     for item in result["hits"]["hits"]:
         data = format_hit(item)
         data.update({
             "@id":
             container_url + data.get("path", ""),
             "@type":
             data.get("type_name"),
             "@uid":
             item["_id"],
             "@name":
             data.get("id",
                      data.get("path", "").split("/")[-1]),
         })
         sort_value = item.get("sort")
         if sort_value:
             data.update({"sort": sort_value})
         if "highlight" in item:
             data["@highlight"] = item["highlight"]
         items.append(data)
     return items
Пример #21
0
    async def tus_create(self, *args, **kwargs):
        await self.dm.load()
        # 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()

        md5 = extension = size = None

        deferred_length = False
        if self.request.headers.get('Upload-Defer-Length') == '1':
            deferred_length = True

        if 'UPLOAD-LENGTH' in self.request.headers:
            size = int(self.request.headers['UPLOAD-LENGTH'])
        else:
            if not deferred_length:
                raise HTTPPreconditionFailed(
                    content={'reason': 'We need upload-length header'})

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

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

        if 'TUS-RESUMABLE' not in self.request.headers:
            raise HTTPPreconditionFailed(
                content={'reason': 'TUS needs a TUS version'})

        if 'X-UPLOAD-FILENAME' in self.request.headers:
            filename = self.request.headers['X-UPLOAD-FILENAME']
        elif 'UPLOAD-FILENAME' in self.request.headers:
            filename = self.request.headers['UPLOAD-FILENAME']
        elif 'UPLOAD-METADATA' not in self.request.headers:
            filename = uuid.uuid4().hex
        else:
            filename = self.request.headers['UPLOAD-METADATA']
            filename = base64.b64decode(filename.split()[1]).decode('utf-8')
        if extension is None and '.' in filename:
            extension = filename.split('.')[-1]

        await self.dm.start()
        await self.dm.update(content_type=self.request.content_type,
                             md5=md5,
                             filename=filename,
                             extension=extension,
                             size=size,
                             deferred_length=deferred_length,
                             offset=0)

        await self.file_storage_manager.start(self.dm)
        await self.dm.save()

        if 'filename' in self.request.matchdict:
            location = posixpath.join(
                get_object_url(self.context, self.request), '@tusupload',
                self.field.__name__, self.request.matchdict['filename'])
        else:
            location = posixpath.join(
                get_object_url(self.context, self.request), '@tusupload',
                self.field.__name__)

        return Response(
            status=201,
            headers={
                'Location': location,  # noqa
                'Tus-Resumable': '1.0.0',
                'Access-Control-Expose-Headers': 'Location,Tus-Resumable'
            })
Пример #22
0
    async def __call__(self, include=None, omit=None):
        self.include = include or []
        self.omit = omit or []

        parent = self.context.__parent__
        if parent is not None:
            # We render the summary of the parent
            try:
                parent_summary = await get_multi_adapter(
                    (parent, self.request), IResourceSerializeToJsonSummary)()
            except ComponentLookupError:
                parent_summary = {}
        else:
            parent_summary = {}

        factory = get_cached_factory(self.context.type_name)
        behaviors = []
        for behavior_schema in factory.behaviors or ():
            behaviors.append(behavior_schema.__identifier__)

        result = {
            "@id": get_object_url(self.context, self.request),
            "@type": self.context.type_name,
            "@name": self.context.__name__,
            "@uid": self.context.uuid,
            "@static_behaviors": behaviors,
            "parent": parent_summary,  # should be @parent
            "is_folderish":
            IFolder.providedBy(self.context),  # eek, should be @folderish?
            "creation_date": json_compatible(self.context.creation_date),
            "modification_date":
            json_compatible(self.context.modification_date),
        }

        main_schema = factory.schema
        await self.get_schema(main_schema, self.context, result, False)

        # include can be one of:
        # - <field name> on content schema
        # - namespace.IBehavior
        # - namespace.IBehavior.field_name
        included_ifaces = [name for name in self.include if "." in name]
        included_ifaces.extend(
            [name.rsplit(".", 1)[0] for name in self.include if "." in name])
        for behavior_schema, behavior in await get_all_behaviors(self.context,
                                                                 load=False):
            if "*" not in self.include:
                dotted_name = behavior_schema.__identifier__
                if dotted_name in self.omit or (len(included_ifaces) > 0
                                                and dotted_name
                                                not in included_ifaces):
                    # make sure the schema isn't filtered
                    continue
                if not getattr(behavior, "auto_serialize",
                               True) and dotted_name not in included_ifaces:
                    continue
            if IAsyncBehavior.implementedBy(behavior.__class__):
                # providedBy not working here?
                await behavior.load(create=False)
            await self.get_schema(behavior_schema, behavior, result, True)

        for post_serialize_processors in app_settings["post_serialize"]:
            await apply_coroutine(post_serialize_processors, self.context,
                                  result)

        return result
Пример #23
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)
                if isinstance(new_id, str) and not valid_id(new_id):
                    raise ErrorResponse('PreconditionFailed',
                                        'Invalid id: {}'.format(new_id),
                                        status=412,
                                        reason=error_reasons.INVALID_ID)
        else:
            if not isinstance(id_, str) or not valid_id(id_):
                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, **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)
Пример #24
0
    async def tus_create(self, *args, **kwargs):
        await self.dm.load()
        # 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()

        md5 = extension = size = None

        deferred_length = False
        if self.request.headers.get("Upload-Defer-Length") == "1":
            deferred_length = True

        if "UPLOAD-LENGTH" in self.request.headers:
            size = int(self.request.headers["UPLOAD-LENGTH"])
        else:
            if not deferred_length:
                raise HTTPPreconditionFailed(
                    content={"reason": "We need upload-length header"})

        if "UPLOAD-MD5" in self.request.headers:
            md5 = self.request.headers["UPLOAD-MD5"]

        if "UPLOAD-EXTENSION" in self.request.headers:
            extension = self.request.headers["UPLOAD-EXTENSION"]

        if "TUS-RESUMABLE" not in self.request.headers:
            raise HTTPPreconditionFailed(
                content={"reason": "TUS needs a TUS version"})

        if "X-UPLOAD-FILENAME" in self.request.headers:
            filename = self.request.headers["X-UPLOAD-FILENAME"]
        elif "UPLOAD-FILENAME" in self.request.headers:
            filename = self.request.headers["UPLOAD-FILENAME"]
        elif "UPLOAD-METADATA" not in self.request.headers:
            filename = uuid.uuid4().hex
        else:
            filename = self.request.headers["UPLOAD-METADATA"]
            filename = base64.b64decode(filename.split()[1]).decode("utf-8")
        if extension is None and "." in filename:
            extension = filename.split(".")[-1]

        await self.dm.start()
        await self.dm.update(
            content_type=self.request.content_type,
            md5=md5,
            filename=filename,
            extension=extension,
            size=size,
            deferred_length=deferred_length,
            offset=0,
        )

        await self.file_storage_manager.start(self.dm)
        await self.dm.save()

        if "file_key" in self.request.matchdict:
            location = posixpath.join(
                get_object_url(self.context, self.request),
                "@tusupload",
                self.field.__name__,
                self.request.matchdict["file_key"],
            )
        else:
            location = posixpath.join(
                get_object_url(self.context, self.request), "@tusupload",
                self.field.__name__)

        return Response(
            status=201,
            headers={
                "Location": location,  # noqa
                "Tus-Resumable": "1.0.0",
                "Access-Control-Expose-Headers": "Location,Tus-Resumable",
            },
        )
Пример #25
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 = IGetOwner(obj)
        roleperm = IPrincipalRoleManager(obj)
        owner = await get_owner(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)