data access first working version

sync
Laurent 1 year ago
parent 415f70458c
commit 0829a1e246
  1. 32
      api/views.py
  2. 23
      tournaments/migrations/0093_modellog_parent_model_id_modellog_parent_model_name.py
  3. 23
      tournaments/migrations/0094_remove_dataaccess_shared_with_dataaccess_shared_with.py
  4. 25
      tournaments/migrations/0095_remove_dataaccess_shared_with_dataaccess_shared_with.py
  5. 28
      tournaments/migrations/0096_alter_modellog_operation_and_more.py
  6. 3
      tournaments/models/base.py
  7. 14
      tournaments/models/data_access.py
  8. 4
      tournaments/models/date_interval.py
  9. 2
      tournaments/models/enums.py
  10. 6
      tournaments/models/event.py
  11. 9
      tournaments/models/group_stage.py
  12. 9
      tournaments/models/match.py
  13. 4
      tournaments/models/model_log.py
  14. 4
      tournaments/models/player_registration.py
  15. 9
      tournaments/models/round.py
  16. 8
      tournaments/models/team_registration.py
  17. 13
      tournaments/models/tournament.py
  18. 30
      tournaments/signals.py

@ -138,25 +138,29 @@ class DataApi(APIView):
updates = defaultdict(dict)
deletions = defaultdict(list)
print(f'>>> log count = {len(logs)}')
for log in logs:
model = apps.get_model(app_label='tournaments', model_name=log.model_name)
if log.operation in ['POST', 'PUT']:
try:
data = self.get_data(model, log)
# instance = model.objects.get(id=log.model_id)
# serializer_class = build_serializer_class(log.model_name)
# serializer = serializer_class(instance)
updates[log.model_name][log.model_id] = data
except model.DoesNotExist:
# If the instance doesn't exist, it might have been deleted after this log was created
pass
elif log.operation == 'DELETE':
deletions[log.model_name].append({'model_id': log.model_id, 'store_id': log.store_id})
elif log.operation == 'SHARE':
elif log.operation == 'GRANT_ACCESS':
data = self.get_data(model, log)
updates[log.model_name][log.model_id] = data
instance = model.objects.get(id=log.model_id)
self.add_children_recursively(instance, updates)
elif log.operation == 'REVOKE_ACCESS':
print(f'revoke access {log.model_id} - {log.store_id}')
# data = self.get_data(model, log)
deletions[log.model_name].append({'model_id': log.model_id, 'store_id': log.store_id})
# Convert updates dict to list for each model
for model_name in updates:
@ -176,6 +180,24 @@ class DataApi(APIView):
return Response(response_data, status=status.HTTP_200_OK)
def add_children_recursively(self, instance, updates):
"""
Recursively add all children of an instance to the updates dictionary.
"""
child_models = instance.get_child_models()
for child_model_name, related_name in child_models.items():
child_model = apps.get_model(app_label='tournaments', model_name=child_model_name)
children = getattr(instance, related_name).all()
for child in children:
serializer_class = build_serializer_class(child_model_name)
serializer = serializer_class(child)
updates[child_model_name][child.id] = serializer.data
# Recursive call for each child
self.add_children_recursively(child, updates)
def get_data(self, model, log):
instance = model.objects.get(id=log.model_id)
serializer_class = build_serializer_class(log.model_name)

@ -0,0 +1,23 @@
# Generated by Django 5.1 on 2024-11-08 15:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tournaments', '0092_dataaccess'),
]
operations = [
migrations.AddField(
model_name='modellog',
name='parent_model_id',
field=models.UUIDField(null=True),
),
migrations.AddField(
model_name='modellog',
name='parent_model_name',
field=models.CharField(max_length=50, null=True),
),
]

@ -0,0 +1,23 @@
# Generated by Django 5.1 on 2024-11-08 16:16
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tournaments', '0093_modellog_parent_model_id_modellog_parent_model_name'),
]
operations = [
migrations.RemoveField(
model_name='dataaccess',
name='shared_with',
),
migrations.AddField(
model_name='dataaccess',
name='shared_with',
field=models.ManyToManyField(related_name='shared_data', to=settings.AUTH_USER_MODEL),
),
]

