From 51fe131c136b999dd811e0695d4bcb921430a0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Thu, 9 Jul 2015 14:04:24 +0200 Subject: [PATCH] Fix timelines generation --- taiga/timeline/signals.py | 86 ++++++++++++++++++------------ tests/integration/test_timeline.py | 31 +++++++++-- 2 files changed, 79 insertions(+), 38 deletions(-) diff --git a/taiga/timeline/signals.py b/taiga/timeline/signals.py index 34a80955..dc8b5a2d 100644 --- a/taiga/timeline/signals.py +++ b/taiga/timeline/signals.py @@ -39,38 +39,44 @@ def _push_to_timeline(*args, **kwargs): def _push_to_timelines(project, user, obj, event_type, created_datetime, extra_data={}): if project is not None: - # Project timeline + # Actions related with a project + + ## Project timeline _push_to_timeline(project, obj, event_type, created_datetime, namespace=build_project_namespace(project), extra_data=extra_data) - # User timeline - _push_to_timeline(user, obj, event_type, created_datetime, - namespace=build_user_namespace(user), - extra_data=extra_data) + ## User profile timelines + ## - Me + related_people = User.objects.filter(id=user.id) - # Calculating related people - related_people = User.objects.none() + ## - Owner + if hasattr(obj, "owner_id") and obj.owner_id: + related_people |= User.objects.filter(id=obj.owner_id) - # Assigned to - if hasattr(obj, "assigned_to") and obj.assigned_to and user != obj.assigned_to: - related_people |= User.objects.filter(id=obj.assigned_to.id) + ## - Assigned to + if hasattr(obj, "assigned_to_id") and obj.assigned_to_id: + related_people |= User.objects.filter(id=obj.assigned_to_id) - # Watchers - watchers = hasattr(obj, "watchers") and obj.watchers.exclude(id=user.id) or User.objects.none() - if watchers: - related_people |= watchers + ## - Watchers + watchers = getattr(obj, "watchers", None) + if watchers: + related_people |= obj.watchers.all() - if project is not None: - # Team - team_members_ids = project.memberships.filter(user__isnull=False).values_list("id", flat=True) - team = User.objects.filter(id__in=team_members_ids) - related_people |= team + ## - Exclude inactive and system users and remove duplicate + related_people = related_people.exclude(is_active=False) + related_people = related_people.exclude(is_system=True) related_people = related_people.distinct() _push_to_timeline(related_people, obj, event_type, created_datetime, namespace=build_user_namespace(user), extra_data=extra_data) + else: + # Actions not related with a project + ## - Me + _push_to_timeline(user, obj, event_type, created_datetime, + namespace=build_user_namespace(user), + extra_data=extra_data) def on_new_history_entry(sender, instance, created, **kwargs): @@ -110,27 +116,37 @@ def on_new_history_entry(sender, instance, created, **kwargs): def create_membership_push_to_timeline(sender, instance, **kwargs): - # Creating new membership with associated user - # If the user is the project owner we don't do anything because that info will - # be shown in created project timeline entry + """ + Creating new membership with associated user. If the user is the project owner we don't + do anything because that info will be shown in created project timeline entry + + @param sender: Membership model + @param instance: Membership object + """ + + # We shown in created project timeline entry if not instance.pk and instance.user and instance.user != instance.project.owner: created_datetime = instance.created_at _push_to_timelines(instance.project, instance.user, instance, "create", created_datetime) - #Updating existing membership + # Updating existing membership elif instance.pk: - prev_instance = sender.objects.get(pk=instance.pk) - if instance.user != prev_instance.user: - created_datetime = timezone.now() - # The new member - _push_to_timelines(instance.project, instance.user, instance, "create", created_datetime) - # If we are updating the old user is removed from project - if prev_instance.user: - _push_to_timelines(instance.project, - prev_instance.user, - prev_instance, - "delete", - created_datetime) + try: + prev_instance = sender.objects.get(pk=instance.pk) + if instance.user != prev_instance.user: + created_datetime = timezone.now() + # The new member + _push_to_timelines(instance.project, instance.user, instance, "create", created_datetime) + # If we are updating the old user is removed from project + if prev_instance.user: + _push_to_timelines(instance.project, + prev_instance.user, + prev_instance, + "delete", + created_datetime) + except sender.DoesNotExist: + # This happens with some tests, when a membership is created with a concrete id + pass def delete_membership_push_to_timeline(sender, instance, **kwargs): diff --git a/tests/integration/test_timeline.py b/tests/integration/test_timeline.py index 3d203494..957c5c91 100644 --- a/tests/integration/test_timeline.py +++ b/tests/integration/test_timeline.py @@ -377,7 +377,7 @@ def test_owner_user_story_timeline(): def test_assigned_to_user_story_timeline(): membership = factories.MembershipFactory.create() - user_story = factories.UserStoryFactory.create(subject="test us timeline", assigned_to=membership.user) + user_story = factories.UserStoryFactory.create(subject="test us timeline", assigned_to=membership.user, project=membership.project) history_services.take_snapshot(user_story, user=user_story.owner) user_timeline = service.get_profile_timeline(user_story.assigned_to) assert user_timeline[0].event_type == "userstories.userstory.create" @@ -386,20 +386,22 @@ def test_assigned_to_user_story_timeline(): def test_watchers_to_user_story_timeline(): membership = factories.MembershipFactory.create() - user_story = factories.UserStoryFactory.create(subject="test us timeline") + user_story = factories.UserStoryFactory.create(subject="test us timeline", project=membership.project) user_story.watchers.add(membership.user) history_services.take_snapshot(user_story, user=user_story.owner) user_timeline = service.get_profile_timeline(membership.user) assert user_timeline[0].event_type == "userstories.userstory.create" assert user_timeline[0].data["userstory"]["subject"] == "test us timeline" -def test_user_data_for_system_users(): + +def test_user_data_for_non_system_users(): user_story = factories.UserStoryFactory.create(subject="test us timeline") history_services.take_snapshot(user_story, user=user_story.owner) project_timeline = service.get_project_timeline(user_story.project) serialized_obj = TimelineSerializer(project_timeline[0]) serialized_obj.data["data"]["user"]["is_profile_visible"] = True + def test_user_data_for_system_users(): user_story = factories.UserStoryFactory.create(subject="test us timeline") user_story.owner.is_system = True @@ -409,6 +411,7 @@ def test_user_data_for_system_users(): serialized_obj = TimelineSerializer(project_timeline[0]) serialized_obj.data["data"]["user"]["is_profile_visible"] = False + def test_user_data_for_unactived_users(): user_story = factories.UserStoryFactory.create(subject="test us timeline") user_story.owner.cancel() @@ -418,3 +421,25 @@ def test_user_data_for_unactived_users(): serialized_obj = TimelineSerializer(project_timeline[0]) serialized_obj.data["data"]["user"]["is_profile_visible"] = False serialized_obj.data["data"]["user"]["username"] = "deleted-user" + +def test_timeline_error_use_member_ids_instead_of_memberships_ids(): + user_story = factories.UserStoryFactory.create(subject="test error use member ids instead of " + "memberships ids") + + member_user = user_story.owner + external_user = factories.UserFactory.create() + + membership = factories.MembershipFactory.create(project=user_story.project, + user=member_user, + id=external_user.id) + + history_services.take_snapshot(user_story, user=member_user) + + user_timeline = service.get_profile_timeline(member_user) + assert len(user_timeline) == 2 + assert user_timeline[0].event_type == "userstories.userstory.create" + assert user_timeline[1].event_type == "users.user.create" + + external_user_timeline = service.get_profile_timeline(external_user) + assert len(external_user_timeline) == 1 + assert external_user_timeline[0].event_type == "users.user.create"