Beispiel #1
0
    def on_record_changed(self, event):
        bucket_id = event.payload['bucket_id']
        collection_id = event.payload['collection_id']
        timestamp = event.payload['timestamp']

        if not is_monitoring_collection(self.registry, bucket_id, collection_id):
            return

        for change in event.impacted_records:
            # This might be the first we've seen of this collection.
            old_timestamp = self.collection_timestamps.get((bucket_id, collection_id), None)

            # Synthesize event for /buckets/monitor/collections/changes record.
            new = changes_record(event.request,
                                 bucket_id, collection_id, timestamp)
            old = None
            action = ACTIONS.CREATE
            if old_timestamp:
                action = ACTIONS.UPDATE
                old = changes_record(event.request,
                                     bucket_id, collection_id, old_timestamp)

            resource_data = {'bucket_id': 'monitor', 'collection_id': 'changes', 'id': new['id']}

            notify_resource_event(
                event.request, '/buckets/monitor/collections/changes',
                timestamp, new, action, old=old,
                resource_name='record', resource_data=resource_data
            )

            self.collection_timestamps[(bucket_id, collection_id)] = timestamp
Beispiel #2
0
    def listener(cls, event):
        cls.events.append(event)

        # In these resource tests, the resource parent id is the user id.
        parent_id = event.request.prefixed_userid

        # Let's create a cascade of event. When a CREATE event is received,
        # we send an UPDATE one.
        if event.payload["action"] == "create":
            notify_resource_event(event.request, parent_id,
                                  event.payload["timestamp"], {"foo": "42"},
                                  ACTIONS.UPDATE)
Beispiel #3
0
 def listener(cls, event):
     """Have the first "de Paris" event trigger a follow-up "de New York" event."""
     cls.events.append(event)
     if not isinstance(event, ResourceChanged):
         return
     if len(event.impacted_records) > 1:
         raise ValueError("Too many events {}".format(event.impacted_records))
     # An event without records is impossible.
     assert len(event.impacted_records) == 1
     if event.impacted_records[0]['new']['name'] == 'de Paris':
         new_record = {'name': 'de New York'}
         # Trying to match the Mushroom (i.e. UserResource) parent
         # ID to test event grouping
         parent_id = event.request.prefixed_userid
         notify_resource_event(event.request, parent_id, event.payload['timestamp'], new_record,
                               ACTIONS.CREATE)
 def listener(cls, event):
     """Have the first "de Paris" event trigger a follow-up "de New York" event."""
     cls.events.append(event)
     if not isinstance(event, ResourceChanged):
         return
     if len(event.impacted_objects) > 1:
         raise ValueError("Too many events {}".format(
             event.impacted_objects))
     # An event without objects is impossible.
     assert len(event.impacted_objects) == 1
     if event.impacted_objects[0]["new"]["name"] == "de Paris":
         new_object = {"name": "de New York"}
         # Trying to match the Mushroom parent ID to test event grouping
         parent_id = event.request.prefixed_userid
         notify_resource_event(event.request, parent_id,
                               event.payload["timestamp"], new_object,
                               ACTIONS.CREATE)
Beispiel #5
0
 def listener(cls, event):
     """Have the first "de Paris" event trigger a follow-up "de New York" event."""
     cls.events.append(event)
     if not isinstance(event, ResourceChanged):
         return
     if len(event.impacted_records) > 1:
         raise ValueError("Too many events {}".format(
             event.impacted_records))
     # An event without records is impossible.
     assert len(event.impacted_records) == 1
     if event.impacted_records[0]['new']['name'] == 'de Paris':
         new_record = {'name': 'de New York'}
         # Trying to match the Mushroom (i.e. UserResource) parent
         # ID to test event grouping
         parent_id = event.request.prefixed_userid
         notify_resource_event(event.request, parent_id,
                               event.payload['timestamp'], new_record,
                               ACTIONS.CREATE)
Beispiel #6
0
    def delete(self):
        principal = self.request.matchdict["principal"]
        storage = self.request.registry.storage
        permission = self.request.registry.permission
        object_uris_and_permissions = permission.get_accessible_objects(
            [principal])
        object_uris = list(object_uris_and_permissions.keys())
        write_perm_principals = permission.get_objects_permissions(
            object_uris, ["write"])
        to_delete = set()
        for object_uri, principals in zip(object_uris, write_perm_principals):
            principals = principals["write"]
            # "Ownership" isn't a real concept in Kinto, so instead we
            # define ownership as meaning "this user is the only one
            # who can write to this object".
            if principals == set([principal]):
                to_delete.add(object_uri)

        # Any accessible objects that won't be deleted, need to have
        # the user's permission removed.
        for object_uri, permissions in object_uris_and_permissions.items():
            if object_uri in to_delete:
                continue

            for perm in permissions:
                permission.remove_principal_from_ace(object_uri, perm,
                                                     principal)

        to_delete = condense_under_parents(self.request, to_delete)

        # Group by (parent_uri, resource of child) to make fewer
        # requests to storage backend.
        # Store the parsed object IDs, since those are what we
        # actually give to the storage backend.
        object_ids_by_parent_uri = collections.defaultdict(list)
        # Store also the object URIs, which we give to the permission backend.
        objects_by_parent_uri = collections.defaultdict(list)
        # We have to get the matchdict of the child here anyhow, so
        # keep that to generate events later.
        matchdicts_by_parent_uri = {}
        for object_uri in to_delete:
            parent_uri = get_parent_uri(object_uri)
            resource_name, matchdict = core_utils.view_lookup(
                self.request, object_uri)
            objects_by_parent_uri[(parent_uri,
                                   resource_name)].append(object_uri)
            object_ids_by_parent_uri[(parent_uri,
                                      resource_name)].append(matchdict["id"])
            # This overwrites previous matchdicts for the parent, but
            # we'll only use the fields that are relevant to the
            # parent, which will be the same for each child.
            matchdicts_by_parent_uri[parent_uri] = matchdict

        for (parent_uri,
             resource_name), object_ids in object_ids_by_parent_uri.items():
            # Generate the parent matchdict from an arbitrary child's matchdict.
            matchdict = {**matchdicts_by_parent_uri[parent_uri]}
            matchdict.pop("id", None)

            # Deletes are paginated too, so take the page size from settings.
            batch_size = self.request.registry.settings[
                "storage_max_fetch_size"]
            for batch in slice_into_batches(object_ids, batch_size):
                batch = list(batch)
                filters = [Filter("id", batch, core_utils.COMPARISON.IN)]
                timestamp = storage.resource_timestamp(resource_name,
                                                       parent_uri)
                records, _ = storage.get_all(resource_name=resource_name,
                                             parent_id=parent_uri,
                                             filters=filters)
                tombstones = storage.delete_all(resource_name=resource_name,
                                                parent_id=parent_uri,
                                                filters=filters)
                notify_resource_event(
                    self.request,
                    parent_uri,
                    timestamp,
                    tombstones,
                    ACTIONS.DELETE,
                    old=records,
                    resource_name=resource_name,
                    resource_data=matchdict,
                )
                # FIXME: need to purge the above tombstones, but no
                # way to purge just some tombstones for just this
                # principal

                # Clear permissions from the deleted objects, for
                # example those of other users.
                permission.delete_object_permissions(
                    *objects_by_parent_uri[(parent_uri, resource_name)])

        # Remove this principal from existing users.
        permission.remove_principal(principal)

        # Remove this principal from all groups that contain it.
        associated_principals = permission.get_user_principals(principal)
        for associated_principal in associated_principals:
            permission.remove_user_principal(principal, associated_principal)

        return {"data": {"principal": principal}}