@ -0,0 +1,25 @@
# Generated by Django 5.1 on 2024-11-08 16:45
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tournaments', '0094_remove_dataaccess_shared_with_dataaccess_shared_with'),
]
operations = [
migrations.RemoveField(
model_name='dataaccess',
name='shared_with',
),
migrations.AddField(
model_name='dataaccess',
name='shared_with',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, related_name='shared_data', to=settings.AUTH_USER_MODEL),
preserve_default=False,
),
]

@ -0,0 +1,28 @@
# Generated by Django 5.1 on 2024-11-08 16:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('tournaments', '0095_remove_dataaccess_shared_with_dataaccess_shared_with'),
]
operations = [
migrations.AlterField(
model_name='modellog',
name='operation',
field=models.CharField(choices=[('POST', 'POST'), ('PUT', 'PUT'), ('DELETE', 'DELETE'), ('GRANT_ACCESS', 'GRANT_ACCESS'), ('REVOKE_ACCESS', 'REVOKE_ACCESS')], max_length=50),
),
migrations.AlterField(
model_name='modellog',
name='parent_model_id',
field=models.UUIDField(blank=True, null=True),
),
migrations.AlterField(
model_name='modellog',
name='parent_model_name',
field=models.CharField(blank=True, max_length=50, null=True),
),
]

@ -12,6 +12,9 @@ class BaseModel(models.Model):
"""Override in child models to provide parent reference"""
return None, None
def get_child_models(self):
return {}
class SideStoreModel(BaseModel):
store_id = models.CharField(max_length=100)

@ -18,11 +18,17 @@ class DataAccess(models.Model):
super().save(*args, **kwargs)
if is_new:
self.create_initial_sync_logs()
self.create_initial_log()
def create_initial_sync_logs(self):
# def delete(self, *args, **kwargs):
# print('>>> delete data access')
# # Create deletion sync logs before deleting the access
# self.create_deletion_log()
# return super().delete(*args, **kwargs)
model_class = apps.get_model(self.model_name)
def create_initial_log(self):
model_class = apps.get_model('tournaments', self.model_name)
obj = model_class.objects.get(id=self.model_id)
parent_model, parent_id = obj.get_parent_reference()
store_id = None
@ -33,7 +39,7 @@ class DataAccess(models.Model):
user=self.shared_with, # The user receiving access
model_id=self.model_id,
model_name=self.model_name,
operation='SHARE', # New operation type
operation='GRANT_ACCESS',
date=timezone.now(),
store_id=store_id,
parent_model_id=parent_id,

@ -8,3 +8,7 @@ class DateInterval(BaseModel):
court_index = models.IntegerField()
start_date = models.DateTimeField()
end_date = models.DateTimeField()
# Data Access
def get_parent_reference(self):
return 'Event', self.event.id

@ -61,3 +61,5 @@ class ModelOperation(models.TextChoices):
POST = 'POST', 'POST'
PUT = 'PUT', 'PUT'
DELETE = 'DELETE', 'DELETE'
GRANT_ACCESS = 'GRANT_ACCESS', 'GRANT_ACCESS'
REVOKE_ACCESS = 'REVOKE_ACCESS', 'REVOKE_ACCESS'

@ -12,6 +12,12 @@ class Event(BaseModel):
tenup_id = models.CharField(max_length=20, null=True, blank=True)
creator_full_name = models.CharField(max_length=200, null=True, blank=True)
# Data Access
def get_child_models(self):
return {
'Tournament': 'tournament_set',
}
def __str__(self):
return self.display_name()

@ -15,6 +15,15 @@ class GroupStage(SideStoreModel):
start_date = models.DateTimeField(null=True, blank=True)
name = models.CharField(max_length=200, null=True, blank=True)
# Data Access
def get_parent_reference(self):
return 'Event', self.tournament.event.id
def get_child_models(self):
return {
'Match': 'match_set',
}
def __str__(self):
return self.display_name()
# return f"{self.tournament.display_name()} - {self.display_name()}"

