diff --git a/sync/models/base.py b/sync/models/base.py index 564def2..7a6c3ae 100644 --- a/sync/models/base.py +++ b/sync/models/base.py @@ -137,6 +137,8 @@ class BaseModel(models.Model): if isinstance(child, BaseModel): children.extend(child.get_recursive_children(processed_objects)) + logger.info(f'***** added children = {children}') + return children def get_recursive_parents(self, processed_objects: Set = None) -> List: @@ -220,7 +222,8 @@ class BaseModel(models.Model): children = self.get_shared_children_from_relationships(relationships, processed_objects) instances.extend(children) else: - instances.extend(self.get_recursive_children(processed_objects)) + children = self.get_recursive_children(processed_objects) + instances.extend(children) return instances @@ -241,7 +244,6 @@ class BaseModel(models.Model): values.extend(value.all()) else: processed_objects.add(value) - values.append(value) current = values diff --git a/sync/models/data_access.py b/sync/models/data_access.py index 1a34a11..0db5726 100644 --- a/sync/models/data_access.py +++ b/sync/models/data_access.py @@ -77,7 +77,7 @@ class DataAccess(BaseModel): with transaction.atomic(): for instance in related_instance: - logger.info(f'adds DataAccess to {instance.__class__.__name__}') + # logger.info(f'adds DataAccess to {instance.__class__.__name__}') if isinstance(instance, BaseModel): instance.add_data_access_relation(self) instance.save() diff --git a/sync/registry.py b/sync/registry.py index 881f2d6..4b2abef 100644 --- a/sync/registry.py +++ b/sync/registry.py @@ -91,24 +91,35 @@ class RelatedUsersRegistry: def register(self, instance_id, users): """Register a device_id for a model instance ID.""" + # logger.info(f'USER REGISTRY register {instance_id} : {users}') with self._lock: instance_id_str = str(instance_id) if instance_id_str in self._registry: existing_users = self._registry[instance_id_str] self._registry[instance_id_str] = existing_users.union(users) else: - self._registry[instance_id_str] = users + self._registry[instance_id_str] = set(users) # we convert to set because transmitted query_set are emptying themselves def get_users(self, instance_id): """Get the device_id for a model instance ID.""" with self._lock: - return self._registry.get(str(instance_id)) + instance_id_str = str(instance_id) + if instance_id_str in self._registry: + # logger.info(f'###### get_users exists ! {instance_id}') + return self._registry[instance_id_str] + else: + # logger.info(f'####### get_users {instance_id} not referenced !') + return {} + + # return self._registry.get(instance_id_str) def unregister(self, instance_id): """Remove an instance from the registry.""" + # logger.info(f'USER REGISTRY unregister {instance_id}') with self._lock: - if instance_id in self._registry: - del self._registry[instance_id] + instance_id_str = str(instance_id) + if instance_id_str in self._registry: + del self._registry[instance_id_str] # Global instance related_users_registry = RelatedUsersRegistry() diff --git a/sync/signals.py b/sync/signals.py index 9719746..54661d0 100644 --- a/sync/signals.py +++ b/sync/signals.py @@ -53,12 +53,16 @@ def synchronization_notifications(sender, instance, created=False, **kwargs): # some classes are excluded in settings_app.py: SYNC_APPS if not isinstance(instance, BaseModel) and not isinstance(instance, User): return + if isinstance(instance, DataAccess): + return try: process_foreign_key_changes(sender, instance, **kwargs) signal = kwargs.get('signal') save_model_log_if_possible(instance, signal, created) notify_impacted_users(instance) + + # print(f'!!!!! related_users_registry.unregister for {instance.__class__.__name__} / {signal}') related_users_registry.unregister(instance.id) except Exception as e: logger.info(f'*** ERROR2: {e}') @@ -68,6 +72,7 @@ def synchronization_notifications(sender, instance, created=False, **kwargs): def notify_impacted_users(instance): device_id = device_registry.get_device_id(instance.id) users = related_users_registry.get_users(instance.id) + # logger.info(f'>>> notify_impacted_users: {users} for {instance.id}') if users: user_ids = [user.id for user in users] @@ -275,6 +280,7 @@ def handle_shared_with_changes(sender, instance, action, pk_set, **kwargs): instance.create_access_log(users, 'REVOKED_ACCESS') device_id = device_registry.get_device_id(instance.id) + # logger.info(f'*** send message to : {pk_set}') websocket_sender.send_message(pk_set, device_id) # for user_id in pk_set: @@ -298,9 +304,12 @@ def data_access_post_save(sender, instance, **kwargs): @receiver(pre_delete, sender=DataAccess) def revoke_access_after_delete(sender, instance, **kwargs): + # logger.info(f'.........PRE_DELETE DATAACCESS = {instance.id}..........') try: instance.cleanup_references() instance.create_revoke_access_log() + # logger.info(f'*** users to notify data access delete: {instance.shared_with.all()}') + related_users_registry.register(instance.id, instance.shared_with.all()) instance._user = instance.related_user @@ -321,6 +330,8 @@ def data_access_post_delete(sender, instance, **kwargs): logger.info(f'*** ERROR5: {e}') logger.info(traceback.format_exc()) raise + # logger.info(f'.........POST_DELETE END DATAACCESS = {instance.id}..........') + def related_users(instance): users = set() diff --git a/sync/utils.py b/sync/utils.py index 787e766..43f333d 100644 --- a/sync/utils.py +++ b/sync/utils.py @@ -98,13 +98,17 @@ class HierarchyOrganizer: def add_relations(self, instance): self.add_related_parents(instance) + logger.info(f'A///// grouped children = {self.children}') self.add_related_children(instance) + logger.info(f'B///// grouped children = {self.children}') def add_related_children(self, instance): - instance.get_shared_children(self.children) + self.children = instance.get_shared_children(set()) def grouped_children(self): grouped = defaultdict(list) + logger.info(f'///// grouped children = {self.children}') + for instance in self.children: class_name = instance.__class__.__name__ grouped[class_name].append(instance.data_identifier_dict()) diff --git a/sync/views.py b/sync/views.py index d8a27c9..ba720f7 100644 --- a/sync/views.py +++ b/sync/views.py @@ -251,7 +251,7 @@ class SynchronizationApi(APIView): return Response({"error": f"Invalid date format for last_update: {decoded_last_update}"}, status=status.HTTP_400_BAD_REQUEST) - print(f'>>> GET last modifications since: {last_update_str} / converted = {last_update}') + print(f'>>> {request.user.username} : GET last modifications since: {last_update_str} / converted = {last_update}') device_id = request.query_params.get('device_id') logs = self.query_model_logs(last_update, request.user, device_id) @@ -413,6 +413,8 @@ class LogProcessingResult: shared, grants = self.process_shared() revocations, revocated_relations_organizer = self.process_revocations() + print(f'self.revocations = {dict(revocations)}') + print(f'self.revocated_relations_organizer = {revocated_relations_organizer.get_organized_data()}') # print(f'self.deletions = {dict(self.deletions)}') # print(f'self.shared_relationship_sets = {self.shared_relationship_sets}') # print(f'self.shared_relationship_removals = {self.shared_relationship_removals}') diff --git a/sync/ws_sender.py b/sync/ws_sender.py index f3fefa7..90059ca 100644 --- a/sync/ws_sender.py +++ b/sync/ws_sender.py @@ -1,6 +1,10 @@ from channels.layers import get_channel_layer from asgiref.sync import async_to_sync + from threading import Timer, Lock +import logging + +logger = logging.getLogger(__name__) class WebSocketSender: """ @@ -55,6 +59,7 @@ class WebSocketSender: user_ids_key = frozenset(user_ids) if not user_ids_key: # No users to send to + logger.info(f'WARNING: no user ids : {user_ids}') return with self._debounce_lock: