async def test_create_annotation(db, guillotina_main): db = await get_database("db") login() async with transaction(db=db): container = await create_content_in_container(db, "Container", "container", title="Container") ob = await create_content_in_container(container, "Item", "foobar") annotations = IAnnotations(ob) data = AnnotationData() data["foo"] = "bar" await annotations.async_set("foobar", data) async with transaction(db=db): container = await db.async_get("container") ob = await container.async_get("foobar") annotations = IAnnotations(ob) assert "foobar" in (await annotations.async_keys()) await annotations.async_del("foobar") async with transaction(db=db): container = await db.async_get("container") ob = await container.async_get("foobar") annotations = IAnnotations(ob) assert "foobar" not in (await annotations.async_keys()) await container.async_del("foobar") await db.async_del("container")
async def test_create_annotation(db, guillotina_main): root = get_utility(IApplication, name='root') db = root['db'] request = get_mocked_request(db) login(request) async with managed_transaction(request=request, write=True): container = await create_content_in_container( db, 'Container', 'container', request=request, title='Container') ob = await create_content_in_container( container, 'Item', 'foobar', request=request) annotations = IAnnotations(ob) data = AnnotationData() data['foo'] = 'bar' await annotations.async_set('foobar', data) async with managed_transaction(request=request, write=True): container = await db.async_get('container') ob = await container.async_get('foobar') annotations = IAnnotations(ob) assert 'foobar' in (await annotations.async_keys()) await annotations.async_del('foobar') async with managed_transaction(request=request, write=True): container = await db.async_get('container') ob = await container.async_get('foobar') annotations = IAnnotations(ob) assert 'foobar' not in (await annotations.async_keys()) await container.async_del('foobar') await db.async_del('container')
async def test_create_annotation(db, guillotina_main): db = await get_database('db') login() async with transaction(db=db): container = await create_content_in_container(db, 'Container', 'container', title='Container') ob = await create_content_in_container(container, 'Item', 'foobar') annotations = IAnnotations(ob) data = AnnotationData() data['foo'] = 'bar' await annotations.async_set('foobar', data) async with transaction(db=db): container = await db.async_get('container') ob = await container.async_get('foobar') annotations = IAnnotations(ob) assert 'foobar' in (await annotations.async_keys()) await annotations.async_del('foobar') async with transaction(db=db): container = await db.async_get('container') ob = await container.async_get('foobar') annotations = IAnnotations(ob) assert 'foobar' not in (await annotations.async_keys()) await container.async_del('foobar') await db.async_del('container')
async def get_annotation(self, context, annotation_index, create=True): annotation_name = self.get_annotation_name(annotation_index) annotations_container = IAnnotations(context) annotation = annotations_container.get(annotation_name, _default) if annotation is _default: annotation = await annotations_container.async_get( annotation_name, _default) if annotation is _default: if not create: return # create annotation = AnnotationData() annotation.update({'items': []}) await annotations_container.async_set(annotation_name, annotation) if annotation_index not in self.annotations_metadata: self.annotations_metadata[annotation_index] = {} return annotation
async def _get_registry_or_create(self): annotations_container = IAnnotations(self.context) object_settings = await annotations_container.async_get("default" ) # noqa if object_settings is None: # need to create annotation... object_settings = AnnotationData() await annotations_container.async_set("default", object_settings) return object_settings
async def get_annotation(self, context, annotation_index, create=True): annotation_name = self.get_annotation_name(annotation_index) annotations_container = IAnnotations(context) annotation = annotations_container.get(annotation_name, _default) if annotation is _default: annotation = await annotations_container.async_get( annotation_name, _default) if annotation is _default: if not create: return # create annotation = AnnotationData() annotation.update({ 'items': [] }) await annotations_container.async_set(annotation_name, annotation) if annotation_index not in self.annotations_metadata: self.annotations_metadata[annotation_index] = {} return annotation
async def get_annotation(self, context: IBaseObject, annotation_index: int, create: bool = True) -> Optional[IAnnotationData]: annotation_name = self.get_annotation_name(annotation_index) annotations_container = IAnnotations(context) annotation = annotations_container.get(annotation_name, _default) if annotation is _default: annotation = await annotations_container.async_get( annotation_name, _default) if annotation is _default: if not create: return None # create annotation = AnnotationData() annotation.update({"items": []}) await annotations_container.async_set(annotation_name, annotation) if annotation_index not in self.annotations_metadata: self.annotations_metadata[annotation_index] = {} return annotation
async def get_registry(self, refresh=False): if (refresh and self.object_settings is not None): txn = get_transaction(self.request) await txn.refresh(self.object_settings) annotations_container = IAnnotations(self.context) self.object_settings = await annotations_container.async_get('default') if self.object_settings is None: # need to create annotation... self.object_settings = AnnotationData() await annotations_container.async_set('default', self.object_settings) return self.object_settings
async def load(self, create=False): annotations_container = IAnnotations(self.__dict__['context']) annotations = {} try: annotations = await annotations_container.async_get( self.__annotations_data_key) except KeyError: if create: annotations = AnnotationData() await annotations_container.async_set( self.__annotations_data_key, annotations) self.__dict__['data'] = annotations
async def load(self, create=False): annotations_container = IAnnotations(self.__dict__["context"]) data = annotations_container.get(self.__annotations_data_key__, _default) if data is not _default: # data is already preloaded, we do not need to get from db again... self.__dict__["data"] = data return annotations = await annotations_container.async_get(self.__annotations_data_key__) if annotations is None: if create: annotations = AnnotationData() await annotations_container.async_set(self.__annotations_data_key__, annotations) else: annotations = {} # fallback, assumed only for reading here... self.__dict__["data"] = annotations
async def get_annotation(self, context, key=None, anno_id=None, create=True) -> typing.Optional[AnnotationData]: if anno_id is None: bidx, bucket = self._find_bucket(key) annotation_name = self.get_annotation_name(bucket["id"]) else: annotation_name = self.get_annotation_name(anno_id) annotations_container = IAnnotations(context) annotation = annotations_container.get(annotation_name, _default) if annotation is _default: annotation = await annotations_container.async_get( annotation_name, _default) if annotation is _default: if not create: return None annotation = AnnotationData({"keys": [], "values": []}) await annotations_container.async_set(annotation_name, annotation) return annotation
async def duplicate(context, request): try: data = await request.json() except Exception: data = {} destination = data.get('destination') if destination is not None: destination_ob = await navigate_to(request.container, destination) if destination_ob is None: raise PreconditionFailed( context, 'Could not find destination object', ) else: destination_ob = context.__parent__ 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 'new_id' in data: new_id = data['new_id'] if await destination_ob.async_contains(new_id): raise PreconditionFailed( context, f'Destination already has object with the id {new_id}') else: count = 1 new_id = f'{context.id}-duplicate-{count}' while await destination_ob.async_contains(new_id): count += 1 new_id = f'{context.id}-duplicate-{count}' new_obj = await create_content_in_container( destination_ob, context.type_name, new_id, id=new_id, creators=context.creators, contributors=context.contributors) for key in context.__dict__.keys(): if key.startswith('__') or key.startswith('_BaseObject'): continue if key in ('id', ): continue new_obj.__dict__[key] = context.__dict__[key] new_obj.__acl__ = context.__acl__ for behavior in context.__behaviors__: new_obj.add_behavior(behavior) # need to copy annotation data as well... # load all annotations for context [b for b in await get_all_behaviors(context, load=True)] annotations_container = IAnnotations(new_obj) for anno_id, anno_data in context.__gannotations__.items(): new_anno_data = AnnotationData() for key, value in anno_data.items(): new_anno_data[key] = value await annotations_container.async_set(anno_id, new_anno_data) data['id'] = new_id await notify( ObjectDuplicatedEvent(new_obj, context, destination_ob, new_id, payload=data)) get = DefaultGET(new_obj, request) return await get()
async def test_txn_uses_cached_hits_on_annotations(redis_container, guillotina_main): util = get_utility(ICacheUtility) await util.initialize() async with transaction(db=await get_database("db")) as txn: root = await txn.manager.get_root() container = await create_container(root, "container") with pytest.raises(KeyError): # should set in cache as empty though await txn.get_annotation(container, "foobar") # should be registered as cache miss assert txn._cache._hits == 0 assert txn._cache._misses == 2 with pytest.raises(KeyError): # do again, should be hit this time await txn.get_annotation(container, "foobar") assert txn._cache._hits == 1 assert txn._cache._misses == 2 # now set a value for it and we'll retrieve it again annotations_container = IAnnotations(container) adata = AnnotationData() await annotations_container.async_set("foobar", adata) async with transaction(db=await get_database("db")) as txn: # everything here should be hits! root = await txn.manager.get_root() container = await root.async_get("container") adata = await txn.get_annotation(container, "foobar") # should be registered as cache miss assert txn._cache._hits == 2 assert txn._cache._misses == 0 async with transaction(db=await get_database("db")) as txn: # now, edit the value root = await txn.manager.get_root() container = await root.async_get("container") adata = await txn.get_annotation(container, "foobar") adata["foo"] = "bar" adata.register() # should be registered as cache miss assert txn._cache._hits == 2 assert txn._cache._misses == 0 async with transaction(db=await get_database("db")) as txn: # everything here should be hits! root = await txn.manager.get_root() container = await root.async_get("container") adata = await txn.get_annotation(container, "foobar") assert adata["foo"] == "bar" # should be registered as cache miss assert txn._cache._hits == 2 assert txn._cache._misses == 0 # same again, but clear cache implementation await util.clear() async with transaction(db=await get_database("db")) as txn: # everything here should be hits! root = await txn.manager.get_root() container = await root.async_get("container") adata = await txn.get_annotation(container, "foobar") assert adata["foo"] == "bar" # should be registered as cache miss assert txn._cache._hits == 0 assert txn._cache._misses == 2
async def duplicate( context: IResource, destination: Optional[Union[IResource, str]] = None, new_id: Optional[str] = None, check_permission: bool = True, reset_acl: bool = False, ) -> IResource: if destination is not None: if isinstance(destination, str): destination_ob = None if destination.startswith("/"): container = task_vars.container.get() if container: try: destination_ob = await navigate_to(container, destination) except KeyError: pass else: try: destination_ob = await get_object_by_uid(destination) except KeyError: pass else: destination_ob = destination if destination_ob is None: raise PreconditionFailed(context, "Could not find destination object") else: destination_ob = context.__parent__ if check_permission: policy = get_security_policy() if not policy.check_permission("guillotina.AddContent", destination_ob): raise PreconditionFailed( context, "You do not have permission to add content to " "the destination object" ) if new_id is not None: if await destination_ob.async_contains(new_id): raise PreconditionFailed(context, f"Destination already has object with the id {new_id}") else: count = 1 new_id = f"{context.id}-duplicate-{count}" while await destination_ob.async_contains(new_id): count += 1 new_id = f"{context.id}-duplicate-{count}" from guillotina.content import create_content_in_container creators = context.creators contributors = context.contributors user_id = get_authenticated_user_id() if reset_acl: creators = [user_id] contributors = [user_id] new_obj = await create_content_in_container( destination_ob, context.type_name, new_id, id=new_id, creators=creators, contributors=contributors, check_security=check_permission, check_constraints=True, ) for key in context.__dict__.keys(): if key.startswith("__") or key.startswith("_BaseObject"): continue if key in ("id", "creators", "contributors"): continue new_obj.__dict__[key] = context.__dict__[key] if reset_acl: new_obj.__acl__ = None get_owner = get_utility(IGetOwner) roleperm = IPrincipalRoleManager(new_obj) owner = await get_owner(new_obj, user_id) if owner is not None: roleperm.assign_role_to_principal("guillotina.Owner", owner) else: new_obj.__acl__ = context.__acl__ for behavior in context.__behaviors__: new_obj.add_behavior(behavior) # need to copy annotation data as well... # load all annotations for context [b for b in await get_all_behaviors(context, load=True)] annotations_container = IAnnotations(new_obj) for anno_id, anno_data in context.__gannotations__.items(): new_anno_data = AnnotationData() for key, value in anno_data.items(): new_anno_data[key] = value await annotations_container.async_set(anno_id, new_anno_data) await notify( ObjectDuplicatedEvent( new_obj, context, destination_ob, new_id, payload={"id": new_id, "destination": destination} ) ) return new_obj
async def duplicate( context: IResource, destination: Union[IResource, str] = None, new_id: str = None, check_permission: bool = True, ) -> IResource: if destination is not None: if isinstance(destination, str): container = task_vars.container.get() if container: destination_ob = await navigate_to(container, destination) else: raise PreconditionFailed(context, "Could not find destination object") else: destination_ob = destination if destination_ob is None: raise PreconditionFailed(context, "Could not find destination object") else: destination_ob = context.__parent__ if check_permission: policy = get_security_policy() if not policy.check_permission("guillotina.AddContent", destination_ob): raise PreconditionFailed( context, "You do not have permission to add content to " "the destination object" ) if new_id is not None: if await destination_ob.async_contains(new_id): raise PreconditionFailed(context, f"Destination already has object with the id {new_id}") else: count = 1 new_id = f"{context.id}-duplicate-{count}" while await destination_ob.async_contains(new_id): count += 1 new_id = f"{context.id}-duplicate-{count}" from guillotina.content import create_content_in_container new_obj = await create_content_in_container( destination_ob, context.type_name, new_id, id=new_id, creators=context.creators, contributors=context.contributors, ) for key in context.__dict__.keys(): if key.startswith("__") or key.startswith("_BaseObject"): continue if key in ("id",): continue new_obj.__dict__[key] = context.__dict__[key] new_obj.__acl__ = context.__acl__ for behavior in context.__behaviors__: new_obj.add_behavior(behavior) # need to copy annotation data as well... # load all annotations for context [b for b in await get_all_behaviors(context, load=True)] annotations_container = IAnnotations(new_obj) for anno_id, anno_data in context.__gannotations__.items(): new_anno_data = AnnotationData() for key, value in anno_data.items(): new_anno_data[key] = value await annotations_container.async_set(anno_id, new_anno_data) await notify( ObjectDuplicatedEvent( new_obj, context, destination_ob, new_id, payload={"id": new_id, "destination": destination} ) ) return new_obj
async def duplicate(context: IResource, destination: Union[IResource, str] = None, new_id: str = None, check_permission: bool = True) -> IResource: if destination is not None: if isinstance(destination, str): request = get_current_request() destination_ob = await navigate_to(request.container, destination) else: destination_ob = destination if destination_ob is None: raise PreconditionFailed( context, 'Could not find destination object', ) else: destination_ob = context.__parent__ if check_permission: request = get_current_request() 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 new_id is not None: if await destination_ob.async_contains(new_id): raise PreconditionFailed( context, f'Destination already has object with the id {new_id}') else: count = 1 new_id = f'{context.id}-duplicate-{count}' while await destination_ob.async_contains(new_id): count += 1 new_id = f'{context.id}-duplicate-{count}' from guillotina.content import create_content_in_container new_obj = await create_content_in_container( destination_ob, context.type_name, new_id, id=new_id, creators=context.creators, contributors=context.contributors) for key in context.__dict__.keys(): if key.startswith('__') or key.startswith('_BaseObject'): continue if key in ('id', ): continue new_obj.__dict__[key] = context.__dict__[key] new_obj.__acl__ = context.__acl__ for behavior in context.__behaviors__: new_obj.add_behavior(behavior) # need to copy annotation data as well... # load all annotations for context [b for b in await get_all_behaviors(context, load=True)] annotations_container = IAnnotations(new_obj) for anno_id, anno_data in context.__gannotations__.items(): new_anno_data = AnnotationData() for key, value in anno_data.items(): new_anno_data[key] = value await annotations_container.async_set(anno_id, new_anno_data) await notify( ObjectDuplicatedEvent(new_obj, context, destination_ob, new_id, payload={ 'id': new_id, 'destination': destination, })) return new_obj