Пример #1
0
        def resolve_diff_value(key):
            value = None
            diff = get_diff_of_htmls(self.diff[key][0] or "", self.diff[key][1] or "")

            if diff:
                key = "{}_diff".format(key)
                value = (None, diff)

            return (key, value)
Пример #2
0
def make_diff(oldobj:FrozenObj, newobj:FrozenObj) -> FrozenDiff:
    """
    Compute a diff between two frozen objects.
    """

    assert isinstance(newobj, FrozenObj), "newobj parameter should be instance of FrozenObj"

    if oldobj is None:
        return FrozenDiff(newobj.key, {}, newobj.snapshot)

    first = oldobj.snapshot
    second = newobj.snapshot

    diff = {}
    not_found_value = None

    # Check all keys in first dict
    for key in first:
        if key not in second:
            diff[key] = (first[key], not_found_value)
        elif first[key] != second[key]:
            diff[key] = (first[key], second[key])

    # Check all keys in second dict to find missing
    for key in second:
        if key not in first:
            diff[key] = (not_found_value, second[key])

    if "description" in diff:
        description_diff = get_diff_of_htmls(
            diff["description"][0],
            diff["description"][1]
        )
        diff["description_diff"] = (not_found_value, description_diff)

    return FrozenDiff(newobj.key, diff, newobj.snapshot)
Пример #3
0
def test_get_diff_of_htmls_modifications():
    result = get_diff_of_htmls("<p>test1</p>", "<p>1test</p>")
    assert result == "<span>&lt;p&gt;</span><ins style=\"background:#e6ffe6;\">1</ins><span>test</span><del style=\"background:#ffe6e6;\">1</del><span>&lt;/p&gt;</span>"
Пример #4
0
def test_get_diff_of_htmls_deletions():
    result = get_diff_of_htmls("<p>test</p>", "")
    assert result == "<del style=\"background:#ffe6e6;\">&lt;p&gt;test&lt;/p&gt;</del>"
Пример #5
0
def test_get_diff_of_htmls_insertions():
    result = get_diff_of_htmls("", "<p>test</p>")
    assert result == "<ins style=\"background:#e6ffe6;\">&lt;p&gt;test&lt;/p&gt;</ins>"
Пример #6
0
    def values_diff(self):
        result = {}
        users_keys = ["assigned_to", "owner"]

        def resolve_value(field, key):
            data = self.values[field]
            key = str(key)

            if key not in data:
                return None
            return data[key]

        for key in self.diff:
            value = None

            # Note: Hack to prevent description_diff propagation
            #       on old HistoryEntry objects.
            if key == "description_diff":
                continue
            elif key == "description":
                description_diff = get_diff_of_htmls(
                    self.diff[key][0],
                    self.diff[key][1]
                )

                if description_diff:
                    key = "description_diff"
                    value = (None, description_diff)
            elif key == "content":
                content_diff = get_diff_of_htmls(
                    self.diff[key][0],
                    self.diff[key][1]
                )

                if content_diff:
                    key = "content_diff"
                    value = (None, content_diff)
            elif key in users_keys:
                value = [resolve_value("users", x) for x in self.diff[key]]
            elif key == "watchers":
                value = [[resolve_value("users", x) for x in self.diff[key][0]],
                         [resolve_value("users", x) for x in self.diff[key][1]]]
            elif key == "points":
                points = {}

                pointsold = self.diff["points"][0]
                pointsnew = self.diff["points"][1]
                # pointsold = pointsnew

                if pointsold is None:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        points[role_name] = [None, resolve_value("points", point_id)]

                else:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        oldpoint_id = pointsold.get(role_id, None)
                        points[role_name] = [resolve_value("points", oldpoint_id),
                                           resolve_value("points", point_id)]

                # Process that removes points entries with
                # duplicate value.
                for role in dict(points):
                    values = points[role]
                    if values[1] == values[0]:
                        del points[role]

                if points:
                    value = points

            elif key == "attachments":
                attachments = {
                    "new": [],
                    "changed": [],
                    "deleted": [],
                }

                oldattachs = {x["id"]:x for x in self.diff["attachments"][0]}
                newattachs = {x["id"]:x for x in self.diff["attachments"][1]}

                for aid in set(tuple(oldattachs.keys()) + tuple(newattachs.keys())):
                    if aid in oldattachs and aid in newattachs:
                        changes = make_diff_from_dicts(oldattachs[aid], newattachs[aid],
                                                       excluded_keys=("filename", "url"))

                        if changes:
                            change = {
                                "filename": newattachs.get(aid, {}).get("filename", ""),
                                "url": newattachs.get(aid, {}).get("url", ""),
                                "changes": changes
                            }
                            attachments["changed"].append(change)
                    elif aid in oldattachs and aid not in newattachs:
                        attachments["deleted"].append(oldattachs[aid])
                    elif aid not in oldattachs and aid in newattachs:
                        attachments["new"].append(newattachs[aid])

                if attachments["new"] or attachments["changed"] or attachments["deleted"]:
                    value = attachments

            elif key in self.values:
                value = [resolve_value(key, x) for x in self.diff[key]]
            else:
                value = self.diff[key]

            if not value:
                continue

            result[key] = value

        return result
Пример #7
0
    def values_diff(self):
        if self.values_diff_cache is not None:
            return self.values_diff_cache

        result = {}
        users_keys = ["assigned_to", "owner"]

        def resolve_diff_value(key):
            value = None
            diff = get_diff_of_htmls(
                self.diff[key][0] or "",
                self.diff[key][1] or ""
            )

            if diff:
                key = "{}_diff".format(key)
                value = (None, diff)

            return (key, value)

        def resolve_value(field, key):
            data = self.values[field]
            key = str(key)

            if key not in data:
                return None
            return data[key]

        for key in self.diff:
            value = None
            if key in IGNORE_DIFF_FIELDS:
                continue
            elif key in["description", "content", "blocked_note"]:
                (key, value) = resolve_diff_value(key)
            elif key in users_keys:
                value = [resolve_value("users", x) for x in self.diff[key]]
            elif key == "assigned_users":
                diff_in, diff_out = self.diff[key]
                value_in = None
                value_out = None

                if diff_in:
                    users_list = [resolve_value("users", x) for x in diff_in if x]
                    value_in = ", ".join(filter(None, users_list))
                if diff_out:
                    users_list = [resolve_value("users", x) for x in diff_out if x]
                    value_out = ", ".join(filter(None, users_list))
                value = [value_in, value_out]
            elif key == "points":
                points = {}

                pointsold = self.diff["points"][0]
                pointsnew = self.diff["points"][1]
                # pointsold = pointsnew

                if pointsold is None:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        points[role_name] = [None, resolve_value("points", point_id)]

                else:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        oldpoint_id = pointsold.get(role_id, None)
                        points[role_name] = [resolve_value("points", oldpoint_id),
                                             resolve_value("points", point_id)]

                # Process that removes points entries with
                # duplicate value.
                for role in dict(points):
                    values = points[role]
                    if values[1] == values[0]:
                        del points[role]

                if points:
                    value = points

            elif key == "attachments":
                attachments = {
                    "new": [],
                    "changed": [],
                    "deleted": [],
                }

                oldattachs = {x["id"]: x for x in self.diff["attachments"][0]}
                newattachs = {x["id"]: x for x in self.diff["attachments"][1]}

                for aid in set(tuple(oldattachs.keys()) + tuple(newattachs.keys())):
                    if aid in oldattachs and aid in newattachs:
                        changes = make_diff_from_dicts(oldattachs[aid], newattachs[aid],
                                                       excluded_keys=("filename", "url", "thumb_url"))

                        if changes:
                            change = {
                                "filename": newattachs.get(aid, {}).get("filename", ""),
                                "url": newattachs.get(aid, {}).get("url", ""),
                                "thumb_url": newattachs.get(aid, {}).get("thumb_url", ""),
                                "changes": changes
                            }
                            attachments["changed"].append(change)
                    elif aid in oldattachs and aid not in newattachs:
                        attachments["deleted"].append(oldattachs[aid])
                    elif aid not in oldattachs and aid in newattachs:
                        attachments["new"].append(newattachs[aid])

                if attachments["new"] or attachments["changed"] or attachments["deleted"]:
                    value = attachments

            elif key == "custom_attributes":
                custom_attributes = {
                    "new": [],
                    "changed": [],
                    "deleted": [],
                }

                oldcustattrs = {x["id"]: x for x in self.diff["custom_attributes"][0] or []}
                newcustattrs = {x["id"]: x for x in self.diff["custom_attributes"][1] or []}

                for aid in set(tuple(oldcustattrs.keys()) + tuple(newcustattrs.keys())):
                    if aid in oldcustattrs and aid in newcustattrs:
                        changes = make_diff_from_dicts(oldcustattrs[aid], newcustattrs[aid],
                                                       excluded_keys=("name", "type"))
                        newcustattr = newcustattrs.get(aid, {})
                        if changes:
                            change_type = newcustattr.get("type", TEXT_TYPE)

                            if change_type in [NUMBER_TYPE, CHECKBOX_TYPE]:
                                old_value = oldcustattrs[aid].get("value")
                                new_value = newcustattrs[aid].get("value")
                                value_diff = [old_value, new_value]
                            else:
                                old_value = oldcustattrs[aid].get("value", "")
                                new_value = newcustattrs[aid].get("value", "")
                                value_diff = get_diff_of_htmls(old_value,
                                                               new_value)
                            change = {
                                "name": newcustattr.get("name", ""),
                                "changes": changes,
                                "type": change_type,
                                "value_diff": value_diff
                            }
                            custom_attributes["changed"].append(change)
                    elif aid in oldcustattrs and aid not in newcustattrs:
                        custom_attributes["deleted"].append(oldcustattrs[aid])
                    elif aid not in oldcustattrs and aid in newcustattrs:
                        newcustattr = newcustattrs.get(aid, {})
                        change_type = newcustattr.get("type", TEXT_TYPE)
                        if change_type in [NUMBER_TYPE, CHECKBOX_TYPE]:
                            old_value = None
                            new_value = newcustattrs[aid].get("value")
                            value_diff = [old_value, new_value]
                        else:
                            new_value = newcustattrs[aid].get("value", "")
                            value_diff = get_diff_of_htmls("", new_value)
                        newcustattrs[aid]["value_diff"] = value_diff
                        custom_attributes["new"].append(newcustattrs[aid])

                if custom_attributes["new"] or custom_attributes["changed"] or custom_attributes["deleted"]:
                    value = custom_attributes

            elif key == "user_stories":
                user_stories = {
                    "new": [],
                    "deleted": [],
                }

                olduss = {x["id"]: x for x in self.diff["user_stories"][0]}
                newuss = {x["id"]: x for x in self.diff["user_stories"][1]}

                for usid in set(tuple(olduss.keys()) + tuple(newuss.keys())):
                    if usid in olduss and usid not in newuss:
                        user_stories["deleted"].append(olduss[usid])
                    elif usid not in olduss and usid in newuss:
                        user_stories["new"].append(newuss[usid])

                if user_stories["new"] or user_stories["deleted"]:
                    value = user_stories

            elif key in self.values:
                value = [resolve_value(key, x) for x in self.diff[key]]
            else:
                value = self.diff[key]

            if not value:
                continue

            result[key] = value

        self.values_diff_cache = result
        # Update values_diff_cache without dispatching signals
        HistoryEntry.objects.filter(pk=self.pk).update(values_diff_cache=self.values_diff_cache)
        return self.values_diff_cache
