sync
Laurent 12 months ago
parent 41ba44df98
commit 1f4687f78a
  1. 97
      api/sync.py
  2. 3
      api/utils.py
  3. 100
      tournaments/migrations/0100_club_last_updated_by_court_last_updated_by_and_more.py
  4. 5
      tournaments/models/base.py
  5. 84
      tournaments/models/data_access.py
  6. 4
      tournaments/models/date_interval.py
  7. 4
      tournaments/models/event.py
  8. 4
      tournaments/models/group_stage.py
  9. 4
      tournaments/models/match.py
  10. 4
      tournaments/models/player_registration.py
  11. 4
      tournaments/models/purchase.py
  12. 4
      tournaments/models/round.py
  13. 4
      tournaments/models/team_score.py
  14. 2
      tournaments/models/tournament.py
  15. 64
      tournaments/signals.py

@ -7,6 +7,7 @@ from rest_framework import status
from django.apps import apps from django.apps import apps
from django.utils import timezone from django.utils import timezone
from django.db.models import Q from django.db.models import Q
from django.core.exceptions import ObjectDoesNotExist
from collections import defaultdict from collections import defaultdict
@ -28,17 +29,14 @@ class DataApi(APIView):
print(f"DataApi post > {model_operation} {model_name}") print(f"DataApi post > {model_operation} {model_name}")
serializer_class = build_serializer_class(model_name) serializer_class = build_serializer_class(model_name)
data['last_updated_by'] = request.user.id # always refresh the user performing the operation
model = apps.get_model(app_label='tournaments', model_name=model_name) model = apps.get_model(app_label='tournaments', model_name=model_name)
now = timezone.localtime(timezone.now()) now = timezone.localtime(timezone.now())
try: try:
data_id = data.get('id') data_id = data.get('id')
# instance = model.objects.get(id=data_id)
instance = get_data('tournaments', model_name, data_id) instance = get_data('tournaments', model_name, data_id)
# update the possible data access objects with the current date
if model_operation == 'DELETE': if model_operation == 'DELETE':
parent_model, parent_id = instance.get_parent_reference() parent_model, parent_id = instance.get_parent_reference()
return self.delete_and_save_log(request, data_id, model_operation, model_name, store_id, now) return self.delete_and_save_log(request, data_id, model_operation, model_name, store_id, now)
@ -62,9 +60,10 @@ class DataApi(APIView):
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def save_and_create_log(self, request, serializer, model_operation, model_name, store_id, date): def save_and_create_log(self, request, serializer, model_operation, model_name, store_id, date):
instance = serializer.save() instance = serializer.save()
self.create_and_save_model_log( self.save_model_log(
user=request.user, user=request.user,
model_operation=model_operation, model_operation=model_operation,
model_name=model_name, model_name=model_name,
@ -84,10 +83,10 @@ class DataApi(APIView):
instance.delete() instance.delete()
# we delete all previous logs linked to the instance because they won't be needed anymore # We delete all previous logs linked to the instance because they won't be needed anymore
ModelLog.objects.filter(model_id=data_id).delete() ModelLog.objects.filter(model_id=data_id).delete()
self.create_and_save_model_log( self.save_model_log(
user=request.user, user=request.user,
model_operation=model_operation, model_operation=model_operation,
model_name=model_name, model_name=model_name,
@ -108,15 +107,21 @@ class DataApi(APIView):
data_access.last_hierarchy_update = date data_access.last_hierarchy_update = date
data_access.save() data_access.save()
def create_and_save_model_log(self, user, model_operation, model_name, model_id, store_id, date): def save_model_log(self, user, model_operation, model_name, model_id, store_id, date):
model_log = ModelLog() existing_log = ModelLog.objects.filter(user=user, model_id=model_id, operation=model_operation).first()
model_log.user = user if existing_log:
model_log.operation = model_operation existing_log.date = date
model_log.date = date existing_log.model_operation = model_operation
model_log.model_name = model_name existing_log.save()
model_log.model_id = model_id else:
model_log.store_id = store_id model_log = ModelLog()
model_log.save() model_log.user = user
model_log.operation = model_operation
model_log.date = date
model_log.model_name = model_name
model_log.model_id = model_id
model_log.store_id = store_id
model_log.save()
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
last_update = request.query_params.get('last_update') last_update = request.query_params.get('last_update')
@ -130,29 +135,32 @@ class DataApi(APIView):
updates = defaultdict(dict) updates = defaultdict(dict)
deletions = defaultdict(list) deletions = defaultdict(list)
print(f'>>> log count = {len(logs)}') # print(f'>>> log count = {len(logs)}')
for log in logs: for log in logs:
if log.operation in ['POST', 'PUT']: try:
data = get_serialized_data('tournaments', log.model_name, log.model_id) if log.operation in ['POST', 'PUT']:
updates[log.model_name][log.model_id] = data data = get_serialized_data('tournaments', log.model_name, log.model_id)
elif log.operation == 'DELETE': updates[log.model_name][log.model_id] = data
deletions[log.model_name].append({'model_id': log.model_id, 'store_id': log.store_id}) elif log.operation == 'DELETE':
elif log.operation == 'GRANT_ACCESS': deletions[log.model_name].append({'model_id': log.model_id, 'store_id': log.store_id})
elif log.operation == 'GRANT_ACCESS':
model = apps.get_model('tournaments', model_name=log.model_name)
instance = model.objects.get(id=log.model_id) model = apps.get_model('tournaments', model_name=log.model_name)
serializer_class = build_serializer_class(log.model_name) instance = model.objects.get(id=log.model_id)
serializer = serializer_class(instance) serializer_class = build_serializer_class(log.model_name)
serializer = serializer_class(instance)
# data = get_serialized_data('tournaments', log.model_name, log.model_id)
updates[log.model_name][log.model_id] = serializer.data # data = get_serialized_data('tournaments', log.model_name, log.model_id)
# instance = model.objects.get(id=log.model_id) updates[log.model_name][log.model_id] = serializer.data
self.add_children_recursively(instance, updates) # instance = model.objects.get(id=log.model_id)
self.add_parents_recursively(instance, updates) self.add_children_recursively(instance, updates)
elif log.operation == 'delete data access signal': self.add_parents_recursively(instance, updates)
print(f'revoke access {log.model_id} - {log.store_id}') elif log.operation == 'delete data access signal':
deletions[log.model_name].append({'model_id': log.model_id, 'store_id': log.store_id}) 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})
except ObjectDoesNotExist:
pass
# Convert updates dict to list for each model # Convert updates dict to list for each model
for model_name in updates: for model_name in updates:
@ -179,16 +187,19 @@ class DataApi(APIView):
data_access_query = Q(last_hierarchy_update__gt=last_update) & (Q(shared_with__in=[user]) | Q(owner=user)) 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) data_access_list = DataAccess.objects.filter(data_access_query) #.values_list('model_id', flat=True)
print(f'>> da count = {len(data_access_list)}') # print(f'>> da count = {len(data_access_list)}')
# get ids of all recently updated related instances of each shared data # get ids of all recently updated related instances of each shared data
model_ids = [] model_ids = []
for data_access in data_access_list: for data_access in data_access_list:
instance = get_data('tournaments', data_access.model_name, data_access.model_id) model_ids.append(data_access.model_id)
related_instances = instance.related_instances() try:
related_ids = [ri.id for ri in instance.related_instances() if ri.last_update > last_update] instance = get_data('tournaments', data_access.model_name, data_access.model_id)
model_ids.extend(related_ids) related_instances = instance.related_instances()
model_ids.append(instance.id) 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 # get all ModelLog list since the last_update, from the user and from the data he has access to
log_query = Q(date__gt=last_update) & (Q(user=user) | Q(model_id__in=model_ids)) log_query = Q(date__gt=last_update) & (Q(user=user) | Q(model_id__in=model_ids))

@ -26,9 +26,6 @@ def build_serializer_class(source):
def get_data(app_label, model_name, model_id): def get_data(app_label, model_name, model_id):
model = apps.get_model(app_label=app_label, model_name=model_name) model = apps.get_model(app_label=app_label, model_name=model_name)
return model.objects.get(id=model_id) return model.objects.get(id=model_id)
# serializer_class = build_serializer_class(model_name)
# serializer = serializer_class(instance)
# return serializer.data
def get_serialized_data(app_label, model_name, model_id): def get_serialized_data(app_label, model_name, model_id):
model = apps.get_model(app_label=app_label, model_name=model_name) model = apps.get_model(app_label=app_label, model_name=model_name)

@ -0,0 +1,100 @@
# Generated by Django 5.1 on 2024-11-20 14:15
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tournaments', '0099_dataaccess_last_hierarchy_update'),
]
operations = [
migrations.AddField(
model_name='club',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='court',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='dataaccess',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='dateinterval',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='devicetoken',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='event',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='failedapicall',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='groupstage',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='log',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='match',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='playerregistration',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='purchase',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='round',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='teamregistration',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='teamscore',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='tournament',
name='last_updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='tournament',
name='event',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tournaments', to='tournaments.event'),
),
]

@ -5,14 +5,11 @@ from typing import List, Set
class BaseModel(models.Model): class BaseModel(models.Model):
creation_date = models.DateTimeField(default=now, editable=False) creation_date = models.DateTimeField(default=now, editable=False)
last_update = models.DateTimeField(default=now) last_update = models.DateTimeField(default=now)
# last_updated_by = models.ForeignKey('CustomUser', blank=True, null=True, on_delete=models.SET_NULL) last_updated_by = models.ForeignKey('CustomUser', blank=True, null=True, on_delete=models.SET_NULL)
class Meta: class Meta:
abstract = True abstract = True
def get_owner(self):
return None
def get_parent_reference(self): def get_parent_reference(self):
"""Return a tuple: model_name, model_id""" """Return a tuple: model_name, model_id"""
return None, None return None, None

@ -1,6 +1,8 @@
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.apps import apps from django.apps import apps
from django.core.exceptions import ObjectDoesNotExist
import uuid import uuid
from . import ModelLog, SideStoreModel, BaseModel from . import ModelLog, SideStoreModel, BaseModel
@ -14,66 +16,28 @@ class DataAccess(BaseModel):
granted_at = models.DateTimeField(auto_now_add=True) granted_at = models.DateTimeField(auto_now_add=True)
last_hierarchy_update = models.DateTimeField(default=timezone.now) last_hierarchy_update = models.DateTimeField(default=timezone.now)
# def save(self, *args, **kwargs):
# is_new = self._state.adding
# print('>>> save DA')
# if not is_new:
# # Store old shared_with users before save
# old_instance = DataAccess.objects.get(pk=self.pk)
# self._old_shared_with = set(old_instance.shared_with.all())
# super().save(*args, **kwargs)
# if is_new:
# # For new instances, create logs for all shared users
# self.create_access_logs('GRANT_ACCESS')
# else:
# # For updates, handle differences
# new_shared_with = set(self.shared_with.all())
# # Users that were added
# added_users = new_shared_with - self._old_shared_with
# for user in added_users:
# self.create_access_log(user, 'GRANT_ACCESS')
# # Users that were removed
# removed_users = self._old_shared_with - new_shared_with
# for user in removed_users:
# self.create_access_log(user, 'REVOKE_ACCESS')
# def delete(self, *args, **kwargs):
# # Store users before deletion
# users_to_revoke = list(self.shared_with.all())
# # First delete the instance
# super().delete(*args, **kwargs)
# # Then create revoke logs for all users
# for user in users_to_revoke:
# self.create_access_log(user, 'REVOKE_ACCESS')
# def create_access_logs(self, operation):
# """Create logs for all shared users"""
# users = self.shared_with.all()
# print(f'>>> create logs for users = {len(users)}')
# for user in self.shared_with.all():
# self.create_access_log(user, operation)
def create_access_log(self, user, operation): def create_access_log(self, user, operation):
"""Create a single access log for a specific user""" """Create a single access log for a specific user"""
model_class = apps.get_model('tournaments', self.model_name) model_class = apps.get_model('tournaments', self.model_name)
obj = model_class.objects.get(id=self.model_id) try:
store_id = None obj = model_class.objects.get(id=self.model_id)
if isinstance(obj, SideStoreModel): store_id = None
store_id = obj.store_id if isinstance(obj, SideStoreModel):
store_id = obj.store_id
ModelLog.objects.create(
user=user, existing_log = ModelLog.objects.filter(user=user, model_id=self.model_id, operation=operation).first()
model_id=self.model_id, if existing_log:
model_name=self.model_name, existing_log.date = timezone.now()
operation=operation, existing_log.model_operation = operation
date=timezone.now(), existing_log.save()
store_id=store_id else:
) ModelLog.objects.create(
user=user,
model_id=self.model_id,
model_name=self.model_name,
operation=operation,
date=timezone.now(),
store_id=store_id
)
except ObjectDoesNotExist:
pass

