diff --git a/taiga/projects/history/freeze_impl.py b/taiga/projects/history/freeze_impl.py index ae7eec7c..85c47d4f 100644 --- a/taiga/projects/history/freeze_impl.py +++ b/taiga/projects/history/freeze_impl.py @@ -93,7 +93,8 @@ def _common_users_values(diff): if "assigned_to" in diff: users.update(diff["assigned_to"]) if "assigned_users" in diff: - [users.update(usrs_id) if usrs_id else None for usrs_id in diff["assigned_users"]] + [users.update(usrs_ids) for usrs_ids in diff["assigned_users"] if + usrs_ids] if users: values["users"] = _get_users_values(users) @@ -335,6 +336,12 @@ def userstory_freezer(us) -> dict: for rp in rpqsd: points[str(rp.role_id)] = rp.points_id + assigned_users = [u.id for u in us.assigned_users.all()] + # Due to multiple assignment migration, for new snapshots we add to + # assigned users a list with the 'assigned to' value + if us.assigned_to_id and not assigned_users: + assigned_users = [us.assigned_to_id] + snapshot = { "ref": us.ref, "owner": us.owner_id, @@ -348,7 +355,7 @@ def userstory_freezer(us) -> dict: "description": us.description, "description_html": mdrender(us.project, us.description), "assigned_to": us.assigned_to_id, - "assigned_users": [u.id for u in us.assigned_users.all()], + "assigned_users": assigned_users, "milestone": us.milestone_id, "client_requirement": us.client_requirement, "team_requirement": us.team_requirement, diff --git a/taiga/projects/history/services.py b/taiga/projects/history/services.py index ef684f1e..4f3487fc 100644 --- a/taiga/projects/history/services.py +++ b/taiga/projects/history/services.py @@ -229,6 +229,31 @@ def get_excluded_fields(typename: str) -> tuple: return _deprecated_fields.get(typename, ()) +def migrate_userstory_diff(obj: FrozenObj) -> FrozenObj: + # Due to multiple assignment migration, for old snapshots we add a list + # with the 'assigned to' value + if 'assigned_users' not in obj.snapshot.keys(): + snapshot = deepcopy(obj.snapshot) + snapshot['assigned_users'] = [obj.snapshot['assigned_to']] + + obj = FrozenObj(obj.key, snapshot) + + return obj + + +_migrations = {"userstories.userstory": migrate_userstory_diff} + + +def migrate_to_last_version(typename: str, obj: FrozenObj) -> FrozenObj: + """"" + Adapt old snapshots to the last format in order to generate correct diffs. + :param typename: + :param obj: + :return: + """ + return _migrations.get(typename, lambda x: x)(obj) + + def make_diff(oldobj: FrozenObj, newobj: FrozenObj, excluded_keys: tuple = ()) -> FrozenDiff: """ @@ -342,6 +367,10 @@ def take_snapshot(obj: object, *, comment: str="", user=None, new_fobj = freeze_model_instance(obj) old_fobj, need_real_snapshot = get_last_snapshot_for_key(key) + # migrate diff to latest schema + if old_fobj: + old_fobj = migrate_to_last_version(typename, old_fobj) + entry_model = apps.get_model("history", "HistoryEntry") user_id = None if user is None else user.id user_name = "" if user is None else user.get_full_name() @@ -358,6 +387,7 @@ def take_snapshot(obj: object, *, comment: str="", user=None, raise RuntimeError("Unexpected condition") excluded_fields = get_excluded_fields(typename) + fdiff = make_diff(old_fobj, new_fobj, excluded_fields) # If diff and comment are empty, do diff --git a/taiga/projects/userstories/serializers.py b/taiga/projects/userstories/serializers.py index 3177884b..2e34fff4 100644 --- a/taiga/projects/userstories/serializers.py +++ b/taiga/projects/userstories/serializers.py @@ -90,7 +90,16 @@ class UserStoryListSerializer(ProjectExtraInfoSerializerMixin, :return: User queryset object representing the assigned users """ - return [user.id for user in obj.assigned_users.all()] + if not obj.assigned_to: + return set([user.id for user in obj.assigned_users.all()]) + + assigned_users = [user.id for user in obj.assigned_users.all()] + \ + [obj.assigned_to.id] + + if not assigned_users: + return None + + return set(assigned_users) def get_epic_order(self, obj): include_epic_order = getattr(obj, "include_epic_order", False) diff --git a/tests/integration/test_userstories.py b/tests/integration/test_userstories.py index 87c87947..82979b89 100644 --- a/tests/integration/test_userstories.py +++ b/tests/integration/test_userstories.py @@ -104,7 +104,7 @@ def test_create_userstory_with_assigned_users(client): response = client.json.post(url, json_data) assert response.status_code == 201 - assert response.data["assigned_users"] == [user.id, user_watcher.id] + assert response.data["assigned_users"] == set([user.id, user_watcher.id]) def test_create_userstory_with_watchers(client):