Пример #8
0
def test_get_diff_of_htmls_insertions():
    result = get_diff_of_htmls("", "<p>test</p>")
    assert result == "<ins style=\"background:#e6ffe6;\">&lt;p&gt;test&lt;/p&gt;</ins>"
Пример #9
0
    def values_diff(self):
        result = {}
        users_keys = ["assigned_to", "owner"]

        def resolve_value(field, key):
            data = self.values[field]
            key = str(key)

            if key not in data:
                return None
            return data[key]

        for key in self.diff:
            value = None

            # Note: Hack to prevent description_diff propagation
            #       on old HistoryEntry objects.
            if key == "description_diff":
                continue
            elif key == "description":
                description_diff = get_diff_of_htmls(self.diff[key][0],
                                                     self.diff[key][1])

                if description_diff:
                    key = "description_diff"
                    value = (None, description_diff)
            elif key == "content":
                content_diff = get_diff_of_htmls(self.diff[key][0],
                                                 self.diff[key][1])

                if content_diff:
                    key = "content_diff"
                    value = (None, content_diff)
            elif key in users_keys:
                value = [resolve_value("users", x) for x in self.diff[key]]
            elif key == "watchers":
                value = [[
                    resolve_value("users", x) for x in self.diff[key][0]
                ], [resolve_value("users", x) for x in self.diff[key][1]]]
            elif key == "points":
                points = {}

                pointsold = self.diff["points"][0]
                pointsnew = self.diff["points"][1]
                # pointsold = pointsnew

                if pointsold is None:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        points[role_name] = [
                            None, resolve_value("points", point_id)
                        ]

                else:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        oldpoint_id = pointsold.get(role_id, None)
                        points[role_name] = [
                            resolve_value("points", oldpoint_id),
                            resolve_value("points", point_id)
                        ]

                # Process that removes points entries with
                # duplicate value.
                for role in dict(points):
                    values = points[role]
                    if values[1] == values[0]:
                        del points[role]

                if points:
                    value = points

            elif key == "attachments":
                attachments = {
                    "new": [],
                    "changed": [],
                    "deleted": [],
                }

                oldattachs = {x["id"]: x for x in self.diff["attachments"][0]}
                newattachs = {x["id"]: x for x in self.diff["attachments"][1]}

                for aid in set(
                        tuple(oldattachs.keys()) + tuple(newattachs.keys())):
                    if aid in oldattachs and aid in newattachs:
                        changes = make_diff_from_dicts(
                            oldattachs[aid],
                            newattachs[aid],
                            excluded_keys=("filename", "url"))

                        if changes:
                            change = {
                                "filename":
                                newattachs.get(aid, {}).get("filename", ""),
                                "url":
                                newattachs.get(aid, {}).get("url", ""),
                                "changes":
                                changes
                            }
                            attachments["changed"].append(change)
                    elif aid in oldattachs and aid not in newattachs:
                        attachments["deleted"].append(oldattachs[aid])
                    elif aid not in oldattachs and aid in newattachs:
                        attachments["new"].append(newattachs[aid])

                if attachments["new"] or attachments["changed"] or attachments[
                        "deleted"]:
                    value = attachments

            elif key in self.values:
                value = [resolve_value(key, x) for x in self.diff[key]]
            else:
                value = self.diff[key]

            if not value:
                continue

            result[key] = value

        return result
