[Backport] Improving asynch timeline generation
parent
2b9ddc27db
commit
51a673586a
|
@ -32,9 +32,9 @@ class TimelineAppConfig(AppConfig):
|
|||
signals.post_save.connect(handlers.on_new_history_entry,
|
||||
sender=apps.get_model("history", "HistoryEntry"),
|
||||
dispatch_uid="timeline")
|
||||
signals.pre_save.connect(handlers.create_membership_push_to_timeline,
|
||||
signals.post_save.connect(handlers.create_membership_push_to_timeline,
|
||||
sender=apps.get_model("projects", "Membership"))
|
||||
signals.post_delete.connect(handlers.delete_membership_push_to_timeline,
|
||||
signals.pre_delete.connect(handlers.delete_membership_push_to_timeline,
|
||||
sender=apps.get_model("projects", "Membership"))
|
||||
signals.post_save.connect(handlers.create_user_push_to_timeline,
|
||||
sender=get_user_model())
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.apps import apps
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models import Model
|
||||
from django.db.models import Q
|
||||
|
@ -89,10 +90,27 @@ def _push_to_timeline(objects, instance:object, event_type:str, created_datetime
|
|||
|
||||
|
||||
@app.task
|
||||
def push_to_timelines(project, user, obj, event_type, created_datetime, extra_data={}):
|
||||
if project is not None:
|
||||
def push_to_timelines(project_id, user_id, obj_app_label, obj_model_name, obj_id, event_type, created_datetime, extra_data={}):
|
||||
ObjModel = apps.get_model(obj_app_label, obj_model_name)
|
||||
try:
|
||||
obj = ObjModel.objects.get(id=obj_id)
|
||||
except ObjModel.DoesNotExist:
|
||||
return
|
||||
|
||||
try:
|
||||
user = get_user_model().objects.get(id=user_id)
|
||||
except get_user_model().DoesNotExist:
|
||||
return
|
||||
|
||||
if project_id is not None:
|
||||
# Actions related with a project
|
||||
|
||||
projectModel = apps.get_model("projects", "Project")
|
||||
try:
|
||||
project = projectModel.objects.get(id=project_id)
|
||||
except projectModel.DoesNotExist:
|
||||
return
|
||||
|
||||
## Project timeline
|
||||
_push_to_timeline(project, obj, event_type, created_datetime,
|
||||
namespace=build_project_namespace(project),
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
|
@ -29,11 +30,14 @@ from taiga.timeline.service import (push_to_timelines,
|
|||
extract_user_info)
|
||||
|
||||
|
||||
def _push_to_timelines(*args, **kwargs):
|
||||
def _push_to_timelines(project, user, obj, event_type, created_datetime, extra_data={}):
|
||||
project_id = None if project is None else project.id
|
||||
|
||||
ct = ContentType.objects.get_for_model(obj)
|
||||
if settings.CELERY_ENABLED:
|
||||
push_to_timelines.delay(*args, **kwargs)
|
||||
push_to_timelines.delay(project_id, user.id, ct.app_label, ct.model, obj.id, event_type, created_datetime, extra_data=extra_data)
|
||||
else:
|
||||
push_to_timelines(*args, **kwargs)
|
||||
push_to_timelines(project_id, user.id, ct.app_label, ct.model, obj.id, event_type, created_datetime, extra_data=extra_data)
|
||||
|
||||
|
||||
def _clean_description_fields(values_diff):
|
||||
|
@ -86,7 +90,7 @@ def on_new_history_entry(sender, instance, created, **kwargs):
|
|||
_push_to_timelines(project, user, obj, event_type, created_datetime, extra_data=extra_data)
|
||||
|
||||
|
||||
def create_membership_push_to_timeline(sender, instance, **kwargs):
|
||||
def create_membership_push_to_timeline(sender, instance, created, **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
|
||||
|
@ -96,29 +100,10 @@ def create_membership_push_to_timeline(sender, instance, **kwargs):
|
|||
"""
|
||||
|
||||
# We shown in created project timeline entry
|
||||
if not instance.pk and instance.user and instance.user != instance.project.owner:
|
||||
if created 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
|
||||
elif instance.pk:
|
||||
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):
|
||||
if instance.user:
|
||||
|
|
|
@ -351,29 +351,6 @@ def test_update_wiki_page_timeline():
|
|||
assert user_watcher_timeline[0].data["values_diff"]["slug"][1] == "test wiki page timeline updated"
|
||||
|
||||
|
||||
def test_update_membership_timeline():
|
||||
user_1 = factories.UserFactory.create()
|
||||
user_2 = factories.UserFactory.create()
|
||||
membership = factories.MembershipFactory.create(user=user_1)
|
||||
membership.user = user_2
|
||||
membership.save()
|
||||
project_timeline = service.get_project_timeline(membership.project)
|
||||
user_1_timeline = service.get_user_timeline(user_1)
|
||||
user_2_timeline = service.get_user_timeline(user_2)
|
||||
assert project_timeline[0].event_type == "projects.membership.delete"
|
||||
assert project_timeline[0].data["project"]["id"] == membership.project.id
|
||||
assert project_timeline[0].data["user"]["id"] == user_1.id
|
||||
assert project_timeline[1].event_type == "projects.membership.create"
|
||||
assert project_timeline[1].data["project"]["id"] == membership.project.id
|
||||
assert project_timeline[1].data["user"]["id"] == user_2.id
|
||||
assert user_1_timeline[0].event_type == "projects.membership.delete"
|
||||
assert user_1_timeline[0].data["project"]["id"] == membership.project.id
|
||||
assert user_1_timeline[0].data["user"]["id"] == user_1.id
|
||||
assert user_2_timeline[0].event_type == "projects.membership.create"
|
||||
assert user_2_timeline[0].data["project"]["id"] == membership.project.id
|
||||
assert user_2_timeline[0].data["user"]["id"] == user_2.id
|
||||
|
||||
|
||||
def test_delete_project_timeline():
|
||||
project = factories.ProjectFactory.create(name="test project timeline")
|
||||
user_watcher= factories.UserFactory()
|
||||
|
@ -534,9 +511,11 @@ def test_timeline_error_use_member_ids_instead_of_memberships_ids():
|
|||
history_services.take_snapshot(user_story, user=member_user)
|
||||
|
||||
user_timeline = service.get_profile_timeline(member_user)
|
||||
assert len(user_timeline) == 2
|
||||
|
||||
assert len(user_timeline) == 3
|
||||
assert user_timeline[0].event_type == "userstories.userstory.create"
|
||||
assert user_timeline[1].event_type == "users.user.create"
|
||||
assert user_timeline[1].event_type == "projects.membership.create"
|
||||
assert user_timeline[2].event_type == "users.user.create"
|
||||
|
||||
external_user_timeline = service.get_profile_timeline(external_user)
|
||||
assert len(external_user_timeline) == 1
|
||||
|
|
Loading…
Reference in New Issue