fix sharing issue

sync3
Laurent 5 months ago
parent c8dd481ebd
commit 9c121cb106
  1. 46
      sync/utils.py
  2. 143
      sync/views.py

@ -1,7 +1,7 @@
import importlib
from django.apps import apps
from .registry import model_registry
from collections import defaultdict
from .registry import model_registry
from .models import BaseModel, SideStoreModel
import random
import string
@ -50,7 +50,7 @@ class HierarchyOrganizer:
def __init__(self):
self.levels = [] # List of dictionaries, each representing a level
self.item_levels = {} # Keep track of items and their levels: (model_name, id) -> level
self.sharing_related_instances = {} # Keep track of items and their levels: (model_name, id) -> level
self.children = set()
def add_item(self, model_name, item_data, level):
"""
@ -91,3 +91,43 @@ class HierarchyOrganizer:
if cleaned_dict:
cleaned_levels.append(cleaned_dict)
return cleaned_levels
def add_relations(self, instance):
self.add_related_parents(instance)
self.add_related_children(instance)
def add_related_children(self, instance):
instance.get_shared_children(self.children)
def grouped_children(self):
grouped = defaultdict(list)
for instance in self.children:
class_name = instance.__class__.__name__
# serializer = get_serializer(instance, class_name)
grouped[class_name].append(instance.data_identifier_dict())
return dict(grouped)
def add_related_parents(self, instance, current_level=0):
"""
Recursively add all parents of an instance to the hierarchy organizer.
Parents are added at a higher level than their children.
"""
parent_models = instance.get_parents_by_model()
for parent_model_name, parent in parent_models.items():
if isinstance(parent, BaseModel):
store_id = None
if isinstance(parent, SideStoreModel):
store_id = parent.store_id
parent_data = {
'model_id': parent.id,
'store_id': store_id
}
# Add parent at the next level
# print(f'*** add parent: {parent_model_name}: {parent.id}')
self.add_item(parent_model_name, parent_data, current_level + 1)
# Recursively process parent's parents
self.add_related_parents(parent, current_level + 1)

@ -30,6 +30,25 @@ logger = logging.getLogger(__name__)
# class HierarchyApiView(APIView):
def instances_to_dict(instances, models_dict):
for instance in instances:
child_model_name = instance.__class__.__name__
serializer = get_serializer(instance, child_model_name)
if child_model_name not in models_dict:
models_dict[child_model_name] = {}
models_dict[child_model_name][instance.id] = serializer.data
return models_dict
def instances_to_data_identifier_dict(instances, models_dict):
for instance in instances:
if isinstance(instance, BaseModel):
child_model_name = instance.__class__.__name__
if child_model_name not in models_dict:
models_dict[child_model_name] = {}
models_dict[child_model_name][instance.id] = instance.data_identifier_dict()
return models_dict
def add_children_hierarchy(instance, models_dict):
sync_models = getattr(settings, 'SYNC_MODEL_CHILDREN_SHARING', {})
if instance.__class__.__name__ in sync_models:
@ -79,30 +98,30 @@ def add_children_recursively(instance, models_dict):
models_dict[child_model_name][child.id] = serializer.data
add_children_recursively(child, models_dict)
def add_parents_with_hierarchy_organizer(instance, hierarchy_organizer, current_level=0):
"""
Recursively add all parents of an instance to the hierarchy organizer.
Parents are added at a higher level than their children.
"""
parent_models = instance.get_parents_by_model()
# def add_parents_with_hierarchy_organizer(instance, hierarchy_organizer, current_level=0):
# """
# Recursively add all parents of an instance to the hierarchy organizer.
# Parents are added at a higher level than their children.
# """
# parent_models = instance.get_parents_by_model()
for parent_model_name, parent in parent_models.items():
if isinstance(parent, BaseModel):
store_id = None
if isinstance(parent, SideStoreModel):
store_id = parent.store_id
# for parent_model_name, parent in parent_models.items():
# if isinstance(parent, BaseModel):
# store_id = None
# if isinstance(parent, SideStoreModel):
# store_id = parent.store_id
parent_data = {
'model_id': parent.id,
'store_id': store_id
}
# parent_data = {
# 'model_id': parent.id,
# 'store_id': store_id
# }
# Add parent at the next level
print(f'*** add parent: {parent_model_name}: {parent.id}')
hierarchy_organizer.add_item(parent_model_name, parent_data, current_level + 1)
# # Add parent at the next level
# print(f'*** add parent: {parent_model_name}: {parent.id}')
# hierarchy_organizer.add_item(parent_model_name, parent_data, current_level + 1)
# Recursively process parent's parents
add_parents_with_hierarchy_organizer(parent, hierarchy_organizer, current_level + 1)
# # Recursively process parent's parents
# add_parents_with_hierarchy_organizer(parent, hierarchy_organizer, current_level + 1)
def add_parents_recursively(instance, dictionary):
"""
@ -363,15 +382,11 @@ class LogProcessingResult:
def process_revocations(self):
"""Process revocations and their hierarchies."""
revocations = defaultdict(list)
revocations_parents_organizer = HierarchyOrganizer()
# logger.info(f'$$$ process_revocations: {len(self.revoke_info)}')
# sync_models = getattr(settings, 'SYNC_MODEL_CHILDREN_SHARING', {})
revocated_relations_organizer = HierarchyOrganizer()
# First, collect all revocations
for model_name, items in self.revoke_info.items():
revocations[model_name].extend(items)
logger.info(f'$$$ process_revocations for {model_name}, items = {len(items)}')
# Process parent hierarchies for each revoked item
@ -383,23 +398,20 @@ class LogProcessingResult:
try:
instance = model.objects.get(id=item['model_id'])
logger.info(f'$$$ process revoked item parents of {model_name} : {item['model_id']}')
add_parents_with_hierarchy_organizer(instance, revocations_parents_organizer)
# if instance.__class__.__name__ in sync_models:
# sharing_related_instances = sharing_related_instances(instance, True)
# logger.info(f'$$$ get shared instances: {len(sharing_related_instances)}')
# revocations = merge_dicts_dedup(revocations, sharing_related_instances)
# # revocations_parents_organizer.sharing_related_instances = instance.sharing_related_instances()
revocated_relations_organizer.add_relations(instance)
except model.DoesNotExist:
pass
return revocations, revocations_parents_organizer
children = revocated_relations_organizer.grouped_children()
merged_revocations = merge_dicts(revocations, children)
return merged_revocations, revocated_relations_organizer
def get_response_data(self):
"""Construct the complete response data structure."""
shared, grants = self.process_shared()
revocations, revocations_parents_organizer = self.process_revocations()
revocations, revocated_relations_organizer = self.process_revocations()
# print(f'self.deletions = {dict(self.deletions)}')
# print(f'self.shared_relationship_sets = {self.shared_relationship_sets}')
@ -413,7 +425,7 @@ class LogProcessingResult:
"shared": dict(shared),
"grants": dict(grants),
"revocations": dict(revocations),
"revocation_parents": revocations_parents_organizer.get_organized_data(),
"revocated_relations": revocated_relations_organizer.get_organized_data(),
"shared_relationship_sets": self.shared_relationship_sets,
"shared_relationship_removals": self.shared_relationship_removals,
"date": self.last_log_date
@ -472,60 +484,11 @@ class DataAccessViewSet(viewsets.ModelViewSet):
return self.queryset.filter(Q(related_user=self.request.user) | Q(shared_with__in=[self.request.user]))
return []
def merge_dicts_dedup(dict1, dict2):
"""Merge two dictionaries, combining arrays and removing duplicates"""
all_keys = set(dict1.keys()) | set(dict2.keys())
merged = {}
for key in all_keys:
arr1 = dict1.get(key, [])
arr2 = dict2.get(key, [])
# Convert to sets, union them, then back to list to remove duplicates
merged[key] = list(set(arr1) | set(arr2))
return merged
def sharing_related_instances(instance, identifiers_only):
sync_models = getattr(settings, 'SYNC_MODEL_CHILDREN_SHARING', {})
# if self.__class__.__name__ in sync_models:
relationships = sync_models[instance.__class__.__name__]
# 'Match': {'team_scores', 'team_registration', 'player_registrations'}
models_dict = defaultdict(dict)
print(f'relationships = {relationships}')
current = [instance]
for relationship in relationships:
print(f'> relationship = {relationship}')
values = []
for item in current:
value = getattr(item, relationship)
if hasattr(value, 'all') and callable(value.all):
# This is a queryset from a reverse relationship
for related_obj in value.all():
child_model_name = related_obj.__class__.__name__
if identifiers_only:
models_dict[child_model_name].append(related_obj.data_identifier_dict())
else:
serializer = get_serializer(related_obj, child_model_name)
models_dict[child_model_name].append(serializer.data)
# print(f'>>> 1 Added child for {relationship}: {child_model_name}')
values.extend(value.all())
else:
# This is a single object
child_model_name = value.__class__.__name__
if identifiers_only:
models_dict[child_model_name].append(value.data_identifier_dict())
else:
serializer = get_serializer(value, child_model_name)
models_dict[child_model_name].append(serializer.data)
def merge_dicts(dict1, dict2):
result = defaultdict(list)
# serializer = get_serializer(value, child_model_name)
# models_dict[child_model_name][value.id] = serializer.data
# print(f'>>> 2 Added child for {relationship}: {child_model_name}')
for d in [dict1, dict2]:
for key, value in d.items():
result[key].extend(value)
values.append(value)
current = values
return models_dict
return dict(result)

Loading…
Cancel
Save