@ -9,10 +9,6 @@ class DateInterval(BaseModel):
start_date = models.DateTimeField() start_date = models.DateTimeField()
end_date = models.DateTimeField() end_date = models.DateTimeField()
# Required for sync web sockets update
def get_owner(self):
return self.event.creator
# Data Access # Data Access
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.event.id return 'Event', self.event.id

@ -15,10 +15,6 @@ class Event(BaseModel):
def __str__(self): def __str__(self):
return self.display_name() return self.display_name()
# Required for sync web sockets update
def get_owner(self):
return self.creator
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.creator: if self.creator:
self.creator_full_name = self.creator.full_name() self.creator_full_name = self.creator.full_name()

@ -19,10 +19,6 @@ class GroupStage(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament.event.id return 'Event', self.tournament.event.id
# Required for sync web sockets update
def get_owner(self):
return self.tournament.event.creator
def __str__(self): def __str__(self):
return self.display_name() return self.display_name()
# return f"{self.tournament.display_name()} - {self.display_name()}" # return f"{self.tournament.display_name()} - {self.display_name()}"

@ -30,10 +30,6 @@ class Match(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament().event.id return 'Event', self.tournament().event.id
# Required for sync web sockets update
def get_owner(self):
return self.tournament().event.creator
def __str__(self): def __str__(self):
names = " / ".join(self.player_names()) names = " / ".join(self.player_names())
return f"{self.stage_name()} #{self.index}: {names}" return f"{self.stage_name()} #{self.index}: {names}"

@ -38,10 +38,6 @@ class PlayerRegistration(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.team_registration.tournament.event.id return 'Event', self.team_registration.tournament.event.id
# Required for sync web sockets update
def get_owner(self):
return self.team_registration.tournament.event.creator
def __str__(self): def __str__(self):
return self.name() return self.name()

@ -13,7 +13,3 @@ class Purchase(BaseModel):
def __str__(self): def __str__(self):
return f"{self.identifier} > {self.product_id} - {self.purchase_date} - {self.user.username}" return f"{self.identifier} > {self.product_id} - {self.purchase_date} - {self.user.username}"
# Required for sync web sockets update
def get_owner(self):
return self.user

@ -14,10 +14,6 @@ class Round(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament.event.id return 'Event', self.tournament.event.id
# Required for sync web sockets update
def get_owner(self):
return self.tournament.event.creator
def __str__(self): def __str__(self):
if self.parent: if self.parent:
return f"LB: {self.name()}" return f"LB: {self.name()}"

@ -17,10 +17,6 @@ class TeamScore(SideStoreModel):
def get_parent_reference(self): def get_parent_reference(self):
return 'Event', self.tournament().event.id return 'Event', self.tournament().event.id
# Required for sync web sockets update
def get_owner(self):
return self.tournament().event.creator
def tournament(self): def tournament(self):
if self.team_registration: if self.team_registration:
return self.team_registration.tournament return self.team_registration.tournament

@ -17,7 +17,7 @@ class TeamSortingType(models.IntegerChoices):
class Tournament(BaseModel): class Tournament(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE, related_name="events") event = models.ForeignKey(Event, blank=True, null=True, on_delete=models.CASCADE, related_name="tournaments")
name = models.CharField(max_length=200, null=True, blank=True) name = models.CharField(max_length=200, null=True, blank=True)
start_date = models.DateTimeField() start_date = models.DateTimeField()
end_date = models.DateTimeField(null=True, blank=True) end_date = models.DateTimeField(null=True, blank=True)

@ -27,24 +27,30 @@ def synchronization_notifications(sender, instance, **kwargs):
if sender in [FailedApiCall, Log, ModelLog]: if sender in [FailedApiCall, Log, ModelLog]:
return return
channel_layer = get_channel_layer() if kwargs.get('signal') == post_delete:
delete_data_access_if_necessary(instance.id)
print(f'*** signals {sender}')
user_ids = set() user_ids = set()
# add impacted users
if isinstance(instance, CustomUser): if isinstance(instance, CustomUser):
user_ids.add(instance.id) user_ids.add(instance.id)
elif isinstance(instance, DataAccess):
for shared_user in instance.shared_with.all():
user_ids.add(shared_user.id)
elif isinstance(instance, BaseModel): elif isinstance(instance, BaseModel):
owner = instance.get_owner() owner = instance.last_updated_by
if owner is not None: if owner is not None:
user_ids.add(owner.id) user_ids.add(owner.id)
if isinstance(instance, BaseModel): if isinstance(instance, BaseModel):
parent_model, data_access_reference_id = instance.get_parent_reference()
data_access_query = Q(model_id=instance.id) data_access_query = Q(model_id=instance.id)
if data_access_reference_id is not None: if kwargs.get('signal') != post_delete:
data_access_query |= Q(model_id=data_access_reference_id) # when deleting objects, accessing reference generates DoesNotExist exceptions
parent_model, data_access_reference_id = instance.get_parent_reference()
if data_access_reference_id is not None:
data_access_query |= Q(model_id=data_access_reference_id)
# look for users through data access objects
data_access_list = DataAccess.objects.filter(data_access_query) data_access_list = DataAccess.objects.filter(data_access_query)
for data_access in data_access_list: for data_access in data_access_list:
user_ids.add(data_access.owner.id) user_ids.add(data_access.owner.id)
@ -52,13 +58,20 @@ def synchronization_notifications(sender, instance, **kwargs):
user_ids.add(shared_user.id) user_ids.add(shared_user.id)
for user_id in user_ids: for user_id in user_ids:
group_name = f"sync_{user_id}" send_user_message(user_id)
print(f">>> send to group {group_name}")
# Send to all clients in the sync group def delete_data_access_if_necessary(model_id):
async_to_sync(channel_layer.group_send)( DataAccess.objects.filter(model_id=model_id).delete()
group_name, {"type": "sync.update", "message": "hello"}
) def send_user_message(user_id):
group_name = f"sync_{user_id}"
print(f">>> send to group {group_name}")
# Send to all clients in the sync group
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)(
group_name, {"type": "sync.update", "message": "hello"}
)
@receiver(m2m_changed, sender=DataAccess.shared_with.through) @receiver(m2m_changed, sender=DataAccess.shared_with.through)
def handle_shared_with_changes(sender, instance, action, pk_set, **kwargs): def handle_shared_with_changes(sender, instance, action, pk_set, **kwargs):
@ -66,22 +79,27 @@ def handle_shared_with_changes(sender, instance, action, pk_set, **kwargs):
for user_id in pk_set: for user_id in pk_set:
user = CustomUser.objects.get(id=user_id) user = CustomUser.objects.get(id=user_id)
instance.create_access_log(user, 'GRANT_ACCESS') instance.create_access_log(user, 'GRANT_ACCESS')
send_user_message(user_id)
elif action == "post_remove": elif action == "post_remove":
for user_id in pk_set: for user_id in pk_set:
user = CustomUser.objects.get(id=user_id) user = CustomUser.objects.get(id=user_id)
instance.create_access_log(user, 'REVOKE_ACCESS') instance.create_access_log(user, 'REVOKE_ACCESS')
send_user_message(user_id)
@receiver(pre_delete, sender=DataAccess) @receiver(pre_delete, sender=DataAccess)
def store_users_before_delete(sender, instance, **kwargs):
# Store the users in a temporary attribute that we can access after deletion
instance._users_to_revoke = list(instance.shared_with.all())
@receiver(post_delete, sender=DataAccess)
def revoke_access_after_delete(sender, instance, **kwargs): def revoke_access_after_delete(sender, instance, **kwargs):
# Create revoke logs for all previously stored users for user in instance.shared_with.all():
if hasattr(instance, '_users_to_revoke'): instance.create_access_log(user, 'REVOKE_ACCESS')
for user in instance._users_to_revoke:
instance.create_access_log(user, 'REVOKE_ACCESS') # # Store the users in a temporary attribute that we can access after deletion
# instance._users_to_revoke = list(instance.shared_with.all())
# @receiver(post_delete, sender=DataAccess)
# def revoke_access_after_delete(sender, instance, **kwargs):
# # Create revoke logs for all previously stored users
# if hasattr(instance, '_users_to_revoke'):
# for user in instance._users_to_revoke:
# instance.create_access_log(user, 'REVOKE_ACCESS')
# Others # Others

Loading…
Cancel
Save