Skip to content

Commit

Permalink
feat(project, handlers): refactor project singal handlers for views a…
Browse files Browse the repository at this point in the history
…nd add for tasks

Signed-off-by: David Wallace <[email protected]>
  • Loading branch information
MyPyDavid committed Jan 6, 2025
1 parent fc153d9 commit 798703b
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 101 deletions.
3 changes: 2 additions & 1 deletion rdmo/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@

PROJECT_SEND_INVITE = True

PROJECT_REMOVE_VIEWS = True
PROJECT_VIEWS_SYNC = True
PROJECT_TASKS_SYNC = True

PROJECT_CREATE_RESTRICTED = False
PROJECT_CREATE_GROUPS = []
Expand Down
6 changes: 4 additions & 2 deletions rdmo/projects/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ class ProjectsConfig(AppConfig):
def ready(self):
from . import rules # noqa: F401

if settings.PROJECT_REMOVE_VIEWS:
from . import handlers # noqa: F401
if settings.PROJECT_VIEWS_SYNC:
from .handlers import project_views # noqa: F401
if settings.PROJECT_TASKS_SYNC:
from .handlers import project_tasks # noqa: F401
Empty file.
78 changes: 78 additions & 0 deletions rdmo/projects/handlers/project_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import logging

from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.db.models.signals import m2m_changed
from django.dispatch import receiver

from rdmo.projects.models import Membership, Project
from rdmo.questions.models import Catalog
from rdmo.tasks.models import Task

logger = logging.getLogger(__name__)


@receiver(m2m_changed, sender=Task.catalogs.through)
def m2m_changed_task_catalog_signal(sender, instance, action, model, **kwargs):

task = instance
# catalogs that were changed
catalogs = model.objects.filter(pk__in=kwargs['pk_set'])
if action in ('post_remove', 'post_clear'):
# Remove the task from projects whose catalog is no longer linked to this task
projects_to_change = Project.objects.filter(catalog__in=catalogs, tasks=task)
for project in projects_to_change:
project.tasks.remove(task)

elif action == 'post_add':
# Add the task to projects whose catalog is now linked to this task
projects_to_change = Project.objects.filter(catalog__in=task.catalogs.all()).exclude(tasks=task)
for project in projects_to_change:
project.tasks.add(task)


@receiver(m2m_changed, sender=Task.sites.through)
def m2m_changed_task_sites_signal(sender, instance, action, model, **kwargs):

task = instance
sites = model.objects.filter(pk__in=kwargs['pk_set'])
catalogs = task.catalogs.all() or Catalog.objects.all() # If no catalogs, consider all

if action in ('post_remove', 'post_clear'):
# Remove the task from projects whose site is no longer linked to this task
site_candidates = Site.objects.exclude(id__in=sites.values_list('id', flat=True))
projects_to_change = Project.objects.filter(site__in=site_candidates, catalog__in=catalogs, tasks=task)
for project in projects_to_change:
project.tasks.remove(task)

elif action == 'post_add':
# Add the task to projects whose site is now linked to this task
site_candidates = sites
projects_to_change = Project.objects.filter(site__in=site_candidates, catalog__in=catalogs).exclude(tasks=task)
for project in projects_to_change:
project.tasks.add(task)


@receiver(m2m_changed, sender=Task.groups.through)
def m2m_changed_task_groups_signal(sender, instance, action=None, **kwargs):

task = instance
groups = task.groups.all()
catalogs = task.catalogs.all() or Catalog.objects.all() # If no catalogs, consider all

if action in ('post_remove', 'post_clear'):
# Remove the task from projects whose group is no longer linked to this task
users = User.objects.exclude(groups__in=groups)
memberships = Membership.objects.filter(role='owner', user__in=users).values_list('id', flat=True)
projects_to_change = Project.objects.filter(memberships__in=memberships, catalog__in=catalogs, tasks=task)
for project in projects_to_change:
project.tasks.remove(task)

