Ejemplo n.º 1
0
async def create_content_in_container(container,
                                      type_,
                                      id_,
                                      request=None,
                                      check_security=True,
                                      **kw):
    """Utility to create a content.

    This method is the one to use to create content.
    id_ can be None
    """
    factory = get_cached_factory(type_)

    if check_security and factory.add_permission:
        if factory.add_permission in PERMISSIONS_CACHE:
            permission = PERMISSIONS_CACHE[factory.add_permission]
        else:
            permission = query_utility(IPermission,
                                       name=factory.add_permission)
            PERMISSIONS_CACHE[factory.add_permission] = permission

        if request is None:
            request = get_current_request()

        if permission is not None and \
                not IInteraction(request).check_permission(permission.id, container):
            raise NoPermissionToAdd(str(container), type_)

    constrains = IConstrainTypes(container, None)
    if constrains is not None:
        if not constrains.is_type_allowed(type_):
            raise NotAllowedContentType(str(container), type_)

    # We create the object with at least the ID
    obj = factory(id=id_, parent=container)
    for key, value in kw.items():
        setattr(obj, key, value)

    txn = getattr(container, '_p_jar', None) or get_transaction()
    if txn is None or not txn.storage.supports_unique_constraints:
        # need to manually check unique constraints
        if await container.async_contains(obj.id):
            raise ConflictIdOnContainer(
                f'Duplicate ID: {container} -> {obj.id}')

    obj.__new_marker__ = True

    await notify(BeforeObjectAddedEvent(obj, container, id_))
    await container.async_set(obj.id, obj)
    return obj
Ejemplo n.º 2
0
async def create_content_in_container(container,
                                      type_,
                                      id_,
                                      request=None,
                                      **kw):
    """Utility to create a content.

    This method is the one to use to create content.
    id_ can be None
    """
    factory = get_cached_factory(type_)

    if factory.add_permission:
        if factory.add_permission in PERMISSIONS_CACHE:
            permission = PERMISSIONS_CACHE[factory.add_permission]
        else:
            permission = query_utility(IPermission,
                                       name=factory.add_permission)
            PERMISSIONS_CACHE[factory.add_permission] = permission

        if request is None:
            request = get_current_request()

        if permission is not None and \
                not IInteraction(request).check_permission(permission.id, container):
            raise NoPermissionToAdd(str(container), type_)

    constrains = IConstrainTypes(container, None)
    if constrains is not None:
        if not constrains.is_type_allowed(type_):
            raise NotAllowedContentType(str(container), type_)

    # We create the object with at least the ID
    obj = factory(id=id_)
    obj.__parent__ = container
    obj.__name__ = obj.id
    for key, value in kw.items():
        setattr(obj, key, value)

    if request is None or 'OVERWRITE' not in request.headers:
        if await container.async_contains(obj.id):
            raise ConflictIdOnContainer(str(container), obj.id)

    obj.__new_marker__ = True

    await notify(BeforeObjectAddedEvent(obj, container, id_))
    await container.async_set(obj.id, obj)
    return obj
