From 5a94582a749fd4ef750f8c4d203f1793d4a290bc Mon Sep 17 00:00:00 2001 From: jefer94 Date: Fri, 5 Jul 2024 21:14:13 -0500 Subject: [PATCH] fix mentorship survey, update signals, add vs extensions to codespaces, update hook manager serializer --- .devcontainer/devcontainer.json | 9 ++- breathecode/assessment/signals.py | 13 ++--- breathecode/assignments/admin.py | 27 ++++++++- breathecode/assignments/signals.py | 15 +++-- breathecode/authenticate/signals.py | 16 +++--- breathecode/feedback/apps.py | 3 +- breathecode/feedback/receivers.py | 6 +- breathecode/feedback/signals.py | 11 ++-- breathecode/feedback/tasks.py | 40 +++++++++---- breathecode/mentorship/models.py | 7 ++- breathecode/mentorship/signals.py | 11 +++- ...s.py => tests_mentorship_session_saved.py} | 56 +++++++++++++++---- .../tests/urls/tests_academy_session.py | 38 ------------- .../tests/urls/tests_academy_session_id.py | 46 --------------- breathecode/monitoring/signals.py | 13 ++--- breathecode/notify/utils/hook_manager.py | 17 +++--- breathecode/registry/signals.py | 17 +++--- 17 files changed, 172 insertions(+), 173 deletions(-) rename breathecode/mentorship/tests/signals/{tests_mentorship_session_status.py => tests_mentorship_session_saved.py} (83%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 909f447ae..1c808940c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -25,9 +25,14 @@ "eamodio.gitlens", "gruntfuggly.todo-tree", "redhat.vscode-yaml", - "bungcip.better-toml", + "ms-python.black-formatter", + "ms-python.isort", + "janisdd.vscode-edit-csv", + "tamasfe.even-better-toml", + "ms-python.flake8", + "donjayamanne.githistory", "TabNine.tabnine-vscode", - "github.vscode-github-actions" + "ms-python.debugpy" ] } }, diff --git a/breathecode/assessment/signals.py b/breathecode/assessment/signals.py index 4a7057fff..33ab72ea9 100644 --- a/breathecode/assessment/signals.py +++ b/breathecode/assessment/signals.py @@ -1,9 +1,8 @@ -""" -For each signal you want other apps to be able to receive, you have to -declare a new variable here like this: -""" +"""For each signal you want other apps to be able to receive, you have to declare a new variable here like this:""" -from django import dispatch +from task_manager.django.dispatch import Emisor -assessment_updated = dispatch.Signal() -userassessment_status_updated = dispatch.Signal() +emisor = Emisor("breathecode.assessment") + +assessment_updated = emisor.signal("assessment_updated") +userassessment_status_updated = emisor.signal("userassessment_status_updated") diff --git a/breathecode/assignments/admin.py b/breathecode/assignments/admin.py index 24e474b0e..7df752ed7 100644 --- a/breathecode/assignments/admin.py +++ b/breathecode/assignments/admin.py @@ -10,7 +10,17 @@ from breathecode.services.learnpack import LearnPack from .actions import sync_student_tasks -from .models import AssignmentTelemetry, CohortProxy, FinalProject, LearnPackWebhook, Task, UserAttachment, UserProxy +from .models import ( + AssignmentTelemetry, + CohortProxy, + FinalProject, + LearnPackWebhook, + RepositoryDeletionOrder, + RepositoryWhiteList, + Task, + UserAttachment, + UserProxy, +) # Register your models here. logger = logging.getLogger(__name__) @@ -125,7 +135,6 @@ def async_process_hook(modeladmin, request, queryset): def process_hook(modeladmin, request, queryset): # stay this here for use the poor mocking system for hook in queryset.all().order_by("created_at"): - print(f"Procesing hook: {hook.id}") client = LearnPack() try: client.execute_action(hook.id) @@ -166,3 +175,17 @@ def from_status(s): return "" return format_html(f"
{obj.status}
{obj.status_text}") + + +@admin.register(RepositoryDeletionOrder) +class RepositoryDeletionOrderAdmin(admin.ModelAdmin): + list_display = ("provider", "status", "repository_user", "repository_name") + search_fields = ["repository_user", "repository_name"] + list_filter = ["provider", "status"] + + +@admin.register(RepositoryWhiteList) +class RepositoryWhiteListAdmin(admin.ModelAdmin): + list_display = ("provider", "repository_user", "repository_name") + search_fields = ["repository_user", "repository_name"] + list_filter = ["provider"] diff --git a/breathecode/assignments/signals.py b/breathecode/assignments/signals.py index e26e8e30c..f65505b4e 100644 --- a/breathecode/assignments/signals.py +++ b/breathecode/assignments/signals.py @@ -1,10 +1,9 @@ -""" -For each signal you want other apps to be able to receive, you have to -declare a new variable here like this: -""" +"""For each signal you want other apps to be able to receive, you have to declare a new variable here like this:""" -from django import dispatch +from task_manager.django.dispatch import Emisor -assignment_created = dispatch.Signal() -assignment_status_updated = dispatch.Signal() -revision_status_updated = dispatch.Signal() +emisor = Emisor("breathecode.assignments") + +assignment_created = emisor.signal("assignment_created") +assignment_status_updated = emisor.signal("assignment_status_updated") +revision_status_updated = emisor.signal("revision_status_updated") diff --git a/breathecode/authenticate/signals.py b/breathecode/authenticate/signals.py index 421846b9f..d49a34602 100644 --- a/breathecode/authenticate/signals.py +++ b/breathecode/authenticate/signals.py @@ -1,13 +1,15 @@ -from django import dispatch +from task_manager.django.dispatch import Emisor + +emisor = Emisor("breathecode.authenticate") # UserInvite accepted -invite_status_updated = dispatch.Signal() +invite_status_updated = emisor.signal("invite_status_updated") # ProfileAcademy accepted -academy_invite_accepted = dispatch.Signal() -profile_academy_saved = dispatch.Signal() +academy_invite_accepted = emisor.signal("academy_invite_accepted") +profile_academy_saved = emisor.signal("profile_academy_saved") # post_delete and post_save for User, ProfileAcademy and MentorProfileMentorProfile -user_info_updated = dispatch.Signal() -user_info_deleted = dispatch.Signal() +user_info_updated = emisor.signal("user_info_updated") +user_info_deleted = emisor.signal("user_info_deleted") -cohort_user_deleted = dispatch.Signal() +cohort_user_deleted = emisor.signal("cohort_user_deleted") diff --git a/breathecode/feedback/apps.py b/breathecode/feedback/apps.py index d11a79741..df27db632 100644 --- a/breathecode/feedback/apps.py +++ b/breathecode/feedback/apps.py @@ -1,4 +1,5 @@ import logging + from django.apps import AppConfig logger = logging.getLogger(__name__) @@ -8,5 +9,5 @@ class FeedbackConfig(AppConfig): name = "breathecode.feedback" def ready(self): - logger.debug("Loading feedback.receivers") from . import receivers # noqa: F401 + from . import supervisors # noqa: F401 diff --git a/breathecode/feedback/receivers.py b/breathecode/feedback/receivers.py index d0195f0b4..60b5bbb71 100644 --- a/breathecode/feedback/receivers.py +++ b/breathecode/feedback/receivers.py @@ -7,7 +7,7 @@ from breathecode.admissions.models import CohortUser from breathecode.admissions.signals import student_edu_status_updated from breathecode.mentorship.models import MentorshipSession -from breathecode.mentorship.signals import mentorship_session_status +from breathecode.mentorship.signals import mentorship_session_saved from .models import Answer from .signals import survey_answered @@ -33,9 +33,9 @@ def post_save_cohort_user(sender, instance, **kwargs): process_student_graduation.delay(instance.cohort.id, instance.user.id) -@receiver(mentorship_session_status, sender=MentorshipSession) +@receiver(mentorship_session_saved, sender=MentorshipSession) def post_mentorin_session_ended(sender: Type[MentorshipSession], instance: MentorshipSession, **kwargs): - if instance.status == "COMPLETED": + if instance.status == "COMPLETED" and Answer.objects.filter(mentorship_session__id=instance.id).exists() is False: duration = timedelta(seconds=0) if instance.started_at is not None and instance.ended_at is not None: duration = instance.ended_at - instance.started_at diff --git a/breathecode/feedback/signals.py b/breathecode/feedback/signals.py index 98272cfca..680b9ab05 100644 --- a/breathecode/feedback/signals.py +++ b/breathecode/feedback/signals.py @@ -1,9 +1,8 @@ -""" -For each signal you want other apps to be able to receive, you have to -declare a new variable here like this: -""" +"""For each signal you want other apps to be able to receive, you have to declare a new variable here like this:""" -from django import dispatch +from task_manager.django.dispatch import Emisor + +emisor = Emisor("breathecode.feedback") # when a student answers one particular questions of a survey -survey_answered = dispatch.Signal() +survey_answered = emisor.signal("survey_answered") diff --git a/breathecode/feedback/tasks.py b/breathecode/feedback/tasks.py index ac8711efb..ca78d64f5 100644 --- a/breathecode/feedback/tasks.py +++ b/breathecode/feedback/tasks.py @@ -2,7 +2,10 @@ from datetime import timedelta from django.contrib.auth.models import User +from django.core.cache import cache from django.utils import timezone +from django_redis import get_redis_connection +from redis.exceptions import LockError from task_manager.core.exceptions import AbortTask, RetryTask from task_manager.django.decorators import task @@ -11,6 +14,7 @@ from breathecode.mentorship.models import MentorshipSession from breathecode.notify import actions as notify_actions from breathecode.utils import TaskPriority, getLogger +from breathecode.utils.redis import Lock from capyc.rest_framework.exceptions import ValidationException from . import actions @@ -23,6 +27,7 @@ ADMIN_URL = os.getenv("ADMIN_URL", "") API_URL = os.getenv("API_URL", "") ENV = os.getenv("ENV", "") +IS_DJANGO_REDIS = hasattr(cache, "delete_pattern") def build_question(answer): @@ -291,19 +296,30 @@ def send_mentorship_session_survey(session_id, **_): if not session.service: raise AbortTask("Mentorship session doesn't have a service associated with it") - answer = Answer.objects.filter(mentorship_session__id=session.id).first() - if answer is None: - answer = Answer(mentorship_session=session, academy=session.mentor.academy, lang=session.service.language) - question = build_question(answer) - answer.title = question["title"] - answer.lowest = question["lowest"] - answer.highest = question["highest"] - answer.user = session.mentee - answer.status = "SENT" - answer.save() + client = None + if IS_DJANGO_REDIS: + client = get_redis_connection("default") - elif answer.status == "ANSWERED": - raise AbortTask(f"This survey about MentorshipSession {session.id} was answered") + try: + with Lock(client, f"lock:session:{session.id}:answer", timeout=30, blocking_timeout=30): + answer = Answer.objects.filter(mentorship_session__id=session.id).first() + if answer is None: + answer = Answer( + mentorship_session=session, academy=session.mentor.academy, lang=session.service.language + ) + question = build_question(answer) + answer.title = question["title"] + answer.lowest = question["lowest"] + answer.highest = question["highest"] + answer.user = session.mentee + answer.status = "SENT" + answer.save() + + elif answer.status == "ANSWERED": + raise AbortTask(f"This survey about MentorshipSession {session.id} was answered") + + except LockError: + raise RetryTask("Could not acquire lock for activity, operation timed out.") if not session.mentee.email: message = f"Author not have email, this survey cannot be send by {session.mentee.id}" diff --git a/breathecode/mentorship/models.py b/breathecode/mentorship/models.py index fe30a6408..70aaecb7a 100644 --- a/breathecode/mentorship/models.py +++ b/breathecode/mentorship/models.py @@ -468,10 +468,13 @@ def save(self, *args, **kwargs): is_creating = self.pk is None - super().save(*args, **kwargs) # Call the "real" save() method. + super().save(*args, **kwargs) if is_creating or self.__old_status != self.status: - signals.mentorship_session_status.send_robust(instance=self, sender=MentorshipSession) + signals.mentorship_session_status.delay(instance=self, sender=MentorshipSession) + + # we're testing why there hasn't any mentorship session with a survey changing mentorship_session_status by mentorship_session_saved + signals.mentorship_session_saved.delay(instance=self, sender=MentorshipSession) self.__old_status = self.status diff --git a/breathecode/mentorship/signals.py b/breathecode/mentorship/signals.py index 8c1ad770d..677c0b44a 100644 --- a/breathecode/mentorship/signals.py +++ b/breathecode/mentorship/signals.py @@ -1,4 +1,9 @@ -from django import dispatch +"""For each signal you want other apps to be able to receive, you have to declare a new variable here like this:""" -mentorship_session_status = dispatch.Signal() -mentor_profile_saved = dispatch.Signal() +from task_manager.django.dispatch import Emisor + +emisor = Emisor("breathecode.mentorship") + +mentorship_session_status = emisor.signal("mentorship_session_status") +mentor_profile_saved = emisor.signal("mentor_profile_saved") +mentorship_session_saved = emisor.signal("mentorship_session_saved") diff --git a/breathecode/mentorship/tests/signals/tests_mentorship_session_status.py b/breathecode/mentorship/tests/signals/tests_mentorship_session_saved.py similarity index 83% rename from breathecode/mentorship/tests/signals/tests_mentorship_session_status.py rename to breathecode/mentorship/tests/signals/tests_mentorship_session_saved.py index db5a52af4..03d7ad6bc 100644 --- a/breathecode/mentorship/tests/signals/tests_mentorship_session_status.py +++ b/breathecode/mentorship/tests/signals/tests_mentorship_session_saved.py @@ -1,5 +1,6 @@ from datetime import timedelta from unittest.mock import MagicMock, call, patch + from django.utils import timezone from breathecode.payments.tasks import refund_mentoring_session @@ -13,7 +14,7 @@ class TestLead(LegacyAPITestCase): @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_pending(self, enable_signals): + def test_with_status_pending(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -37,7 +38,7 @@ def test_mentorship_session_status__with_status_pending(self, enable_signals): @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_started(self, enable_signals): + def test_with_status_started(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -61,7 +62,7 @@ def test_mentorship_session_status__with_status_started(self, enable_signals): @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_failed(self, enable_signals): + def test_with_status_failed(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -81,7 +82,7 @@ def test_mentorship_session_status__with_status_failed(self, enable_signals): @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_failed__with_mentor_and_mentee(self, enable_signals): + def test_with_status_failed__with_mentor_and_mentee(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -107,7 +108,7 @@ def test_mentorship_session_status__with_status_failed__with_mentor_and_mentee(s @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_ignored(self, enable_signals): + def test_with_status_ignored(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -127,7 +128,7 @@ def test_mentorship_session_status__with_status_ignored(self, enable_signals): @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_ignored__with_mentor_and_mentee(self, enable_signals): + def test_with_status_ignored__with_mentor_and_mentee(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -153,7 +154,7 @@ def test_mentorship_session_status__with_status_ignored__with_mentor_and_mentee( @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_completed__duration_equal_to_zero(self, enable_signals): + def test_with_status_completed__duration_equal_to_zero(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -177,7 +178,7 @@ def test_mentorship_session_status__with_status_completed__duration_equal_to_zer @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_completed__duration_equal_to_five_minutes(self, enable_signals): + def test_with_status_completed__duration_equal_to_five_minutes(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -206,7 +207,7 @@ def test_mentorship_session_status__with_status_completed__duration_equal_to_fiv @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_completed__duration_greater_than_five_minutes(self, enable_signals): + def test_with_status_completed__duration_greater_than_five_minutes(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -235,7 +236,7 @@ def test_mentorship_session_status__with_status_completed__duration_greater_than @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) - def test_mentorship_session_status__with_status_completed__with_mentee__with_mentor(self, enable_signals): + def test_with_status_completed__with_mentee__with_mentor(self, enable_signals): enable_signals() from breathecode.feedback.tasks import send_mentorship_session_survey @@ -258,14 +259,45 @@ def test_mentorship_session_status__with_status_completed__with_mentee__with_men self.assertEqual(send_mentorship_session_survey.delay.call_args_list, [call(1)]) self.assertEqual(refund_mentoring_session.delay.call_args_list, []) + """ + 🔽🔽🔽 With status COMPLETED, duration greater than 0:05:00, with mentee, mentor and answer + """ + + @patch("breathecode.feedback.tasks.send_mentorship_session_survey.delay", MagicMock()) + @patch("breathecode.payments.tasks.refund_mentoring_session.delay", MagicMock()) + def test_with_status_completed__with_mentee__with_mentor__with_answer(self, enable_signals): + enable_signals() + + from breathecode.feedback.tasks import send_mentorship_session_survey + + utc_now = timezone.now() + mentorship_session = { + "status": "PENDING", + "started_at": utc_now, + "ended_at": utc_now + timedelta(minutes=5, seconds=1), + } + model = self.bc.database.create(mentorship_session=mentorship_session, user=1, mentorship_service=1, answer=1) + model.mentorship_session.status = "COMPLETED" + model.mentorship_session.save() + + self.assertEqual( + self.bc.database.list_of("mentorship.MentorshipSession"), + [ + self.bc.format.to_dict(model.mentorship_session), + ], + ) + + assert send_mentorship_session_survey.delay.call_args_list == [] + assert refund_mentoring_session.delay.call_args_list == [] + # """ # 🔽🔽🔽 With status COMPLETED, duration greater than 0:05:00, with mentee and with mentor, with service # """ # @patch('breathecode.feedback.tasks.send_mentorship_session_survey.delay', MagicMock()) # @patch('breathecode.payments.tasks.refund_mentoring_session.delay', MagicMock()) - # def test_mentorship_session_status__with_status_completed__with_mentee__with_mentor_and_service(self, enable_signals): - enable_signals() + # def test_with_status_completed__with_mentee__with_mentor_and_service(self, enable_signals): + # enable_signals() # from breathecode.feedback.tasks import send_mentorship_session_survey diff --git a/breathecode/mentorship/tests/urls/tests_academy_session.py b/breathecode/mentorship/tests/urls/tests_academy_session.py index 4d75926fe..d1a2027d4 100644 --- a/breathecode/mentorship/tests/urls/tests_academy_session.py +++ b/breathecode/mentorship/tests/urls/tests_academy_session.py @@ -363,7 +363,6 @@ def test__get__with_two_mentor_profile(self): 🔽🔽🔽 GET with two MentorshipSession, one MentorProfile and one MentorshipService, passing status """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_bad_status(self): statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -403,7 +402,6 @@ def test__get__with_two_mentor_profile__passing_bad_status(self): # teardown self.bc.database.delete("mentorship.MentorshipSession") - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_status(self): statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -466,7 +464,6 @@ def test__get__with_two_mentor_profile__passing_status(self): 🔽🔽🔽 GET with two MentorshipSession, one MentorProfile and one MentorshipService, passing billed """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_billed_as_true__without_mentorship_bill(self): model = self.bc.database.create( user=1, @@ -496,7 +493,6 @@ def test__get__with_two_mentor_profile__passing_billed_as_true__without_mentorsh ], ) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_billed_as_true__with_mentorship_bill(self): model = self.bc.database.create( user=1, @@ -537,7 +533,6 @@ def test__get__with_two_mentor_profile__passing_billed_as_true__with_mentorship_ ], ) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_billed_as_false__with_mentorship_bill(self): model = self.bc.database.create( user=1, @@ -568,7 +563,6 @@ def test__get__with_two_mentor_profile__passing_billed_as_false__with_mentorship ], ) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_billed_as_false__without_mentorship_bill(self): model = self.bc.database.create( user=1, @@ -612,7 +606,6 @@ def test__get__with_two_mentor_profile__passing_billed_as_false__without_mentors 🔽🔽🔽 GET with two MentorshipSession, one MentorProfile and one MentorshipService, passing started_after """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_bad_started_after(self): utc_now = timezone.now() mentorship_session = {"started_at": utc_now} @@ -647,7 +640,6 @@ def test__get__with_two_mentor_profile__passing_bad_started_after(self): ], ) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_started_after(self): utc_now = timezone.now() mentorship_session = {"started_at": utc_now} @@ -692,7 +684,6 @@ def test__get__with_two_mentor_profile__passing_started_after(self): ], ) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_started_after__without_started_at(self): utc_now = timezone.now() model = self.bc.database.create( @@ -742,7 +733,6 @@ def test__get__with_two_mentor_profile__passing_started_after__without_started_a 🔽🔽🔽 GET with two MentorshipSession, one MentorProfile and one MentorshipService, passing ended_before """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_bad_ended_before(self): utc_now = timezone.now() mentorship_session = {"ended_at": utc_now} @@ -777,7 +767,6 @@ def test__get__with_two_mentor_profile__passing_bad_ended_before(self): ], ) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_ended_before(self): utc_now = timezone.now() mentorship_session = {"ended_at": utc_now} @@ -822,7 +811,6 @@ def test__get__with_two_mentor_profile__passing_ended_before(self): ], ) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__get__with_two_mentor_profile__passing_ended_before__without_ended_at(self): utc_now = timezone.now() model = self.bc.database.create( @@ -1503,7 +1491,6 @@ def test__put__without_capabilities(self): 🔽🔽🔽 PUT without id """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__without_id(self): model = self.bc.database.create(user=1, role=1, capability="crud_mentorship_session", profile_academy=1) @@ -1526,7 +1513,6 @@ def test__put__without_id(self): 🔽🔽🔽 PUT not found the MentorshipSession """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__not_found(self): cases = [ (1, {}, False), @@ -1568,7 +1554,6 @@ def test__put__not_found(self): 🔽🔽🔽 PUT found a MentorshipSession, with one MentorProfile and MentorshipService """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__without_required_fields(self): model = self.bc.database.create( user=1, @@ -1600,7 +1585,6 @@ def test__put__found__without_required_fields(self): ) self.assertEqual(self.bc.database.list_of("mentorship.MentorshipBill"), []) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_required_fields(self): model = self.bc.database.create( user=1, @@ -1646,7 +1630,6 @@ def test__put__found__with_required_fields(self): 🔽🔽🔽 PUT with all required fields, is_online is False """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_all_required_fields__is_online_as_false(self): mentorship_bill = {"status": random.choice(["RECALCULATE", "DUE"])} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -1665,8 +1648,6 @@ def test__put__found__with_all_required_fields__is_online_as_false(self): profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -1746,18 +1727,11 @@ def test__put__found__with_all_required_fields__is_online_as_false(self): self.bc.format.to_dict(model.mentorship_bill), ], ) - self.assertEqual( - signals.mentorship_session_status.send_robust.call_args_list, - [ - call(instance=model.mentorship_session, sender=model.mentorship_session.__class__), - ], - ) """ 🔽🔽🔽 PUT with all required fields, is_online is False, MentorshipBill finished """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_all_required_fields__is_online_as_false__bill_finished(self): mentorship_bill = {"status": random.choice(["APPROVED", "PAID", "IGNORED"])} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -1776,8 +1750,6 @@ def test__put__found__with_all_required_fields__is_online_as_false__bill_finishe profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -1826,7 +1798,6 @@ def test__put__found__with_all_required_fields__is_online_as_false__bill_finishe }, ], ) - self.assertEqual(signals.mentorship_session_status.send_robust.call_args_list, []) self.assertEqual( self.bc.database.list_of("mentorship.MentorshipBill"), [ @@ -1838,7 +1809,6 @@ def test__put__found__with_all_required_fields__is_online_as_false__bill_finishe 🔽🔽🔽 PUT passing a MentorshipBill with some MentorshipSession without MentorshipService """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__passing_a_bill_with_some_session_without_service(self): mentorship_bill = {"status": "DUE"} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -1868,8 +1838,6 @@ def test__put__found__passing_a_bill_with_some_session_without_service(self): profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -1949,9 +1917,3 @@ def test__put__found__passing_a_bill_with_some_session_without_service(self): }, ], ) - self.assertEqual( - signals.mentorship_session_status.send_robust.call_args_list, - [ - call(instance=model.mentorship_session[0], sender=model.mentorship_session[0].__class__), - ], - ) diff --git a/breathecode/mentorship/tests/urls/tests_academy_session_id.py b/breathecode/mentorship/tests/urls/tests_academy_session_id.py index 181a3c7b4..c264ee741 100644 --- a/breathecode/mentorship/tests/urls/tests_academy_session_id.py +++ b/breathecode/mentorship/tests/urls/tests_academy_session_id.py @@ -241,7 +241,6 @@ def test__put__without_capabilities(self): 🔽🔽🔽 PUT not found the MentorshipSession """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__not_found(self): cases = [ (1, {}, False), @@ -282,7 +281,6 @@ def test__put__not_found(self): 🔽🔽🔽 PUT found a MentorshipSession, with one MentorProfile and MentorshipService """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__without_required_fields(self): model = self.bc.database.create( user=1, @@ -313,7 +311,6 @@ def test__put__found__without_required_fields(self): ) self.assertEqual(self.bc.database.list_of("mentorship.MentorshipBill"), []) - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_required_fields(self): model = self.bc.database.create( user=1, @@ -356,7 +353,6 @@ def test__put__found__with_required_fields(self): 🔽🔽🔽 PUT with all required fields, is_online is False """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_all_required_fields__is_online_as_false(self): mentorship_bill = {"status": random.choice(["RECALCULATE", "DUE"])} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -375,8 +371,6 @@ def test__put__found__with_all_required_fields__is_online_as_false(self): profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -450,18 +444,11 @@ def test__put__found__with_all_required_fields__is_online_as_false(self): self.bc.format.to_dict(model.mentorship_bill), ], ) - self.assertEqual( - signals.mentorship_session_status.send_robust.call_args_list, - [ - call(instance=model.mentorship_session, sender=model.mentorship_session.__class__), - ], - ) """ 🔽🔽🔽 PUT with all required fields, is_online is False, MentorshipBill finished """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_all_required_fields__is_online_as_false__bill_finished(self): mentorship_bill = {"status": random.choice(["APPROVED", "PAID", "IGNORED"])} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -480,8 +467,6 @@ def test__put__found__with_all_required_fields__is_online_as_false__bill_finishe profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -533,13 +518,11 @@ def test__put__found__with_all_required_fields__is_online_as_false__bill_finishe self.bc.format.to_dict(model.mentorship_bill), ], ) - self.assertEqual(str(signals.mentorship_session_status.send_robust.call_args_list), str([])) """ 🔽🔽🔽 PUT with all required fields, is_online is True, trying to edit readonly fields """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_all_required_fields__is_online_as_true__trying_to_edit_readonly_fields(self): statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -554,8 +537,6 @@ def test__put__found__with_all_required_fields__is_online_as_true__trying_to_edi profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -620,13 +601,11 @@ def test__put__found__with_all_required_fields__is_online_as_true__trying_to_edi self.bc.format.to_dict(model.mentorship_bill), ], ) - self.assertEqual(str(signals.mentorship_session_status.send_robust.call_args_list), str([])) """ 🔽🔽🔽 PUT with all required fields, is_online is True """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_all_required_fields__is_online_as_true(self): mentorship_bill = {"status": random.choice(["RECALCULATE", "DUE"])} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -645,8 +624,6 @@ def test__put__found__with_all_required_fields__is_online_as_true(self): profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -712,18 +689,10 @@ def test__put__found__with_all_required_fields__is_online_as_true(self): ], ) - self.assertEqual( - signals.mentorship_session_status.send_robust.call_args_list, - [ - call(instance=model.mentorship_session, sender=model.mentorship_session.__class__), - ], - ) - """ 🔽🔽🔽 PUT with all required fields, is_online is True, MentorshipBill finished """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) def test__put__found__with_all_required_fields__is_online_as_true__bill_finished(self): mentorship_bill = {"status": random.choice(["APPROVED", "PAID", "IGNORED"])} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -739,8 +708,6 @@ def test__put__found__with_all_required_fields__is_online_as_true__bill_finished profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -792,15 +759,11 @@ def test__put__found__with_all_required_fields__is_online_as_true__bill_finished self.bc.format.to_dict(model.mentorship_bill), ], ) - self.assertEqual(str(signals.mentorship_session_status.send_robust.call_args_list), str([])) """ 🔽🔽🔽 PUT passing a MentorshipBill with some MentorshipSession without MentorshipService """ - @patch("breathecode.mentorship.signals.mentorship_session_status.send_robust", MagicMock()) - # @patch('breathecode.mentorship.signals.mentorship_session_status.send_robust', - # MagicMock(side_effect=[None, None, Exception('error')])) def test__put__found__passing_a_bill_with_some_session_without_service(self): mentorship_bill = {"status": "DUE"} statuses = ["PENDING", "STARTED", "COMPLETED", "FAILED", "IGNORED"] @@ -830,8 +793,6 @@ def test__put__found__passing_a_bill_with_some_session_without_service(self): profile_academy=1, ) - signals.mentorship_session_status.send_robust.call_args_list = [] - self.bc.request.set_headers(academy=1) self.client.force_authenticate(model.user) @@ -906,10 +867,3 @@ def test__put__found__passing_a_bill_with_some_session_without_service(self): }, ], ) - - self.assertEqual( - signals.mentorship_session_status.send_robust.call_args_list, - [ - call(instance=model.mentorship_session[0], sender=model.mentorship_session[0].__class__), - ], - ) diff --git a/breathecode/monitoring/signals.py b/breathecode/monitoring/signals.py index cbf244ef7..32917a7a2 100644 --- a/breathecode/monitoring/signals.py +++ b/breathecode/monitoring/signals.py @@ -1,9 +1,8 @@ -""" -For each signal you want other apps to be able to receive, you have to -declare a new variable here like this: -""" +"""For each signal you want other apps to be able to receive, you have to declare a new variable here like this:""" -from django import dispatch +from task_manager.django.dispatch import Emisor -github_webhook = dispatch.Signal() -stripe_webhook = dispatch.Signal() +emisor = Emisor("breathecode.monitoring") + +github_webhook = emisor.signal("github_webhook") +stripe_webhook = emisor.signal("stripe_webhook") diff --git a/breathecode/notify/utils/hook_manager.py b/breathecode/notify/utils/hook_manager.py index a47098a9a..f274edd6d 100644 --- a/breathecode/notify/utils/hook_manager.py +++ b/breathecode/notify/utils/hook_manager.py @@ -211,16 +211,17 @@ def serialize(self, payload: dict | list | tuple) -> dict | list | tuple: return payload - for key in payload: - if isinstance(payload[key], dict): - self.serialize(payload[key]) + if isinstance(payload, dict): + for key in payload: + if isinstance(payload[key], dict): + self.serialize(payload[key]) - elif isinstance(payload[key], (list, tuple)): - for item in payload[key]: - self.serialize(item) + elif isinstance(payload[key], (list, tuple)): + for item in payload[key]: + self.serialize(item) - elif isinstance(payload[key], timedelta): - payload[key] = payload[key].total_seconds() + elif isinstance(payload[key], timedelta): + payload[key] = payload[key].total_seconds() return payload diff --git a/breathecode/registry/signals.py b/breathecode/registry/signals.py index d49fb1116..cbb8d3066 100644 --- a/breathecode/registry/signals.py +++ b/breathecode/registry/signals.py @@ -1,11 +1,10 @@ -""" -For each signal you want other apps to be able to receive, you have to -declare a new variable here like this: -""" +"""For each signal you want other apps to be able to receive, you have to declare a new variable here like this:""" -from django import dispatch +from task_manager.django.dispatch import Emisor -asset_slug_modified = dispatch.Signal() -asset_readme_modified = dispatch.Signal() -asset_title_modified = dispatch.Signal() -asset_status_updated = dispatch.Signal() +emisor = Emisor("breathecode.registry") + +asset_slug_modified = emisor.signal("asset_slug_modified") +asset_readme_modified = emisor.signal("asset_readme_modified") +asset_title_modified = emisor.signal("asset_title_modified") +asset_status_updated = emisor.signal("asset_status_updated")