elif action == 'post_add':
# Add the task to projects whose group is now linked to this task
users = User.objects.filter(groups__in=groups)
memberships = Membership.objects.filter(role='owner', user__in=users).values_list('id', flat=True)
projects_to_change = Project.objects.filter(
memberships__in=memberships, catalog__in=catalogs).exclude(tasks=task)
for project in projects_to_change:
project.tasks.add(task)
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,25 @@


@receiver(m2m_changed, sender=View.catalogs.through)
def m2m_changed_view_catalog_signal(sender, instance, action, model, **kwargs):

def m2m_changed_view_catalog_signal(sender, instance, action, model, pk_set, **kwargs):
view = instance
# catalogs that were changed
catalogs = model.objects.filter(pk__in=kwargs['pk_set'])

if action in ('post_remove', 'post_clear'):
if action == 'post_remove':
# catalogs that were changed
catalogs = model.objects.filter(pk__in=pk_set)
# Remove the view from projects whose catalog is no longer linked to this view
projects_to_change = Project.objects.filter(catalog__in=catalogs, views=view)
for project in projects_to_change:
project.views.remove(view)

elif action == 'post_clear':
# Remove the view from all projects that were using this view
for project in Project.objects.filter(views=view):
project.views.remove(view)

elif action == 'post_add':
# Add the view to projects whose catalog is now linked to this view
projects_to_change = Project.objects.filter(catalog__in=view.catalogs.all()).exclude(views=view)
for project in projects_to_change:
for project in Project.objects.filter(catalog__in=view.catalogs.all()):
project.views.add(view)


Expand Down
91 changes: 0 additions & 91 deletions rdmo/projects/tests/test_handlers.py

This file was deleted.

30 changes: 30 additions & 0 deletions rdmo/projects/tests/test_handlers_tasks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@


from rdmo.projects.models import Project
from rdmo.questions.models import Catalog
from rdmo.tasks.models import Task

task_id = 1


def test_project_views_sync_when_adding_or_removing_a_catalog_to_or_from_a_task(db, settings):
assert settings.PROJECT_TASKS_SYNC

# Setup: Create a catalog, a task, and a project using the catalog
catalog = Catalog.objects.first()
task = Task.objects.get(pk=task_id)
task.catalogs.set([])
project = Project.objects.create(title="Test Project", catalog=catalog)

# Initially, the project should not have the task
assert task not in project.tasks.all()

# Add the catalog to the task
task.catalogs.add(catalog)
# After adding the catalog, the project should now include the task
assert task in project.tasks.all()

# Remove the catalog from the task
task.catalogs.remove(catalog)
# After removing the catalog, the project should no longer include the task
assert task not in project.tasks.all()
41 changes: 41 additions & 0 deletions rdmo/projects/tests/test_handlers_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@



from rdmo.projects.models import Project
from rdmo.questions.models import Catalog
from rdmo.views.models import View


def test_project_views_sync_when_adding_or_removing_a_catalog_to_or_from_a_view(db, settings):
assert settings.PROJECT_VIEWS_SYNC

# Setup: Create a catalog, a view, and a project using the catalog
catalog = Catalog.objects.first()
view = View.objects.get(pk=3)
# view.catalogs.clear()
project = Project.objects.create(title="Test Project", catalog=catalog)
pr10 = Project.objects.get(pk=10)

# # Initially, the project should not have the view
# assert view not in project.views.all()
# assert view not in pr10.views.all()

## Tests for .add and .remove
# Add the catalog to the view and assert that the project now includes the view
view.catalogs.add(catalog)
assert view in project.views.all()

# Remove the catalog from the view and assert that the project should no longer include the view
view.catalogs.remove(catalog)
assert view not in project.views.all()
assert view not in pr10.views.all()

## Tests for .set and .clear
# Add the catalog to the view and assert that the project now includes the view
view.catalogs.set([catalog])
assert view in project.views.all()

# Remove the catalog from the view and assert that the project should no longer include the view
view.catalogs.clear()
assert view not in project.views.all()
assert view not in pr10.views.all()

0 comments on commit 798703b

Please sign in to comment.