Ejemplo n.º 3
0
    async def store(self, oid, old_serial, writer, obj, txn):
        assert oid is not None

        pickled = writer.serialize()  # This calls __getstate__ of obj
        if len(pickled) >= self._large_record_size:
            log.info(f"Large object {obj.__class__}: {len(pickled)}")
        if self._store_json:
            json_dict = await writer.get_json()
            json = ujson.dumps(json_dict)
        else:
            json = {}
        part = writer.part
        if part is None:
            part = 0

        update = False
        statement_sql = self._sql.get('NAIVE_UPSERT', self._objects_table_name)
        if not obj.__new_marker__ and obj.__serial__ is not None:
            # we should be confident this is an object update
            statement_sql = self._sql.get('UPDATE', self._objects_table_name)
            update = True

        conn = await txn.get_connection()
        async with txn._lock:
            try:
                result = await conn.fetch(
                    statement_sql,
                    oid,  # The OID of the object
                    txn._tid,  # Our TID
                    len(pickled),  # Len of the object
                    part,  # Partition indicator
                    writer.resource,  # Is a resource ?
                    writer.of,  # It belogs to a main
                    old_serial,  # Old serial
                    writer.parent_id,  # Parent OID
                    writer.id,  # Traversal ID
                    writer.type,  # Guillotina type
                    json,  # JSON catalog
                    pickled  # Pickle state)
                )
            except asyncpg.exceptions.UniqueViolationError as ex:
                if 'Key (parent_id, id)' in ex.detail:
                    raise ConflictIdOnContainer(ex)
                raise
            except asyncpg.exceptions.ForeignKeyViolationError:
                txn.deleted[obj.__uuid__] = obj
                raise TIDConflictError(
                    f'Bad value inserting into database that could be caused '
                    f'by a bad cache value. This should resolve on request retry.',
                    oid, txn, old_serial, writer)
            except asyncpg.exceptions._base.InterfaceError as ex:
                if 'another operation is in progress' in ex.args[0]:
                    raise ConflictError(
                        f'asyncpg error, another operation in progress.', oid,
                        txn, old_serial, writer)
                raise
            except asyncpg.exceptions.DeadlockDetectedError:
                raise ConflictError(f'Deadlock detected.', oid, txn,
                                    old_serial, writer)
            if len(result) != 1 or result[0]['count'] != 1:
                if update:
                    # raise tid conflict error
                    raise TIDConflictError(
                        f'Mismatch of tid of object being updated. This is likely '
                        f'caused by a cache invalidation race condition and should '
                        f'be an edge case. This should resolve on request retry.',
                        oid, txn, old_serial, writer)
                else:
                    log.error('Incorrect response count from database update. '
                              'This should not happen. tid: {}'.format(
                                  txn._tid))
        await txn._cache.store_object(obj, pickled)
Ejemplo n.º 4
0
async def create_content_in_container(
    parent: Folder,
    type_: str,
    id_: str,
    request: IRequest = None,
    check_security: bool = True,
    check_constraints: bool = True,
    **kw,
) -> Resource:
    """Utility to create a content.

    This method is the one to use to create content.
    `id_` can be None

    :param parent: where to create content inside of
    :param type_: content type to create
    :param id_: id to give content in parent object
    :param request: <optional>
    :param check_security: be able to disable security checks
    """
    factory = get_cached_factory(type_)

    if check_security and factory.add_permission:
        if factory.add_permission in PERMISSIONS_CACHE:
            permission = PERMISSIONS_CACHE[factory.add_permission]
        else:
            permission = query_utility(IPermission, name=factory.add_permission)
            PERMISSIONS_CACHE[factory.add_permission] = permission

        if permission is not None:
            policy = get_security_policy()
            if not policy.check_permission(permission.id, parent):
                raise NoPermissionToAdd(str(parent), type_)

    if check_constraints:
        constrains = IConstrainTypes(parent, None)
        if constrains is not None:
            if not constrains.is_type_allowed(type_):
                raise NotAllowedContentType(str(parent), type_)

    # We create the object with at least the ID
    obj = factory(id=id_, parent=parent)
    for key, value in kw.items():
        if key == "id":
            # the factory sets id
            continue
        setattr(obj, key, value)

    txn: Optional[ITransaction]
    if hasattr(parent, "_get_transaction"):
        txn = parent._get_transaction()
    else:
        txn = cast(Optional[ITransaction], getattr(parent, "__txn__", None) or get_transaction())
    if txn is None or not txn.storage.supports_unique_constraints:
        # need to manually check unique constraints
        if await parent.async_contains(obj.id):
            raise ConflictIdOnContainer(f"Duplicate ID: {parent} -> {obj.id}")

    obj.__new_marker__ = True

    await notify(BeforeObjectAddedEvent(obj, parent, id_))

    await parent.async_set(obj.id, obj)
    return obj