diff --git a/api/sync.py b/api/sync.py index 1c27b02..e8e2562 100644 --- a/api/sync.py +++ b/api/sync.py @@ -14,7 +14,7 @@ from urllib.parse import unquote from .utils import build_serializer_class, get_data, get_serialized_data -from tournaments.models import ModelLog, DataAccess, BaseModel +from tournaments.models import ModelLog, DataAccess, BaseModel, SideStoreModel class DataApi(APIView): permission_classes = [IsAuthenticated] @@ -92,9 +92,12 @@ class DataApi(APIView): updates = defaultdict(dict) deletions = defaultdict(list) + revocations = defaultdict(list) # New dictionary for revocations + revocation_parents = defaultdict(dict) last_log_date = None for log in logs: + print(f'log date = {log.date}') last_log_date = log.date try: if log.operation in ['POST', 'PUT']: @@ -116,7 +119,19 @@ class DataApi(APIView): self.add_parents_recursively(instance, updates) elif log.operation == 'REVOKE_ACCESS': print(f'revoke access {log.model_id} - {log.store_id}') - deletions[log.model_name].append({'model_id': log.model_id, 'store_id': log.store_id}) + # Add to revocations instead of deletions + revocations[log.model_name].append({ + 'model_id': log.model_id, + 'store_id': log.store_id + }) + + # Get the model instance and add its parents to revocation_parents + model = apps.get_model('tournaments', model_name=log.model_name) + try: + instance = model.objects.get(id=log.model_id) + self.add_parents_recursively(instance, revocation_parents, minimal=True) + except model.DoesNotExist: + pass except ObjectDoesNotExist: pass @@ -128,12 +143,18 @@ class DataApi(APIView): for model_name in deletions: deletions[model_name] = deletions[model_name] + for model_name in revocation_parents: + revocation_parents[model_name] = list(revocation_parents[model_name].values()) + response_data = { "updates": dict(updates), "deletions": dict(deletions), + "revocations": dict(revocations), + "revocation_parents": dict(revocation_parents), "date": last_log_date } + print(f'response_data = {response_data}') return Response(response_data, status=status.HTTP_200_OK) def query_model_logs(self, last_update, user): @@ -141,27 +162,6 @@ class DataApi(APIView): log_query = Q(date__gt=last_update) & Q(users=user) return ModelLog.objects.filter(log_query).order_by('date') - # get recently modified DataAccess - # data_access_query = Q(last_hierarchy_update__gt=last_update) & (Q(shared_with__in=[user]) | Q(owner=user)) - # data_access_list = DataAccess.objects.filter(data_access_query) #.values_list('model_id', flat=True) - - # print(f'>> da count = {len(data_access_list)}') - - # # get ids of all recently updated related instances of each shared data - # model_ids = [] - # for data_access in data_access_list: - # model_ids.append(data_access.model_id) - # try: - # instance = get_data('tournaments', data_access.model_name, data_access.model_id) - # related_instances = instance.related_instances() - # related_ids = [ri.id for ri in instance.related_instances() if ri.last_update > last_update] - # model_ids.extend(related_ids) - # except ObjectDoesNotExist: - # pass - - # get all ModelLog list since the last_update, from the user and from the data he has access to - - def add_children_recursively(self, instance, updates): """ Recursively add all children of an instance to the updates dictionary. @@ -177,19 +177,38 @@ class DataApi(APIView): updates[child_model_name][child.id] = serializer.data self.add_children_recursively(child, updates) - def add_parents_recursively(self, instance, updates): + # def add_parents_recursively(self, instance, updates): + # parent_models = instance.get_parents_by_model() + + # for parent_model_name, parent in parent_models.items(): + # # print(f'parent = {parent_model_name}') + # if isinstance(parent, BaseModel): + # serializer_class = build_serializer_class(parent_model_name) + # serializer = serializer_class(parent) + # updates[parent_model_name][parent.id] = serializer.data + # self.add_parents_recursively(parent, updates) + + def add_parents_recursively(self, instance, dictionary, minimal=False): + """ + Recursively add all parents of an instance to the updates dictionary. + If minimal=True, only add id and store_id. + """ parent_models = instance.get_parents_by_model() for parent_model_name, parent in parent_models.items(): - # print(f'parent = {parent_model_name}') if isinstance(parent, BaseModel): - serializer_class = build_serializer_class(parent_model_name) - serializer = serializer_class(parent) - updates[parent_model_name][parent.id] = serializer.data - self.add_parents_recursively(parent, updates) - - # def get_data(self, model, log): - # instance = model.objects.get(id=log.model_id) - # serializer_class = build_serializer_class(log.model_name) - # serializer = serializer_class(instance) - # return serializer.data + if minimal: + store_id = None + if isinstance(parent, SideStoreModel): + store_id = parent.store_id + dictionary[parent_model_name][parent.id] = { + 'model_id': parent.id, + 'store_id': store_id + } + else: + # Add full serialized data + serializer_class = build_serializer_class(parent_model_name) + serializer = serializer_class(parent) + dictionary[parent_model_name][parent.id] = serializer.data + + self.add_parents_recursively(parent, dictionary, minimal) diff --git a/tournaments/models/model_log.py b/tournaments/models/model_log.py index 1e80ce2..ee77ff0 100644 --- a/tournaments/models/model_log.py +++ b/tournaments/models/model_log.py @@ -12,3 +12,10 @@ class ModelLog(models.Model): store_id = models.CharField(max_length=200, blank=True, null=True) # parent_model_id = models.UUIDField(blank=True, null=True) # parent_model_name = models.CharField(max_length=50, blank=True, null=True) + + def save(self, *args, **kwargs): + # Round microseconds to milliseconds (3 decimal places) + if self.date: + microseconds = round(self.date.microsecond, -3) # Round to nearest thousand + self.date = self.date.replace(microsecond=microseconds) + super().save(*args, **kwargs)