Razmig Sarkissian 5 months ago
commit b00d5885cc
  1. 5
      sync/admin.py
  2. 8
      sync/models/data_access.py
  3. 65
      sync/signals.py
  4. 5
      tournaments/admin.py

@ -6,13 +6,14 @@ from .models import BaseModel, ModelLog, DataAccess
class SyncedObjectAdmin(admin.ModelAdmin): class SyncedObjectAdmin(admin.ModelAdmin):
exclude = ('data_access_ids',) exclude = ('data_access_ids',)
raw_id_fields = ['related_user']
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):
if isinstance(obj, BaseModel): if isinstance(obj, BaseModel):
obj.last_updated_by = request.user obj.last_updated_by = request.user
obj.last_update = timezone.now() obj.last_update = timezone.now()
if obj.related_user is None: # if obj.related_user is None:
obj.related_user = request.user # obj.related_user = request.user
super().save_model(request, obj, form, change) super().save_model(request, obj, form, change)
def delete_model(self, request, obj): def delete_model(self, request, obj):

@ -8,7 +8,9 @@ from ..registry import model_registry
import uuid import uuid
from . import ModelLog, SideStoreModel, BaseModel from . import ModelLog, SideStoreModel, BaseModel
import logging
logger = logging.getLogger(__name__)
class DataAccess(BaseModel): class DataAccess(BaseModel):
id = models.UUIDField(primary_key=True, default=uuid.uuid4) id = models.UUIDField(primary_key=True, default=uuid.uuid4)
@ -40,6 +42,9 @@ class DataAccess(BaseModel):
store_id = obj.store_id store_id = obj.store_id
for user in users: for user in users:
logger.info(f'=== create ModelLog for: {operation} > {users}')
existing_log = ModelLog.objects.filter(user=user, model_id=self.model_id, operation=operation).first() existing_log = ModelLog.objects.filter(user=user, model_id=self.model_id, operation=operation).first()
if existing_log: if existing_log:
existing_log.date = timezone.now() existing_log.date = timezone.now()
@ -55,9 +60,10 @@ class DataAccess(BaseModel):
store_id=store_id store_id=store_id
) )
except ObjectDoesNotExist: except ObjectDoesNotExist:
logger.warn(f'!!! object does not exists any more: {self.model_name} : {self.model_id} : {operation}')
pass pass
else: else:
print(f'model not found: {self.model_name}') logger.warn(f'!!!model not found: {self.model_name}')
def add_references(self): def add_references(self):
model_class = model_registry.get_model(self.model_name) model_class = model_registry.get_model(self.model_name)