Пример #10
0
def test_get_diff_of_htmls_modifications():
    result = get_diff_of_htmls("<p>test1</p>", "<p>1test</p>")
    assert result == "<span>&lt;p&gt;</span><ins style=\"background:#e6ffe6;\">1</ins><span>test</span><del style=\"background:#ffe6e6;\">1</del><span>&lt;/p&gt;</span>"
Пример #11
0
def test_get_diff_of_htmls_deletions():
    result = get_diff_of_htmls("<p>test</p>", "")
    assert result == "<del style=\"background:#ffe6e6;\">&lt;p&gt;test&lt;/p&gt;</del>"
Пример #12
0
    def values_diff(self):
        if self.values_diff_cache is not None:
            return self.values_diff_cache

        result = {}
        users_keys = ["assigned_to", "owner"]

        def resolve_diff_value(key):
            value = None
            diff = get_diff_of_htmls(self.diff[key][0] or "", self.diff[key][1]
                                     or "")

            if diff:
                key = "{}_diff".format(key)
                value = (None, diff)

            return (key, value)

        def resolve_value(field, key):
            data = self.values[field]
            key = str(key)

            if key not in data:
                return None
            return data[key]

        for key in self.diff:
            value = None
            if key in IGNORE_DIFF_FIELDS:
                continue
            elif key in ["description", "content", "blocked_note"]:
                (key, value) = resolve_diff_value(key)
            elif key in users_keys:
                value = [resolve_value("users", x) for x in self.diff[key]]
            elif key == "assigned_users":
                diff_in, diff_out = self.diff[key]
                value_in = None
                value_out = None

                if diff_in:
                    users_list = [
                        resolve_value("users", x) for x in diff_in if x
                    ]
                    value_in = ", ".join(filter(None, users_list))
                if diff_out:
                    users_list = [
                        resolve_value("users", x) for x in diff_out if x
                    ]
                    value_out = ", ".join(filter(None, users_list))
                value = [value_in, value_out]
            elif key == "points":
                points = {}

                pointsold = self.diff["points"][0]
                pointsnew = self.diff["points"][1]
                # pointsold = pointsnew

                if pointsold is None:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        points[role_name] = [
                            None, resolve_value("points", point_id)
                        ]

                else:
                    for role_id, point_id in pointsnew.items():
                        role_name = resolve_value("roles", role_id)
                        oldpoint_id = pointsold.get(role_id, None)
                        points[role_name] = [
                            resolve_value("points", oldpoint_id),
                            resolve_value("points", point_id)
                        ]

                # Process that removes points entries with
                # duplicate value.
                for role in dict(points):
                    values = points[role]
                    if values[1] == values[0]:
                        del points[role]

                if points:
                    value = points

            elif key == "attachments":
                attachments = {
                    "new": [],
                    "changed": [],
                    "deleted": [],
                }

                oldattachs = {x["id"]: x for x in self.diff["attachments"][0]}
                newattachs = {x["id"]: x for x in self.diff["attachments"][1]}

                for aid in set(
                        tuple(oldattachs.keys()) + tuple(newattachs.keys())):
                    if aid in oldattachs and aid in newattachs:
                        changes = make_diff_from_dicts(
                            oldattachs[aid],
                            newattachs[aid],
                            excluded_keys=("filename", "url", "thumb_url"))

                        if changes:
                            change = {
                                "filename":
                                newattachs.get(aid, {}).get("filename", ""),
                                "url":
                                newattachs.get(aid, {}).get("url", ""),
                                "thumb_url":
                                newattachs.get(aid, {}).get("thumb_url", ""),
                                "changes":
                                changes
                            }
                            attachments["changed"].append(change)
                    elif aid in oldattachs and aid not in newattachs:
                        attachments["deleted"].append(oldattachs[aid])
                    elif aid not in oldattachs and aid in newattachs:
                        attachments["new"].append(newattachs[aid])

                if attachments["new"] or attachments["changed"] or attachments[
                        "deleted"]:
                    value = attachments

            elif key == "custom_attributes":
                custom_attributes = {
                    "new": [],
                    "changed": [],
                    "deleted": [],
                }

                oldcustattrs = {
                    x["id"]: x
                    for x in self.diff["custom_attributes"][0] or []
                }
                newcustattrs = {
                    x["id"]: x
                    for x in self.diff["custom_attributes"][1] or []
                }

                for aid in set(
                        tuple(oldcustattrs.keys()) +
                        tuple(newcustattrs.keys())):
                    if aid in oldcustattrs and aid in newcustattrs:
                        changes = make_diff_from_dicts(oldcustattrs[aid],
                                                       newcustattrs[aid],
                                                       excluded_keys=("name",
                                                                      "type"))
                        newcustattr = newcustattrs.get(aid, {})
                        if changes:
                            change_type = newcustattr.get("type", TEXT_TYPE)

                            if change_type in [NUMBER_TYPE, CHECKBOX_TYPE]:
                                old_value = oldcustattrs[aid].get("value")
                                new_value = newcustattrs[aid].get("value")
                                value_diff = [old_value, new_value]
                            else:
                                old_value = oldcustattrs[aid].get("value", "")
                                new_value = newcustattrs[aid].get("value", "")
                                value_diff = get_diff_of_htmls(
                                    old_value, new_value)
                            change = {
                                "name": newcustattr.get("name", ""),
                                "changes": changes,
                                "type": change_type,
                                "value_diff": value_diff
                            }
                            custom_attributes["changed"].append(change)
                    elif aid in oldcustattrs and aid not in newcustattrs:
                        custom_attributes["deleted"].append(oldcustattrs[aid])
                    elif aid not in oldcustattrs and aid in newcustattrs:
                        newcustattr = newcustattrs.get(aid, {})
                        change_type = newcustattr.get("type", TEXT_TYPE)
                        if change_type in [NUMBER_TYPE, CHECKBOX_TYPE]:
                            old_value = None
                            new_value = newcustattrs[aid].get("value")
                            value_diff = [old_value, new_value]
                        else:
                            new_value = newcustattrs[aid].get("value", "")
                            value_diff = get_diff_of_htmls("", new_value)
                        newcustattrs[aid]["value_diff"] = value_diff
                        custom_attributes["new"].append(newcustattrs[aid])

                if custom_attributes["new"] or custom_attributes[
                        "changed"] or custom_attributes["deleted"]:
                    value = custom_attributes

            elif key == "user_stories":
                user_stories = {
                    "new": [],
                    "deleted": [],
                }

                olduss = {x["id"]: x for x in self.diff["user_stories"][0]}
                newuss = {x["id"]: x for x in self.diff["user_stories"][1]}

                for usid in set(tuple(olduss.keys()) + tuple(newuss.keys())):
                    if usid in olduss and usid not in newuss:
                        user_stories["deleted"].append(olduss[usid])
                    elif usid not in olduss and usid in newuss:
                        user_stories["new"].append(newuss[usid])

                if user_stories["new"] or user_stories["deleted"]:
                    value = user_stories

            elif key in self.values:
                value = [resolve_value(key, x) for x in self.diff[key]]
            else:
                value = self.diff[key]

            if not value:
                continue

            result[key] = value

        self.values_diff_cache = result
        # Update values_diff_cache without dispatching signals
        HistoryEntry.objects.filter(pk=self.pk).update(
            values_diff_cache=self.values_diff_cache)
        return self.values_diff_cache