@ -26,6 +26,15 @@ class Match(SideStoreModel):
court_index = models.IntegerField(null=True, blank=True)
confirmed = models.BooleanField(default=False)
# Data Access
def get_parent_reference(self):
return 'Event', self.tournament().event.id
def get_child_models(self):
return {
'TeamScore': 'team_scores',
}
def __str__(self):
names = " / ".join(self.player_names())
return f"{self.stage_name()} #{self.index}: {names}"

@ -10,5 +10,5 @@ class ModelLog(models.Model):
date = models.DateTimeField()
model_name = models.CharField(max_length=50)
store_id = models.CharField(max_length=200, blank=True, null=True)
parent_model_id = models.UUIDField(null=True)
parent_model_name = models.CharField(max_length=50, null=True)
parent_model_id = models.UUIDField(blank=True, null=True)
parent_model_name = models.CharField(max_length=50, blank=True, null=True)

@ -34,6 +34,10 @@ class PlayerRegistration(SideStoreModel):
source = models.IntegerField(choices=PlayerDataSource.choices, null=True, blank=True)
has_arrived = models.BooleanField(default=False)
# Data Access
def get_parent_reference(self):
return 'Event', self.team_registration.tournament.event.id
def __str__(self):
return self.name()

@ -10,6 +10,15 @@ class Round(SideStoreModel):
format = models.IntegerField(default=FederalMatchCategory.NINE_GAMES, choices=FederalMatchCategory.choices, null=True, blank=True)
start_date = models.DateTimeField(null=True, blank=True)
# Data Access
def get_parent_reference(self):
return 'Event', self.tournament.event.id
def get_child_models(self):
return {
'Match': 'match_set',
}
def __str__(self):
if self.parent:
return f"LB: {self.name()}"

@ -30,6 +30,14 @@ class TeamRegistration(SideStoreModel):
final_ranking = models.IntegerField(null=True, blank=True)
points_earned = models.IntegerField(null=True, blank=True)
# Data Access
def get_parent_reference(self):
return 'Event', self.tournament.event.id
def get_child_models(self):
return {
'PlayerRegistration': 'playerregistration_set',
}
def __str__(self):
if self.name:

@ -60,6 +60,19 @@ class Tournament(BaseModel):
hide_points_earned = models.BooleanField(default=False)
publish_rankings = models.BooleanField(default=False)
def get_parent_reference(self):
return 'Event', self.event.id
def get_child_models(self):
"""
Returns a dictionary of child model names and their related_names.
"""
return {
'Round': 'round_set',
'GroupStage': 'groupstage_set',
'TeamRegistration': 'teamregistration_set'
}
def __str__(self):
if self.name:
return self.name

@ -1,10 +1,12 @@
import random
import string
from django.db.models.signals import post_save
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver
from django.conf import settings
from django.apps import apps
from django.utils import timezone
from .models import Club, FailedApiCall, CustomUser, Log
from .models import Club, FailedApiCall, CustomUser, Log, DataAccess, ModelLog
import requests
def generate_unique_code():
@ -52,3 +54,27 @@ def send_discord_message(webhook_url, content):
raise ValueError(
f'Error sending message to Discord webhook: {response.status_code}, {response.text}'
)
@receiver(pre_delete, sender=DataAccess)
def data_access_pre_delete(sender, instance, **kwargs):
print('>>> delete data access signal')
try:
model_class = apps.get_model('tournaments', instance.model_name)
obj = model_class.objects.get(id=instance.model_id)
parent_model, parent_id = obj.get_parent_reference()
store_id = None
if hasattr(obj, 'store_id'):
store_id = obj.store_id
ModelLog.objects.create(
user=instance.shared_with,
model_id=instance.model_id,
model_name=instance.model_name,
operation='REVOKE_ACCESS',
date=timezone.now(),
store_id=store_id,
parent_model_id=parent_id,
parent_model_name=parent_model
)
except Exception as e:
print(f"Error in data_access_pre_delete signal: {e}")

Loading…
Cancel
Save