@ -6,11 +6,14 @@ from .models import DataAccess, ModelLog, ModelOperation, BaseModel, SideStoreMo
from authentication.models import Device from authentication.models import Device
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.utils import timezone
from .ws_sender import websocket_sender from .ws_sender import websocket_sender
from .registry import device_registry, related_users_registry from .registry import device_registry, related_users_registry
import logging
logger = logging.getLogger(__name__)
User = get_user_model() User = get_user_model()
### Sync ### Sync
@ -28,12 +31,18 @@ def presave_handler(sender, instance, **kwargs):
return return
users = related_users(instance) users = related_users(instance)
# print(f'* impacted users = {users}')
related_users_registry.register(instance.id, users) related_users_registry.register(instance.id, users)
# user_ids = [user.id for user in users] # user_ids = [user.id for user in users]
if signal == pre_save: if signal == pre_save:
detect_foreign_key_changes_for_shared_instances(sender, instance) detect_foreign_key_changes_for_shared_instances(sender, instance)
sig_type = 'pre_save'
else:
sig_type = 'pre_delete'
logger.info(f'* {sig_type} : {instance.__class__.__name__} > impacted users = {users}')
@receiver([post_save, post_delete]) @receiver([post_save, post_delete])
def synchronization_notifications(sender, instance, created=False, **kwargs): def synchronization_notifications(sender, instance, created=False, **kwargs):
@ -87,7 +96,14 @@ def notify_impacted_users(instance):
def save_model_log_if_possible(instance, signal, created): def save_model_log_if_possible(instance, signal, created):
users = related_users_registry.get_users(instance.id) users = related_users_registry.get_users(instance.id)
# print(f'*** save_model_log >>> users = {users}, instance = {instance}') logger.debug(f'*** save_model_log_if_possible >>> users from registry = {users}, instance = {instance}')
if not users:
logger.warning(f'!!! Registry returned empty users for instance {instance.id} ({instance.__class__.__name__})')
# Try to recalculate users as fallback
users = related_users(instance)
logger.info(f'!!! Recalculated users for fallback: {users}')
if users: if users:
if signal == post_save or signal == pre_save: if signal == post_save or signal == pre_save:
if created: if created:
@ -111,16 +127,20 @@ def save_model_log_if_possible(instance, signal, created):
save_model_log(users, operation, model_name, instance.id, store_id) save_model_log(users, operation, model_name, instance.id, store_id)
else: else:
print(f'>>> Model Log could not be created because no linked user could be found: {instance.__class__.__name__} {instance}, {signal}') logger.info(f'!!! Model Log could not be created because no linked user could be found: {instance.__class__.__name__} {instance}, {signal}')
def save_model_log(users, model_operation, model_name, model_id, store_id): def save_model_log(users, model_operation, model_name, model_id, store_id):
device_id = device_registry.get_device_id(model_id) device_id = device_registry.get_device_id(model_id)
# print(f'>> creating Model Log for: {model_operation} {model_name}') logger.info(f'*** creating ModelLogs for: {model_operation} {model_name} : {users}')
logs_to_create = [ try:
ModelLog( with transaction.atomic():
created_logs = []
for user in users:
logger.debug(f'Creating ModelLog for user {user.id} ({user.username})')
model_log = ModelLog(
user=user, user=user,
operation=model_operation, operation=model_operation,
model_name=model_name, model_name=model_name,
@ -128,12 +148,22 @@ def save_model_log(users, model_operation, model_name, model_id, store_id):
store_id=store_id, store_id=store_id,
device_id=device_id device_id=device_id
) )
for user in users model_log.save()
if user.can_synchronize created_logs.append(model_log.id)
] logger.debug(f'Successfully created ModelLog {model_log.id}')
with transaction.atomic(): logger.info(f'*** Successfully created {len(created_logs)} ModelLogs: {created_logs}')
ModelLog.objects.bulk_create(logs_to_create)
# Verify ModelLogs were actually persisted
persisted_count = ModelLog.objects.filter(id__in=created_logs).count()
if persisted_count != len(created_logs):
logger.error(f'*** PERSISTENCE VERIFICATION FAILED! Created {len(created_logs)} ModelLogs but only {persisted_count} were persisted to database')
else:
logger.debug(f'*** PERSISTENCE VERIFIED: All {persisted_count} ModelLogs successfully persisted')
except Exception as e:
logger.error(f'*** FAILED to create ModelLogs for: {model_operation} {model_name}, users: {[u.id for u in users]}, error: {e}', exc_info=True)
raise
# with transaction.atomic(): # with transaction.atomic():
# for user in users: # for user in users:
@ -258,6 +288,7 @@ def handle_shared_with_changes(sender, instance, action, pk_set, **kwargs):
# print(f'm2m changed = {pk_set}') # print(f'm2m changed = {pk_set}')
users = User.objects.filter(id__in=pk_set) users = User.objects.filter(id__in=pk_set)
with transaction.atomic():
if action == "post_add": if action == "post_add":
instance.create_access_log(users, 'SHARED_ACCESS') instance.create_access_log(users, 'SHARED_ACCESS')
elif action == "post_remove": elif action == "post_remove":
@ -302,18 +333,8 @@ def related_users(instance):
users.add(instance) users.add(instance)
elif isinstance(instance, BaseModel): elif isinstance(instance, BaseModel):
users.add(instance.related_user) users.add(instance.related_user)
# users.add(instance.last_updated_by)
# look in hierarchy
# related_instances = instance.related_instances()
# print(f'related_instances = {related_instances}')
# related_users = [ri.related_user for ri in related_instances if isinstance(ri, BaseModel)]
# users.update(related_users)
data_access_list = DataAccess.objects.filter(id__in=instance.data_access_ids) data_access_list = DataAccess.objects.filter(id__in=instance.data_access_ids)
# look in related DataAccess
# data_access_list = instances_related_data_access(instance, related_instances)
# print(f'instance = {instance.__class__.__name__}, data access count = {len(data_access_list)}') # print(f'instance = {instance.__class__.__name__}, data access count = {len(data_access_list)}')
for data_access in data_access_list: for data_access in data_access_list:
users.add(data_access.related_user) users.add(data_access.related_user)

