fixes sharing/revocations issues

mailing
Laurent 1 month ago
parent 1a9eb14dd9
commit e5ac3750d1
  1. 6
      sync/models/base.py
  2. 2
      sync/models/data_access.py
  3. 19
      sync/registry.py
  4. 11
      sync/signals.py
  5. 6
      sync/utils.py
  6. 4
      sync/views.py
  7. 5
      sync/ws_sender.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

@ -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()

@ -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()

@ -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()

@ -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())

@ -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}')

@ -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:

Loading…
Cancel
Save