diff --git a/taiga/projects/notifications/mixins.py b/taiga/projects/notifications/mixins.py index e6e6fc74..bf42a9ed 100644 --- a/taiga/projects/notifications/mixins.py +++ b/taiga/projects/notifications/mixins.py @@ -191,7 +191,11 @@ class WatchedResourceModelSerializer(serializers.ModelSerializer): watcher_field = self.fields.pop("watchers", None) instance = super(WatchedResourceModelSerializer, self).restore_object(attrs, instance) if instance is not None and self.validate_watchers(attrs, "watchers"): - new_watcher_ids = set(attrs.get("watchers", [])) + #A partial update can exclude the watchers field + if not "watchers" in attrs: + return instance + + new_watcher_ids = set(attrs.get("watchers", None)) old_watcher_ids = set(instance.get_watchers().values_list("id", flat=True)) adding_watcher_ids = list(new_watcher_ids.difference(old_watcher_ids)) removing_watcher_ids = list(old_watcher_ids.difference(new_watcher_ids)) @@ -209,7 +213,6 @@ class WatchedResourceModelSerializer(serializers.ModelSerializer): return instance - def to_native(self, obj): #watchers is wasn't attached via the get_queryset of the viewset we need to manually add it if obj is not None and not hasattr(obj, "watchers"): @@ -217,6 +220,12 @@ class WatchedResourceModelSerializer(serializers.ModelSerializer): return super(WatchedResourceModelSerializer, self).to_native(obj) + def save(self, **kwargs): + obj = super(WatchedResourceModelSerializer, self).save(**kwargs) + self.fields["watchers"] = WatchersField(required=False) + obj.watchers = [user.id for user in obj.get_watchers()] + return obj + class WatchersViewSetMixin: # Is a ModelListViewSet with two required params: permission_classes and resource_model diff --git a/tests/integration/test_userstories.py b/tests/integration/test_userstories.py index 33b18a8d..f90fd97a 100644 --- a/tests/integration/test_userstories.py +++ b/tests/integration/test_userstories.py @@ -443,3 +443,21 @@ def test_custom_fields_csv_generation(): assert row[26] == attr.name row = next(reader) assert row[26] == "val1" + + +def test_update_userstory_respecting_watchers(client): + watching_user = f.create_user() + project = f.ProjectFactory.create() + us = f.UserStoryFactory.create(project=project, status__project=project, milestone__project=project) + us.add_watcher(watching_user) + f.MembershipFactory.create(project=us.project, user=us.owner, is_owner=True) + f.MembershipFactory.create(project=us.project, user=watching_user) + + client.login(user=us.owner) + url = reverse("userstories-detail", kwargs={"pk": us.pk}) + data = {"subject": "Updating test", "version": 1} + + response = client.json.patch(url, json.dumps(data)) + assert response.status_code == 200 + assert response.data["subject"] == "Updating test" + assert response.data["watchers"] == [watching_user.id]