-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
signal handlers for syncing of project views and tasks #1218
Changes from 17 commits
3036a33
1a03525
8924baf
55d24f7
bdb6f7e
02137dd
b09af76
ecefbaf
42f54e0
e0799c3
2371728
20ca32d
9b2dedc
d3f94a4
4f32f00
9cb4429
50f25dd
90c32a3
3c2ea28
fa69180
1b42dd1
3da6110
7fc4740
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -160,12 +160,21 @@ class Meta: | |
'catalog': forms.RadioSelect() | ||
} | ||
|
||
def save(self, *args, **kwargs): | ||
# if the catalog is the same, do nothing | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to prevent calling the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure, but shouldn't this be handled by the |
||
if self.instance.catalog.id == self.cleaned_data.get('catalog'): | ||
return self.instance | ||
return super().save(*args, **kwargs) | ||
|
||
|
||
class ProjectUpdateTasksForm(forms.ModelForm): | ||
|
||
use_required_attribute = False | ||
|
||
def __init__(self, *args, **kwargs): | ||
if settings.PROJECT_TASKS_SYNC: | ||
raise ValidationError(_("Editing tasks is disabled.")) | ||
|
||
tasks = kwargs.pop('tasks') | ||
super().__init__(*args, **kwargs) | ||
self.fields['tasks'].queryset = tasks | ||
|
@@ -180,12 +189,20 @@ class Meta: | |
'tasks': forms.CheckboxSelectMultiple() | ||
} | ||
|
||
def save(self, *args, **kwargs): | ||
if settings.PROJECT_TASKS_SYNC: | ||
raise ValidationError(_("Editing tasks is disabled.")) | ||
super().save(*args, **kwargs) | ||
|
||
|
||
class ProjectUpdateViewsForm(forms.ModelForm): | ||
|
||
use_required_attribute = False | ||
|
||
def __init__(self, *args, **kwargs): | ||
if settings.PROJECT_VIEWS_SYNC: | ||
raise ValidationError(_("Editing views is disabled.")) | ||
|
||
views = kwargs.pop('views') | ||
super().__init__(*args, **kwargs) | ||
self.fields['views'].queryset = views | ||
|
@@ -200,6 +217,11 @@ class Meta: | |
'views': forms.CheckboxSelectMultiple() | ||
} | ||
|
||
def save(self, *args, **kwargs): | ||
if settings.PROJECT_VIEWS_SYNC: | ||
raise ValidationError(_("Editing views is disabled.")) | ||
super().save(*args, **kwargs) | ||
|
||
|
||
class ProjectUpdateParentForm(forms.ModelForm): | ||
|
||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
from django.contrib.auth.models import Group, User | ||
from django.contrib.sites.models import Site | ||
|
||
from rdmo.projects.models import Membership, Project | ||
from rdmo.questions.models import Catalog | ||
|
||
|
||
def m2m_catalogs_changed_projects_sync_signal_handler(instance, action, pk_set, project_field): | ||
|
||
if action == 'post_remove' and pk_set: | ||
related_instances = Catalog.objects.filter(pk__in=pk_set) | ||
projects_to_change = Project.objects.filter_catalogs(catalogs=related_instances).filter( | ||
**{project_field: instance} | ||
) | ||
for project in projects_to_change: # remove instance from project | ||
getattr(project, project_field).remove(instance) | ||
|
||
elif action == 'post_clear': | ||
projects_to_change = Project.objects.filter(**{project_field: instance}) | ||
for project in projects_to_change: # remove instance from project | ||
getattr(project, project_field).remove(instance) | ||
|
||
elif action == 'post_add' and pk_set: | ||
related_instances = Catalog.objects.filter(pk__in=pk_set) | ||
projects_to_change = Project.objects.filter_catalogs(catalogs=related_instances).exclude( | ||
**{project_field: instance} | ||
) | ||
for project in projects_to_change: # add instance to project | ||
getattr(project, project_field).add(instance) | ||
|
||
|
||
def m2m_sites_changed_projects_sync_signal_handler(instance, action, pk_set, project_field): | ||
|
||
if action == 'post_remove' and pk_set: | ||
related_sites = Site.objects.filter(pk__in=pk_set) | ||
catalogs = instance.catalogs.all() | ||
|
||
projects_to_change = Project.objects.filter_catalogs(catalogs=catalogs).filter( | ||
site__in=related_sites, | ||
**{project_field: instance} | ||
) | ||
for project in projects_to_change: # remove instance from project | ||
getattr(project, project_field).remove(instance) | ||
|
||
elif action == 'post_clear': | ||
projects_to_change = Project.objects.filter_catalogs().filter(**{project_field: instance}) | ||
for project in projects_to_change: # remove instance from project | ||
getattr(project, project_field).remove(instance) | ||
|
||
elif action == 'post_add' and pk_set: | ||
related_sites = Site.objects.filter(pk__in=pk_set) | ||
catalogs = instance.catalogs.all() | ||
|
||
projects_to_change = Project.objects.filter_catalogs(catalogs=catalogs).filter( | ||
site__in=related_sites | ||
).exclude(**{project_field: instance}) | ||
for project in projects_to_change: # add instance to project | ||
getattr(project, project_field).add(instance) | ||
|
||
|
||
def m2m_groups_changed_projects_sync_signal_handler(instance, action, pk_set, project_field): | ||
|
||
if action == 'post_remove' and pk_set: | ||
related_groups = Group.objects.filter(pk__in=pk_set) | ||
users = User.objects.filter(groups__in=related_groups) | ||
memberships = Membership.objects.filter(role='owner', user__in=users).values_list('id', flat=True) | ||
catalogs = instance.catalogs.all() | ||
|
||
projects_to_change = Project.objects.filter_catalogs(catalogs=catalogs).filter( | ||
memberships__in=memberships, | ||
**{project_field: instance} | ||
) | ||
for project in projects_to_change: # remove instance from project | ||
getattr(project, project_field).remove(instance) | ||
|
||
elif action == 'post_clear': | ||
# Remove all linked projects regardless of catalogs | ||
projects_to_change = Project.objects.filter_catalogs().filter(**{project_field: instance}) | ||
for project in projects_to_change: # remove instance from project | ||
getattr(project, project_field).remove(instance) | ||
|
||
elif action == 'post_add' and pk_set: | ||
related_groups = Group.objects.filter(pk__in=pk_set) | ||
users = User.objects.filter(groups__in=related_groups) | ||
memberships = Membership.objects.filter(role='owner', user__in=users).values_list('id', flat=True) | ||
catalogs = instance.catalogs.all() | ||
|
||
projects_to_change = Project.objects.filter_catalogs(catalogs=catalogs).filter( | ||
memberships__in=memberships | ||
).exclude(**{project_field: instance}) | ||
for project in projects_to_change: # add instance to project | ||
getattr(project, project_field).add(instance) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from django.db.models.signals import m2m_changed | ||
from django.dispatch import receiver | ||
|
||
from rdmo.tasks.models import Task | ||
|
||
from .generic_handlers import ( | ||
m2m_catalogs_changed_projects_sync_signal_handler, | ||
m2m_groups_changed_projects_sync_signal_handler, | ||
m2m_sites_changed_projects_sync_signal_handler, | ||
) | ||
|
||
|
||
@receiver(m2m_changed, sender=Task.catalogs.through) | ||
def m2m_changed_task_catalog_signal(sender, instance, action, pk_set, **kwargs): | ||
m2m_catalogs_changed_projects_sync_signal_handler(instance, action, pk_set, 'tasks') | ||
|
||
|
||
@receiver(m2m_changed, sender=Task.sites.through) | ||
def m2m_changed_task_sites_signal(sender, instance, action, pk_set, **kwargs): | ||
m2m_sites_changed_projects_sync_signal_handler(instance, action, pk_set, 'tasks') | ||
|
||
|
||
@receiver(m2m_changed, sender=Task.groups.through) | ||
def m2m_changed_task_groups_signal(sender, instance, action, pk_set, **kwargs): | ||
m2m_groups_changed_projects_sync_signal_handler(instance, action, pk_set, 'tasks') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from django.db.models.signals import m2m_changed | ||
from django.dispatch import receiver | ||
|
||
from rdmo.views.models import View | ||
|
||
from .generic_handlers import ( | ||
m2m_catalogs_changed_projects_sync_signal_handler, | ||
m2m_groups_changed_projects_sync_signal_handler, | ||
m2m_sites_changed_projects_sync_signal_handler, | ||
) | ||
|
||
|
||
@receiver(m2m_changed, sender=View.catalogs.through) | ||
def m2m_changed_view_catalog_signal(sender, instance, action, pk_set, **kwargs): | ||
m2m_catalogs_changed_projects_sync_signal_handler(instance, action, pk_set, 'views') | ||
|
||
|
||
@receiver(m2m_changed, sender=View.sites.through) | ||
def m2m_changed_view_sites_signal(sender, instance, action, pk_set, **kwargs): | ||
m2m_sites_changed_projects_sync_signal_handler(instance, action, pk_set, 'views') | ||
|
||
|
||
@receiver(m2m_changed, sender=View.groups.through) | ||
def m2m_changed_view_groups_signal(sender, instance, action, pk_set, **kwargs): | ||
m2m_groups_changed_projects_sync_signal_handler(instance, action, pk_set, 'views') |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from django.db.models.signals import post_save, pre_save | ||
from django.dispatch import receiver | ||
|
||
from rdmo.projects.models import Project | ||
from rdmo.tasks.models import Task | ||
|
||
|
||
@receiver(pre_save, sender=Project) | ||
def pre_save_project_sync_tasks_from_catalog(sender, instance, raw, update_fields, **kwargs): | ||
instance._catalog_has_changed_sync_tasks = False | ||
|
||
if raw or (update_fields and 'catalog' not in update_fields): | ||
return | ||
|
||
if instance.id is not None: | ||
# Fetch the original catalog from the database | ||
if sender.objects.get(id=instance.id).catalog == instance.catalog: | ||
# Do nothing if the catalog has not changed | ||
return | ||
|
||
# Defer synchronization of views | ||
instance._catalog_has_changed_sync_tasks = True | ||
|
||
|
||
@receiver(post_save, sender=Project) | ||
def post_save_project_sync_tasks_from_catalog(sender, instance, created, raw, update_fields, **kwargs): | ||
if raw or (update_fields and 'catalog' not in update_fields): | ||
return | ||
|
||
if instance._catalog_has_changed_sync_tasks or (created and not instance.tasks.exists) : | ||
instance.tasks.set(Task.objects.filter_available_tasks_for_project(instance).values_list('id', flat=True)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from django.db.models.signals import post_save, pre_save | ||
from django.dispatch import receiver | ||
|
||
from rdmo.projects.models import Project | ||
from rdmo.views.models import View | ||
|
||
|
||
@receiver(pre_save, sender=Project) | ||
def pre_save_project_sync_views_from_catalog(sender, instance, raw, update_fields, **kwargs): | ||
instance._catalog_has_changed_sync_views = False | ||
|
||
if raw or (update_fields and 'catalog' not in update_fields): | ||
return | ||
|
||
if instance.id is not None: | ||
# Fetch the original catalog from the database | ||
if sender.objects.get(id=instance.id).catalog == instance.catalog: | ||
# Do nothing if the catalog has not changed | ||
return | ||
|
||
# Defer synchronization of views | ||
instance._catalog_has_changed_sync_views = True | ||
|
||
|
||
MyPyDavid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@receiver(post_save, sender=Project) | ||
def post_save_project_sync_views_from_catalog(sender, instance, created, raw, update_fields, **kwargs): | ||
if raw or (update_fields and 'catalog' not in update_fields): | ||
return | ||
|
||
if instance._catalog_has_changed_sync_views or (created and not instance.views.exists): | ||
instance.views.set(View.objects.filter_available_views_for_project(instance).values_list('id', flat=True)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these actually be enabled by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think not.