@ -24,6 +24,7 @@ class CustomUserAdmin(UserAdmin):
list_display = ['email', 'first_name', 'last_name', 'username', 'date_joined', 'latest_event_club_name', 'is_active', 'event_count', 'origin', 'registration_payment_mode', 'licence_id'] list_display = ['email', 'first_name', 'last_name', 'username', 'date_joined', 'latest_event_club_name', 'is_active', 'event_count', 'origin', 'registration_payment_mode', 'licence_id']
list_filter = ['is_active', 'origin'] list_filter = ['is_active', 'origin']
ordering = ['-date_joined'] ordering = ['-date_joined']
raw_id_fields = ['agents']
fieldsets = [ fieldsets = [
(None, {'fields': ['id', 'username', 'email', 'password', 'first_name', 'last_name', 'is_active']}), (None, {'fields': ['id', 'username', 'email', 'password', 'first_name', 'last_name', 'is_active']}),
('Permissions', {'fields': ['is_staff', 'is_superuser', 'groups', 'user_permissions']}), ('Permissions', {'fields': ['is_staff', 'is_superuser', 'groups', 'user_permissions']}),
@ -32,7 +33,7 @@ class CustomUserAdmin(UserAdmin):
'summons_message_body', 'summons_message_signature', 'summons_available_payment_methods', 'summons_message_body', 'summons_message_signature', 'summons_available_payment_methods',
'summons_display_format', 'summons_display_entry_fee', 'summons_use_full_custom_message', 'summons_display_format', 'summons_display_entry_fee', 'summons_use_full_custom_message',
'match_formats_default_duration', 'bracket_match_format_preference', 'group_stage_match_format_preference', 'match_formats_default_duration', 'bracket_match_format_preference', 'group_stage_match_format_preference',
'loser_bracket_match_format_preference', 'device_id', 'loser_bracket_mode', 'origin', 'agents', 'should_synchronize' 'loser_bracket_match_format_preference', 'device_id', 'loser_bracket_mode', 'origin', 'agents', 'should_synchronize', 'can_synchronize'
]}), ]}),
] ]
@ -298,7 +299,7 @@ class TeamRegistrationAdmin(SyncedObjectAdmin):
class TeamScoreAdmin(SyncedObjectAdmin): class TeamScoreAdmin(SyncedObjectAdmin):
list_display = ['team_registration', 'score', 'walk_out', 'match'] list_display = ['team_registration', 'score', 'walk_out', 'match']
list_filter = [TeamScoreTournamentListFilter] list_filter = [TeamScoreTournamentListFilter]
search_fields = ['id'] search_fields = ['id', 'team_registration__player_registrations__first_name', 'team_registration__player_registrations__last_name']
raw_id_fields = ['team_registration', 'match'] # Add this line raw_id_fields = ['team_registration', 'match'] # Add this line
list_per_page = 50 # Controls pagination on the list view list_per_page = 50 # Controls pagination on the list view

Loading…
Cancel
Save